From ccf90cdbb0bae8bca9281f57c67906e5b9d8949a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 6 Sep 2006 13:29:30 -0700 Subject: [PATCH] added dm patches to queue --- queue-2.6.17/dm-add-dmf_freeing.patch | 106 +++++++++ queue-2.6.17/dm-add-module-ref-counting.patch | 60 +++++ .../dm-change-minor_lock-to-spinlock.patch | 132 +++++++++++ .../dm-fix-block-device-initialisation.patch | 53 +++++ .../dm-fix-idr-minor-allocation.patch | 101 ++++++++ .../dm-fix-mapped-device-ref-counting.patch | 167 ++++++++++++++ .../dm-mirror-sector-offset-fix.patch | 121 ++++++++++ queue-2.6.17/dm-move-idr_pre_get.patch | 76 ++++++ .../dm-snapshot-unify-chunk_size.patch | 217 ++++++++++++++++++ queue-2.6.17/series | 9 + 10 files changed, 1042 insertions(+) create mode 100644 queue-2.6.17/dm-add-dmf_freeing.patch create mode 100644 queue-2.6.17/dm-add-module-ref-counting.patch create mode 100644 queue-2.6.17/dm-change-minor_lock-to-spinlock.patch create mode 100644 queue-2.6.17/dm-fix-block-device-initialisation.patch create mode 100644 queue-2.6.17/dm-fix-idr-minor-allocation.patch create mode 100644 queue-2.6.17/dm-fix-mapped-device-ref-counting.patch create mode 100644 queue-2.6.17/dm-mirror-sector-offset-fix.patch create mode 100644 queue-2.6.17/dm-move-idr_pre_get.patch create mode 100644 queue-2.6.17/dm-snapshot-unify-chunk_size.patch diff --git a/queue-2.6.17/dm-add-dmf_freeing.patch b/queue-2.6.17/dm-add-dmf_freeing.patch new file mode 100644 index 00000000000..5dd60c30394 --- /dev/null +++ b/queue-2.6.17/dm-add-dmf_freeing.patch @@ -0,0 +1,106 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:11 2006 +Message-Id: <200606260727.k5Q7RNoI030206@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:23 -0700 +Cc: jeffm@suse.com, stable@kernel.org, agk@redhat.com +Subject: [patch 166/215] dm: add DMF_FREEING + + +From: Jeff Mahoney + +There is a chicken and egg problem between the block layer and dm in which the +gendisk associated with a mapping keeps a reference-less pointer to the +mapped_device. + +This patch uses a new flag DMF_FREEING to indicate when the mapped_device is +no longer valid. This is checked to prevent any attempt to open the device +from succeeding while the device is being destroyed. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Jeff Mahoney +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm.c ++++ linux-2.6.17.11/drivers/md/dm.c +@@ -63,6 +63,7 @@ union map_info *dm_get_mapinfo(struct bi + #define DMF_BLOCK_IO 0 + #define DMF_SUSPENDED 1 + #define DMF_FROZEN 2 ++#define DMF_FREEING 3 + + struct mapped_device { + struct rw_semaphore io_lock; +@@ -221,9 +222,23 @@ static int dm_blk_open(struct inode *ino + { + struct mapped_device *md; + ++ spin_lock(&_minor_lock); ++ + md = inode->i_bdev->bd_disk->private_data; ++ if (!md) ++ goto out; ++ ++ if (test_bit(DMF_FREEING, &md->flags)) { ++ md = NULL; ++ goto out; ++ } ++ + dm_get(md); +- return 0; ++ ++out: ++ spin_unlock(&_minor_lock); ++ ++ return md ? 0 : -ENXIO; + } + + static int dm_blk_close(struct inode *inode, struct file *file) +@@ -919,6 +934,11 @@ static void free_dev(struct mapped_devic + mempool_destroy(md->io_pool); + del_gendisk(md->disk); + free_minor(minor); ++ ++ spin_lock(&_minor_lock); ++ md->disk->private_data = NULL; ++ spin_unlock(&_minor_lock); ++ + put_disk(md->disk); + blk_cleanup_queue(md->queue); + kfree(md); +@@ -1023,9 +1043,14 @@ static struct mapped_device *dm_find_md( + spin_lock(&_minor_lock); + + md = idr_find(&_minor_idr, minor); +- if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor))) ++ if (md && (md == MINOR_ALLOCED || ++ (dm_disk(md)->first_minor != minor) || ++ test_bit(DMF_FREEING, &md->flags))) { + md = NULL; ++ goto out; ++ } + ++out: + spin_unlock(&_minor_lock); + + return md; +@@ -1060,9 +1085,12 @@ void dm_put(struct mapped_device *md) + { + struct dm_table *map; + ++ BUG_ON(test_bit(DMF_FREEING, &md->flags)); ++ + if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { + map = dm_get_table(md); + idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); ++ set_bit(DMF_FREEING, &md->flags); + spin_unlock(&_minor_lock); + if (!dm_suspended(md)) { + dm_table_presuspend_targets(map); diff --git a/queue-2.6.17/dm-add-module-ref-counting.patch b/queue-2.6.17/dm-add-module-ref-counting.patch new file mode 100644 index 00000000000..e02594bdfe0 --- /dev/null +++ b/queue-2.6.17/dm-add-module-ref-counting.patch @@ -0,0 +1,60 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:09 2006 +Message-Id: <200606260727.k5Q7RPFp030214@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:25 -0700 +Cc: jeffm@suse.com, stable@kernel.org, agk@redhat.com +Subject: [patch 168/215] dm: add module ref counting + + +From: Jeff Mahoney + +The reference counting on dm-mod is zero if no mapped devices are open. This +is incorrect, and can lead to an oops if the module is unloaded while mapped +devices exist. + +This patch claims a reference to the module whenever a device is created, and +drops it again when the device is freed. + +Devices must be removed before dm-mod is unloaded. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Jeff Mahoney +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- linux-2.6.17.11.orig/drivers/md/dm.c ++++ linux-2.6.17.11/drivers/md/dm.c +@@ -852,6 +852,9 @@ static struct mapped_device *alloc_dev(u + return NULL; + } + ++ if (!try_module_get(THIS_MODULE)) ++ goto bad0; ++ + /* get a minor number for the dev */ + r = persistent ? specific_minor(md, minor) : next_free_minor(md, &minor); + if (r < 0) +@@ -918,6 +921,8 @@ static struct mapped_device *alloc_dev(u + blk_cleanup_queue(md->queue); + free_minor(minor); + bad1: ++ module_put(THIS_MODULE); ++ bad0: + kfree(md); + return NULL; + } +@@ -941,6 +946,7 @@ static void free_dev(struct mapped_devic + + put_disk(md->disk); + blk_cleanup_queue(md->queue); ++ module_put(THIS_MODULE); + kfree(md); + } + diff --git a/queue-2.6.17/dm-change-minor_lock-to-spinlock.patch b/queue-2.6.17/dm-change-minor_lock-to-spinlock.patch new file mode 100644 index 00000000000..2e4135592e9 --- /dev/null +++ b/queue-2.6.17/dm-change-minor_lock-to-spinlock.patch @@ -0,0 +1,132 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:03 2006 +Message-Id: <200606260727.k5Q7RM9r030202@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:22 -0700 +Cc: jeffm@suse.com, stable@kernel.org, agk@redhat.com +Subject: [patch 165/215] dm: change minor_lock to spinlock + + +From: Jeff Mahoney + +While removing a device, another another thread might attempt to resurrect it. + +This patch replaces the _minor_lock mutex with a spinlock and uses +atomic_dec_and_lock() to serialize reference counting in dm_put(). + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Jeff Mahoney +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm.c | 27 +++++++++++++-------------- + 1 file changed, 13 insertions(+), 14 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm.c ++++ linux-2.6.17.11/drivers/md/dm.c +@@ -26,6 +26,7 @@ static const char *_name = DM_NAME; + static unsigned int major = 0; + static unsigned int _major = 0; + ++static DEFINE_SPINLOCK(_minor_lock); + /* + * One of these is allocated per bio. + */ +@@ -746,14 +747,13 @@ static int dm_any_congested(void *conges + /*----------------------------------------------------------------- + * An IDR is used to keep track of allocated minor numbers. + *---------------------------------------------------------------*/ +-static DEFINE_MUTEX(_minor_lock); + static DEFINE_IDR(_minor_idr); + + static void free_minor(unsigned int minor) + { +- mutex_lock(&_minor_lock); ++ spin_lock(&_minor_lock); + idr_remove(&_minor_idr, minor); +- mutex_unlock(&_minor_lock); ++ spin_unlock(&_minor_lock); + } + + /* +@@ -770,7 +770,7 @@ static int specific_minor(struct mapped_ + if (!r) + return -ENOMEM; + +- mutex_lock(&_minor_lock); ++ spin_lock(&_minor_lock); + + if (idr_find(&_minor_idr, minor)) { + r = -EBUSY; +@@ -788,7 +788,7 @@ static int specific_minor(struct mapped_ + } + + out: +- mutex_unlock(&_minor_lock); ++ spin_unlock(&_minor_lock); + return r; + } + +@@ -801,7 +801,7 @@ static int next_free_minor(struct mapped + if (!r) + return -ENOMEM; + +- mutex_lock(&_minor_lock); ++ spin_lock(&_minor_lock); + + r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); + if (r) { +@@ -817,7 +817,7 @@ static int next_free_minor(struct mapped + *minor = m; + + out: +- mutex_unlock(&_minor_lock); ++ spin_unlock(&_minor_lock); + return r; + } + +@@ -887,9 +887,9 @@ static struct mapped_device *alloc_dev(u + init_waitqueue_head(&md->eventq); + + /* Populate the mapping, nobody knows we exist yet */ +- mutex_lock(&_minor_lock); ++ spin_lock(&_minor_lock); + old_md = idr_replace(&_minor_idr, md, minor); +- mutex_unlock(&_minor_lock); ++ spin_unlock(&_minor_lock); + + BUG_ON(old_md != MINOR_ALLOCED); + +@@ -1020,13 +1020,13 @@ static struct mapped_device *dm_find_md( + if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) + return NULL; + +- mutex_lock(&_minor_lock); ++ spin_lock(&_minor_lock); + + md = idr_find(&_minor_idr, minor); + if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor))) + md = NULL; + +- mutex_unlock(&_minor_lock); ++ spin_unlock(&_minor_lock); + + return md; + } +@@ -1060,11 +1060,10 @@ void dm_put(struct mapped_device *md) + { + struct dm_table *map; + +- if (atomic_dec_and_test(&md->holders)) { ++ if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { + map = dm_get_table(md); +- mutex_lock(&_minor_lock); + idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); +- mutex_unlock(&_minor_lock); ++ spin_unlock(&_minor_lock); + if (!dm_suspended(md)) { + dm_table_presuspend_targets(map); + dm_table_postsuspend_targets(map); diff --git a/queue-2.6.17/dm-fix-block-device-initialisation.patch b/queue-2.6.17/dm-fix-block-device-initialisation.patch new file mode 100644 index 00000000000..00c6604acc0 --- /dev/null +++ b/queue-2.6.17/dm-fix-block-device-initialisation.patch @@ -0,0 +1,53 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:26 2006 +Message-Id: <200606260727.k5Q7RPQY030218@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:25 -0700 +Cc: jeffm@suse.com, stable@kernel.org, agk@redhat.com +Subject: [patch 169/215] dm: fix block device initialisation + + +From: Jeff Mahoney + +In alloc_dev(), we register the device with the block layer and then continue +to initialize the device. But register_disk() makes the device available to +be opened before we have completed initialising it. + +This patch moves the final bits of the initialization above the disk +registration. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Jeff Mahoney +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm.c ++++ linux-2.6.17.11/drivers/md/dm.c +@@ -891,6 +891,10 @@ static struct mapped_device *alloc_dev(u + if (!md->disk) + goto bad4; + ++ atomic_set(&md->pending, 0); ++ init_waitqueue_head(&md->wait); ++ init_waitqueue_head(&md->eventq); ++ + md->disk->major = _major; + md->disk->first_minor = minor; + md->disk->fops = &dm_blk_dops; +@@ -900,10 +904,6 @@ static struct mapped_device *alloc_dev(u + add_disk(md->disk); + format_dev_t(md->name, MKDEV(_major, minor)); + +- atomic_set(&md->pending, 0); +- init_waitqueue_head(&md->wait); +- init_waitqueue_head(&md->eventq); +- + /* Populate the mapping, nobody knows we exist yet */ + spin_lock(&_minor_lock); + old_md = idr_replace(&_minor_idr, md, minor); diff --git a/queue-2.6.17/dm-fix-idr-minor-allocation.patch b/queue-2.6.17/dm-fix-idr-minor-allocation.patch new file mode 100644 index 00000000000..7b0d5210e3f --- /dev/null +++ b/queue-2.6.17/dm-fix-idr-minor-allocation.patch @@ -0,0 +1,101 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:03 2006 +Message-Id: <200606260727.k5Q7RLre030194@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:21 -0700 +Cc: jeffm@suse.com, stable@kernel.org, agk@redhat.com +Subject: [patch 163/215] dm: fix idr minor allocation + + +From: Jeff Mahoney + +One part of the system can attempt to use a mapped device before another has +finished initialising it or while it is being freed. + +This patch introduces a place holder value, MINOR_ALLOCED, to mark the minor +as allocated but in a state where it can't be used, such as mid-allocation or +mid-free. At the end of the initialization, it replaces the place holder with +the pointer to the mapped_device, making it available to the rest of the dm +subsystem. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Jeff Mahoney +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm.c ++++ linux-2.6.17.11/drivers/md/dm.c +@@ -54,6 +54,8 @@ union map_info *dm_get_mapinfo(struct bi + return NULL; + } + ++#define MINOR_ALLOCED ((void *)-1) ++ + /* + * Bits for the md->flags field. + */ +@@ -777,7 +779,7 @@ static int specific_minor(struct mapped_ + goto out; + } + +- r = idr_get_new_above(&_minor_idr, md, minor, &m); ++ r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m); + if (r) { + goto out; + } +@@ -806,7 +808,7 @@ static int next_free_minor(struct mapped + goto out; + } + +- r = idr_get_new(&_minor_idr, md, &m); ++ r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); + if (r) { + goto out; + } +@@ -833,6 +835,7 @@ static struct mapped_device *alloc_dev(u + { + int r; + struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); ++ void *old_md; + + if (!md) { + DMWARN("unable to allocate device, out of memory."); +@@ -888,6 +891,13 @@ static struct mapped_device *alloc_dev(u + init_waitqueue_head(&md->wait); + init_waitqueue_head(&md->eventq); + ++ /* Populate the mapping, nobody knows we exist yet */ ++ mutex_lock(&_minor_lock); ++ old_md = idr_replace(&_minor_idr, md, minor); ++ mutex_unlock(&_minor_lock); ++ ++ BUG_ON(old_md != MINOR_ALLOCED); ++ + return md; + + bad4: +@@ -1018,7 +1028,7 @@ static struct mapped_device *dm_find_md( + mutex_lock(&_minor_lock); + + md = idr_find(&_minor_idr, minor); +- if (!md || (dm_disk(md)->first_minor != minor)) ++ if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor))) + md = NULL; + + mutex_unlock(&_minor_lock); +@@ -1057,6 +1067,9 @@ void dm_put(struct mapped_device *md) + + if (atomic_dec_and_test(&md->holders)) { + map = dm_get_table(md); ++ mutex_lock(&_minor_lock); ++ idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); ++ mutex_unlock(&_minor_lock); + if (!dm_suspended(md)) { + dm_table_presuspend_targets(map); + dm_table_postsuspend_targets(map); diff --git a/queue-2.6.17/dm-fix-mapped-device-ref-counting.patch b/queue-2.6.17/dm-fix-mapped-device-ref-counting.patch new file mode 100644 index 00000000000..e0208d4fbb7 --- /dev/null +++ b/queue-2.6.17/dm-fix-mapped-device-ref-counting.patch @@ -0,0 +1,167 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:34 2006 +Message-Id: <200606260727.k5Q7ROfQ030210@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:24 -0700 +Cc: jeffm@suse.com, stable@kernel.org, agk@redhat.com +Subject: [patch 167/215] dm: fix mapped device ref counting + + +From: Jeff Mahoney + +To avoid races, _minor_lock must be held while changing mapped device +reference counts. + +There are a few paths where a mapped_device pointer is returned before a +reference is taken. This patch fixes them. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Jeff Mahoney +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm-ioctl.c | 34 ++++++++++++++++++++++++---------- + 1 file changed, 24 insertions(+), 10 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm-ioctl.c ++++ linux-2.6.17.11/drivers/md/dm-ioctl.c +@@ -102,8 +102,10 @@ static struct hash_cell *__get_name_cell + unsigned int h = hash_str(str); + + list_for_each_entry (hc, _name_buckets + h, name_list) +- if (!strcmp(hc->name, str)) ++ if (!strcmp(hc->name, str)) { ++ dm_get(hc->md); + return hc; ++ } + + return NULL; + } +@@ -114,8 +116,10 @@ static struct hash_cell *__get_uuid_cell + unsigned int h = hash_str(str); + + list_for_each_entry (hc, _uuid_buckets + h, uuid_list) +- if (!strcmp(hc->uuid, str)) ++ if (!strcmp(hc->uuid, str)) { ++ dm_get(hc->md); + return hc; ++ } + + return NULL; + } +@@ -191,7 +195,7 @@ static int unregister_with_devfs(struct + */ + static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md) + { +- struct hash_cell *cell; ++ struct hash_cell *cell, *hc; + + /* + * Allocate the new cells. +@@ -204,14 +208,19 @@ static int dm_hash_insert(const char *na + * Insert the cell into both hash tables. + */ + down_write(&_hash_lock); +- if (__get_name_cell(name)) ++ hc = __get_name_cell(name); ++ if (hc) { ++ dm_put(hc->md); + goto bad; ++ } + + list_add(&cell->name_list, _name_buckets + hash_str(name)); + + if (uuid) { +- if (__get_uuid_cell(uuid)) { ++ hc = __get_uuid_cell(uuid); ++ if (hc) { + list_del(&cell->name_list); ++ dm_put(hc->md); + goto bad; + } + list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); +@@ -289,6 +298,7 @@ static int dm_hash_rename(const char *ol + if (hc) { + DMWARN("asked to rename to an already existing name %s -> %s", + old, new); ++ dm_put(hc->md); + up_write(&_hash_lock); + kfree(new_name); + return -EBUSY; +@@ -328,6 +338,7 @@ static int dm_hash_rename(const char *ol + dm_table_put(table); + } + ++ dm_put(hc->md); + up_write(&_hash_lock); + kfree(old_name); + return 0; +@@ -611,10 +622,8 @@ static struct hash_cell *__find_device_h + return __get_name_cell(param->name); + + md = dm_get_md(huge_decode_dev(param->dev)); +- if (md) { ++ if (md) + mdptr = dm_get_mdptr(md); +- dm_put(md); +- } + + return mdptr; + } +@@ -628,7 +637,6 @@ static struct mapped_device *find_device + hc = __find_device_hash_cell(param); + if (hc) { + md = hc->md; +- dm_get(md); + + /* + * Sneakily write in both the name and the uuid +@@ -653,6 +661,7 @@ static struct mapped_device *find_device + static int dev_remove(struct dm_ioctl *param, size_t param_size) + { + struct hash_cell *hc; ++ struct mapped_device *md; + + down_write(&_hash_lock); + hc = __find_device_hash_cell(param); +@@ -663,8 +672,11 @@ static int dev_remove(struct dm_ioctl *p + return -ENXIO; + } + ++ md = hc->md; ++ + __hash_remove(hc); + up_write(&_hash_lock); ++ dm_put(md); + param->data_size = 0; + return 0; + } +@@ -790,7 +802,6 @@ static int do_resume(struct dm_ioctl *pa + } + + md = hc->md; +- dm_get(md); + + new_map = hc->new_map; + hc->new_map = NULL; +@@ -1078,6 +1089,7 @@ static int table_clear(struct dm_ioctl * + { + int r; + struct hash_cell *hc; ++ struct mapped_device *md; + + down_write(&_hash_lock); + +@@ -1096,7 +1108,9 @@ static int table_clear(struct dm_ioctl * + param->flags &= ~DM_INACTIVE_PRESENT_FLAG; + + r = __dev_status(hc->md, param); ++ md = hc->md; + up_write(&_hash_lock); ++ dm_put(md); + return r; + } + diff --git a/queue-2.6.17/dm-mirror-sector-offset-fix.patch b/queue-2.6.17/dm-mirror-sector-offset-fix.patch new file mode 100644 index 00000000000..7ca0a657963 --- /dev/null +++ b/queue-2.6.17/dm-mirror-sector-offset-fix.patch @@ -0,0 +1,121 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:18 2006 +Message-Id: <200606260727.k5Q7RQhI030222@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:26 -0700 +Cc: neilb@suse.de, stable@kernel.org, agk@redhat.com +Subject: [patch 170/215] dm: mirror sector offset fix + + +From: Neil Brown + +The device-mapper core does not perform any remapping of bios before passing +them to the targets. If a particular mapping begins part-way into a device, +targets obtain the sector relative to the start of the mapping by subtracting +ti->begin. + +The dm-raid1 target didn't do this everywhere: this patch fixes it, taking +care to subtract ti->begin exactly once for each bio. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Neil Brown +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm-raid1.c | 63 +++++++++++++++++++++++++------------------------- + 1 file changed, 32 insertions(+), 31 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm-raid1.c ++++ linux-2.6.17.11/drivers/md/dm-raid1.c +@@ -106,12 +106,42 @@ struct region { + struct bio_list delayed_bios; + }; + ++ ++/*----------------------------------------------------------------- ++ * Mirror set structures. ++ *---------------------------------------------------------------*/ ++struct mirror { ++ atomic_t error_count; ++ struct dm_dev *dev; ++ sector_t offset; ++}; ++ ++struct mirror_set { ++ struct dm_target *ti; ++ struct list_head list; ++ struct region_hash rh; ++ struct kcopyd_client *kcopyd_client; ++ ++ spinlock_t lock; /* protects the next two lists */ ++ struct bio_list reads; ++ struct bio_list writes; ++ ++ /* recovery */ ++ region_t nr_regions; ++ int in_sync; ++ ++ struct mirror *default_mirror; /* Default mirror */ ++ ++ unsigned int nr_mirrors; ++ struct mirror mirror[0]; ++}; ++ + /* + * Conversion fns + */ + static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio) + { +- return bio->bi_sector >> rh->region_shift; ++ return (bio->bi_sector - rh->ms->ti->begin) >> rh->region_shift; + } + + static inline sector_t region_to_sector(struct region_hash *rh, region_t region) +@@ -541,35 +571,6 @@ static void rh_start_recovery(struct reg + wake(); + } + +-/*----------------------------------------------------------------- +- * Mirror set structures. +- *---------------------------------------------------------------*/ +-struct mirror { +- atomic_t error_count; +- struct dm_dev *dev; +- sector_t offset; +-}; +- +-struct mirror_set { +- struct dm_target *ti; +- struct list_head list; +- struct region_hash rh; +- struct kcopyd_client *kcopyd_client; +- +- spinlock_t lock; /* protects the next two lists */ +- struct bio_list reads; +- struct bio_list writes; +- +- /* recovery */ +- region_t nr_regions; +- int in_sync; +- +- struct mirror *default_mirror; /* Default mirror */ +- +- unsigned int nr_mirrors; +- struct mirror mirror[0]; +-}; +- + /* + * Every mirror should look like this one. + */ +@@ -1115,7 +1116,7 @@ static int mirror_map(struct dm_target * + struct mirror *m; + struct mirror_set *ms = ti->private; + +- map_context->ll = bio->bi_sector >> ms->rh.region_shift; ++ map_context->ll = bio_to_region(&ms->rh, bio); + + if (rw == WRITE) { + queue_bio(ms, bio, rw); diff --git a/queue-2.6.17/dm-move-idr_pre_get.patch b/queue-2.6.17/dm-move-idr_pre_get.patch new file mode 100644 index 00000000000..c4119d07bd0 --- /dev/null +++ b/queue-2.6.17/dm-move-idr_pre_get.patch @@ -0,0 +1,76 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:24 2006 +Message-Id: <200606260727.k5Q7RLCG030198@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:21 -0700 +Cc: jeffm@suse.com, stable@kernel.org, agk@redhat.com +Subject: [patch 164/215] dm: move idr_pre_get + + +From: Jeff Mahoney + +idr_pre_get() can sleep while allocating memory. + +The next patch will change _minor_lock into a spinlock, so this patch moves +idr_pre_get() outside the lock in preparation. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Jeff Mahoney +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm.c | 23 +++++++++-------------- + 1 file changed, 9 insertions(+), 14 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm.c ++++ linux-2.6.17.11/drivers/md/dm.c +@@ -766,6 +766,10 @@ static int specific_minor(struct mapped_ + if (minor >= (1 << MINORBITS)) + return -EINVAL; + ++ r = idr_pre_get(&_minor_idr, GFP_KERNEL); ++ if (!r) ++ return -ENOMEM; ++ + mutex_lock(&_minor_lock); + + if (idr_find(&_minor_idr, minor)) { +@@ -773,16 +777,9 @@ static int specific_minor(struct mapped_ + goto out; + } + +- r = idr_pre_get(&_minor_idr, GFP_KERNEL); +- if (!r) { +- r = -ENOMEM; +- goto out; +- } +- + r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m); +- if (r) { ++ if (r) + goto out; +- } + + if (m != minor) { + idr_remove(&_minor_idr, m); +@@ -800,13 +797,11 @@ static int next_free_minor(struct mapped + int r; + unsigned int m; + +- mutex_lock(&_minor_lock); +- + r = idr_pre_get(&_minor_idr, GFP_KERNEL); +- if (!r) { +- r = -ENOMEM; +- goto out; +- } ++ if (!r) ++ return -ENOMEM; ++ ++ mutex_lock(&_minor_lock); + + r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); + if (r) { diff --git a/queue-2.6.17/dm-snapshot-unify-chunk_size.patch b/queue-2.6.17/dm-snapshot-unify-chunk_size.patch new file mode 100644 index 00000000000..233ace8a7ff --- /dev/null +++ b/queue-2.6.17/dm-snapshot-unify-chunk_size.patch @@ -0,0 +1,217 @@ +From stable-bounces@linux.kernel.org Mon Jun 26 00:28:39 2006 +Message-Id: <200606260727.k5Q7RIaI030186@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Mon, 26 Jun 2006 00:27:18 -0700 +Cc: stable@kernel.org, agk@redhat.com +Subject: [patch 161/215] dm snapshot: unify chunk_size + + +From: Alasdair G Kergon + +Persistent snapshots currently store a private copy of the chunk size. +Userspace also supplies the chunk size when loading a snapshot. Ensure +consistency by only storing the chunk_size in one place instead of two. + + +Currently the two sizes will differ if the chunk size supplied by userspace +does not match the chunk size an existing snapshot actually uses. Amongst +other problems, this causes an incorrect 'percentage full' to be reported. + +The patch ensures consistency by only storing the chunk_size in one place, +removing it from struct pstore. Some initialisation is delayed until the +correct chunk_size is known. If read_header() discovers that the wrong chunk +size was supplied, the 'area' buffer (which the header already got read into) +is reinitialised to the correct size. + +[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled] + +Signed-off-by: Alasdair G Kergon +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + + drivers/md/dm-exception-store.c | 65 +++++++++++++++++++++++++--------------- + drivers/md/dm-snap.c | 6 +-- + 2 files changed, 45 insertions(+), 26 deletions(-) + +--- linux-2.6.17.11.orig/drivers/md/dm-exception-store.c ++++ linux-2.6.17.11/drivers/md/dm-exception-store.c +@@ -91,7 +91,6 @@ struct pstore { + struct dm_snapshot *snap; /* up pointer to my snapshot */ + int version; + int valid; +- uint32_t chunk_size; + uint32_t exceptions_per_area; + + /* +@@ -133,7 +132,7 @@ static int alloc_area(struct pstore *ps) + int r = -ENOMEM; + size_t len; + +- len = ps->chunk_size << SECTOR_SHIFT; ++ len = ps->snap->chunk_size << SECTOR_SHIFT; + + /* + * Allocate the chunk_size block of memory that will hold +@@ -160,8 +159,8 @@ static int chunk_io(struct pstore *ps, u + unsigned long bits; + + where.bdev = ps->snap->cow->bdev; +- where.sector = ps->chunk_size * chunk; +- where.count = ps->chunk_size; ++ where.sector = ps->snap->chunk_size * chunk; ++ where.count = ps->snap->chunk_size; + + return dm_io_sync_vm(1, &where, rw, ps->area, &bits); + } +@@ -188,7 +187,7 @@ static int area_io(struct pstore *ps, ui + + static int zero_area(struct pstore *ps, uint32_t area) + { +- memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); ++ memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); + return area_io(ps, area, WRITE); + } + +@@ -196,6 +195,7 @@ static int read_header(struct pstore *ps + { + int r; + struct disk_header *dh; ++ chunk_t chunk_size; + + r = chunk_io(ps, 0, READ); + if (r) +@@ -210,8 +210,29 @@ static int read_header(struct pstore *ps + *new_snapshot = 0; + ps->valid = le32_to_cpu(dh->valid); + ps->version = le32_to_cpu(dh->version); +- ps->chunk_size = le32_to_cpu(dh->chunk_size); +- ++ chunk_size = le32_to_cpu(dh->chunk_size); ++ if (ps->snap->chunk_size != chunk_size) { ++ DMWARN("chunk size %llu in device metadata overrides " ++ "table chunk size of %llu.", ++ (unsigned long long)chunk_size, ++ (unsigned long long)ps->snap->chunk_size); ++ ++ /* We had a bogus chunk_size. Fix stuff up. */ ++ dm_io_put(sectors_to_pages(ps->snap->chunk_size)); ++ free_area(ps); ++ ++ ps->snap->chunk_size = chunk_size; ++ ps->snap->chunk_mask = chunk_size - 1; ++ ps->snap->chunk_shift = ffs(chunk_size) - 1; ++ ++ r = alloc_area(ps); ++ if (r) ++ return r; ++ ++ r = dm_io_get(sectors_to_pages(chunk_size)); ++ if (r) ++ return r; ++ } + } else { + DMWARN("Invalid/corrupt snapshot"); + r = -ENXIO; +@@ -224,13 +245,13 @@ static int write_header(struct pstore *p + { + struct disk_header *dh; + +- memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT); ++ memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); + + dh = (struct disk_header *) ps->area; + dh->magic = cpu_to_le32(SNAP_MAGIC); + dh->valid = cpu_to_le32(ps->valid); + dh->version = cpu_to_le32(ps->version); +- dh->chunk_size = cpu_to_le32(ps->chunk_size); ++ dh->chunk_size = cpu_to_le32(ps->snap->chunk_size); + + return chunk_io(ps, 0, WRITE); + } +@@ -365,7 +386,7 @@ static void persistent_destroy(struct ex + { + struct pstore *ps = get_info(store); + +- dm_io_put(sectors_to_pages(ps->chunk_size)); ++ dm_io_put(sectors_to_pages(ps->snap->chunk_size)); + vfree(ps->callbacks); + free_area(ps); + kfree(ps); +@@ -384,6 +405,16 @@ static int persistent_read_metadata(stru + return r; + + /* ++ * Now we know correct chunk_size, complete the initialisation. ++ */ ++ ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) / ++ sizeof(struct disk_exception); ++ ps->callbacks = dm_vcalloc(ps->exceptions_per_area, ++ sizeof(*ps->callbacks)); ++ if (!ps->callbacks) ++ return -ENOMEM; ++ ++ /* + * Do we need to setup a new snapshot ? + */ + if (new_snapshot) { +@@ -533,9 +564,6 @@ int dm_create_persistent(struct exceptio + ps->snap = store->snap; + ps->valid = 1; + ps->version = SNAPSHOT_DISK_VERSION; +- ps->chunk_size = chunk_size; +- ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) / +- sizeof(struct disk_exception); + ps->next_free = 2; /* skipping the header and first area */ + ps->current_committed = 0; + +@@ -543,18 +571,9 @@ int dm_create_persistent(struct exceptio + if (r) + goto bad; + +- /* +- * Allocate space for all the callbacks. +- */ + ps->callback_count = 0; + atomic_set(&ps->pending_count, 0); +- ps->callbacks = dm_vcalloc(ps->exceptions_per_area, +- sizeof(*ps->callbacks)); +- +- if (!ps->callbacks) { +- r = -ENOMEM; +- goto bad; +- } ++ ps->callbacks = NULL; + + store->destroy = persistent_destroy; + store->read_metadata = persistent_read_metadata; +--- linux-2.6.17.11.orig/drivers/md/dm-snap.c ++++ linux-2.6.17.11/drivers/md/dm-snap.c +@@ -530,7 +530,7 @@ static int snapshot_ctr(struct dm_target + } + + ti->private = s; +- ti->split_io = chunk_size; ++ ti->split_io = s->chunk_size; + + return 0; + +@@ -1204,7 +1204,7 @@ static int origin_status(struct dm_targe + + static struct target_type origin_target = { + .name = "snapshot-origin", +- .version = {1, 1, 0}, ++ .version = {1, 4, 0}, + .module = THIS_MODULE, + .ctr = origin_ctr, + .dtr = origin_dtr, +@@ -1215,7 +1215,7 @@ static struct target_type origin_target + + static struct target_type snapshot_target = { + .name = "snapshot", +- .version = {1, 1, 0}, ++ .version = {1, 4, 0}, + .module = THIS_MODULE, + .ctr = snapshot_ctr, + .dtr = snapshot_dtr, diff --git a/queue-2.6.17/series b/queue-2.6.17/series index 896111036cc..4716a58b955 100644 --- a/queue-2.6.17/series +++ b/queue-2.6.17/series @@ -5,3 +5,12 @@ fix-compilation-error-on-ia64.patch bridge-netfilter-don-t-overwrite-memory-outside-of-skb.patch allow-per-route-window-scale-limiting.patch have-ext2-reject-file-handles-with-bad-inode-numbers-early.patch +dm-snapshot-unify-chunk_size.patch +dm-fix-idr-minor-allocation.patch +dm-move-idr_pre_get.patch +dm-change-minor_lock-to-spinlock.patch +dm-add-dmf_freeing.patch +dm-fix-mapped-device-ref-counting.patch +dm-add-module-ref-counting.patch +dm-fix-block-device-initialisation.patch +dm-mirror-sector-offset-fix.patch -- 2.47.2