]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
added dm patches to queue
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 6 Sep 2006 20:29:30 +0000 (13:29 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 6 Sep 2006 20:29:30 +0000 (13:29 -0700)
queue-2.6.17/dm-add-dmf_freeing.patch [new file with mode: 0644]
queue-2.6.17/dm-add-module-ref-counting.patch [new file with mode: 0644]
queue-2.6.17/dm-change-minor_lock-to-spinlock.patch [new file with mode: 0644]
queue-2.6.17/dm-fix-block-device-initialisation.patch [new file with mode: 0644]
queue-2.6.17/dm-fix-idr-minor-allocation.patch [new file with mode: 0644]
queue-2.6.17/dm-fix-mapped-device-ref-counting.patch [new file with mode: 0644]
queue-2.6.17/dm-mirror-sector-offset-fix.patch [new file with mode: 0644]
queue-2.6.17/dm-move-idr_pre_get.patch [new file with mode: 0644]
queue-2.6.17/dm-snapshot-unify-chunk_size.patch [new file with mode: 0644]
queue-2.6.17/series

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 (file)
index 0000000..5dd60c3
--- /dev/null
@@ -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 <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);
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 (file)
index 0000000..e02594b
--- /dev/null
@@ -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 <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);
+ }
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 (file)
index 0000000..2e41355
--- /dev/null
@@ -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 <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);
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 (file)
index 0000000..00c6604
--- /dev/null
@@ -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 <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);
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 (file)
index 0000000..7b0d521
--- /dev/null
@@ -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 <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);
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 (file)
index 0000000..e0208d4
--- /dev/null
@@ -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 <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;
+ }
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 (file)
index 0000000..7ca0a65
--- /dev/null
@@ -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 <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);
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 (file)
index 0000000..c4119d0
--- /dev/null
@@ -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 <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) {
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 (file)
index 0000000..233ace8
--- /dev/null
@@ -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 <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,
index 896111036cc21f77a3ec5f4fd33ed103ab898a37..4716a58b95572d039039a6a76b08aecc55b84709 100644 (file)
@@ -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