--- /dev/null
+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 <jeffm@suse.com>
+
+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 <jeffm@suse.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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);
--- /dev/null
+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 <jeffm@suse.com>
+
+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 <jeffm@suse.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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);
+ }
+
--- /dev/null
+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 <jeffm@suse.com>
+
+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 <jeffm@suse.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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);
--- /dev/null
+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 <jeffm@suse.com>
+
+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 <jeffm@suse.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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);
--- /dev/null
+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 <jeffm@suse.com>
+
+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 <jeffm@suse.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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);
--- /dev/null
+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 <jeffm@suse.com>
+
+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 <jeffm@suse.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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;
+ }
+
--- /dev/null
+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 <neilb@suse.de>
+
+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 <neilb@suse.de>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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);
--- /dev/null
+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 <jeffm@suse.com>
+
+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 <jeffm@suse.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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) {
--- /dev/null
+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 <agk@redhat.com>
+
+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 <agk@redhat.com>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+
+ 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,
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