From 042d2a9bcd80fe12d4b0871706aa9dd2231e8238 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Thu, 10 Dec 2009 23:52:24 +0000 Subject: [PATCH] dm: keep old table until after resume succeeded When swapping a new table into place, retain the old table until its replacement is in place. An old check for an empty table is removed because this is enforced in populate_table(). __unbind() becomes redundant when followed by __bind(). Signed-off-by: Alasdair G Kergon --- drivers/md/dm-ioctl.c | 10 ++++++---- drivers/md/dm.c | 34 +++++++++++++++++----------------- include/linux/device-mapper.h | 4 +++- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index a3d20265ffc1..63fd4de25bda 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -855,7 +855,7 @@ static int do_resume(struct dm_ioctl *param) unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG; struct hash_cell *hc; struct mapped_device *md; - struct dm_table *new_map; + struct dm_table *new_map, *old_map = NULL; down_write(&_hash_lock); @@ -884,11 +884,11 @@ static int do_resume(struct dm_ioctl *param) if (!dm_suspended(md)) dm_suspend(md, suspend_flags); - r = dm_swap_table(md, new_map); - if (r) { + old_map = dm_swap_table(md, new_map); + if (IS_ERR(old_map)) { dm_table_destroy(new_map); dm_put(md); - return r; + return PTR_ERR(old_map); } if (dm_table_get_mode(new_map) & FMODE_WRITE) @@ -900,6 +900,8 @@ static int do_resume(struct dm_ioctl *param) if (dm_suspended(md)) r = dm_resume(md); + if (old_map) + dm_table_destroy(old_map); if (!r) { dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 255b75c61544..c254c6cf69a1 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2033,9 +2033,13 @@ static void __set_size(struct mapped_device *md, sector_t size) mutex_unlock(&md->bdev->bd_inode->i_mutex); } -static int __bind(struct mapped_device *md, struct dm_table *t, - struct queue_limits *limits) +/* + * Returns old map, which caller must destroy. + */ +static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t, + struct queue_limits *limits) { + struct dm_table *old_map; struct request_queue *q = md->queue; sector_t size; unsigned long flags; @@ -2050,11 +2054,6 @@ static int __bind(struct mapped_device *md, struct dm_table *t, __set_size(md, size); - if (!size) { - dm_table_destroy(t); - return 0; - } - dm_table_event_callback(t, event_callback, md); /* @@ -2070,11 +2069,12 @@ static int __bind(struct mapped_device *md, struct dm_table *t, __bind_mempools(md, t); write_lock_irqsave(&md->map_lock, flags); + old_map = md->map; md->map = t; dm_table_set_restrictions(t, q, limits); write_unlock_irqrestore(&md->map_lock, flags); - return 0; + return old_map; } /* @@ -2368,13 +2368,13 @@ static void dm_rq_barrier_work(struct work_struct *work) } /* - * Swap in a new table (destroying old one). + * Swap in a new table, returning the old one for the caller to destroy. */ -int dm_swap_table(struct mapped_device *md, struct dm_table *table) +struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) { - struct dm_table *map; + struct dm_table *map = ERR_PTR(-EINVAL); struct queue_limits limits; - int r = -EINVAL; + int r; mutex_lock(&md->suspend_lock); @@ -2383,8 +2383,10 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) goto out; r = dm_calculate_queue_limits(table, &limits); - if (r) + if (r) { + map = ERR_PTR(r); goto out; + } /* cannot change the device type, once a table is bound */ if (md->map && @@ -2393,13 +2395,11 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) goto out; } - map = __unbind(md); - r = __bind(md, table, &limits); - dm_table_destroy(map); + map = __bind(md, table, &limits); out: mutex_unlock(&md->suspend_lock); - return r; + return map; } /* diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index fc16a351ef7a..b9c6c8ca11be 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -295,8 +295,10 @@ void dm_table_event(struct dm_table *t); /* * The device must be suspended before calling this method. + * Returns the previous table, which the caller must destroy. */ -int dm_swap_table(struct mapped_device *md, struct dm_table *t); +struct dm_table *dm_swap_table(struct mapped_device *md, + struct dm_table *t); /* * A wrapper around vmalloc.