]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Oct 2012 17:22:47 +0000 (10:22 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Oct 2012 17:22:47 +0000 (10:22 -0700)
added patches:
dm-handle-requests-beyond-end-of-device-instead-of-using-bug_on.patch
vfs-dcache-fix-deadlock-in-tree-traversal.patch

queue-3.0/dm-handle-requests-beyond-end-of-device-instead-of-using-bug_on.patch [new file with mode: 0644]
queue-3.0/series [new file with mode: 0644]
queue-3.0/vfs-dcache-fix-deadlock-in-tree-traversal.patch [new file with mode: 0644]

diff --git a/queue-3.0/dm-handle-requests-beyond-end-of-device-instead-of-using-bug_on.patch b/queue-3.0/dm-handle-requests-beyond-end-of-device-instead-of-using-bug_on.patch
new file mode 100644 (file)
index 0000000..29c44e8
--- /dev/null
@@ -0,0 +1,131 @@
+From ba1cbad93dd47223b1f3b8edd50dd9ef2abcb2ed Mon Sep 17 00:00:00 2001
+From: Mike Snitzer <snitzer@redhat.com>
+Date: Wed, 26 Sep 2012 23:45:42 +0100
+Subject: dm: handle requests beyond end of device instead of using BUG_ON
+
+From: Mike Snitzer <snitzer@redhat.com>
+
+commit ba1cbad93dd47223b1f3b8edd50dd9ef2abcb2ed upstream.
+
+The access beyond the end of device BUG_ON that was introduced to
+dm_request_fn via commit 29e4013de7ad950280e4b2208 ("dm: implement
+REQ_FLUSH/FUA support for request-based dm") was an overly
+drastic (but simple) response to this situation.
+
+I have received a report that this BUG_ON was hit and now think
+it would be better to use dm_kill_unmapped_request() to fail the clone
+and original request with -EIO.
+
+map_request() will assign the valid target returned by
+dm_table_find_target to tio->ti.  But when the target
+isn't valid tio->ti is never assigned (because map_request isn't
+called); so add a check for tio->ti != NULL to dm_done().
+
+Reported-by: Mike Christie <michaelc@cs.wisc.edu>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm.c |   56 ++++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 38 insertions(+), 18 deletions(-)
+
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -856,10 +856,14 @@ static void dm_done(struct request *clon
+ {
+       int r = error;
+       struct dm_rq_target_io *tio = clone->end_io_data;
+-      dm_request_endio_fn rq_end_io = tio->ti->type->rq_end_io;
++      dm_request_endio_fn rq_end_io = NULL;
+-      if (mapped && rq_end_io)
+-              r = rq_end_io(tio->ti, clone, error, &tio->info);
++      if (tio->ti) {
++              rq_end_io = tio->ti->type->rq_end_io;
++
++              if (mapped && rq_end_io)
++                      r = rq_end_io(tio->ti, clone, error, &tio->info);
++      }
+       if (r <= 0)
+               /* The target wants to complete the I/O */
+@@ -1562,15 +1566,6 @@ static int map_request(struct dm_target
+       int r, requeued = 0;
+       struct dm_rq_target_io *tio = clone->end_io_data;
+-      /*
+-       * Hold the md reference here for the in-flight I/O.
+-       * We can't rely on the reference count by device opener,
+-       * because the device may be closed during the request completion
+-       * when all bios are completed.
+-       * See the comment in rq_completed() too.
+-       */
+-      dm_get(md);
+-
+       tio->ti = ti;
+       r = ti->type->map_rq(ti, clone, &tio->info);
+       switch (r) {
+@@ -1602,6 +1597,26 @@ static int map_request(struct dm_target
+       return requeued;
+ }
++static struct request *dm_start_request(struct mapped_device *md, struct request *orig)
++{
++      struct request *clone;
++
++      blk_start_request(orig);
++      clone = orig->special;
++      atomic_inc(&md->pending[rq_data_dir(clone)]);
++
++      /*
++       * Hold the md reference here for the in-flight I/O.
++       * We can't rely on the reference count by device opener,
++       * because the device may be closed during the request completion
++       * when all bios are completed.
++       * See the comment in rq_completed() too.
++       */
++      dm_get(md);
++
++      return clone;
++}
++
+ /*
+  * q->request_fn for request-based dm.
+  * Called with the queue lock held.
+@@ -1631,14 +1646,21 @@ static void dm_request_fn(struct request
+                       pos = blk_rq_pos(rq);
+               ti = dm_table_find_target(map, pos);
+-              BUG_ON(!dm_target_is_valid(ti));
++              if (!dm_target_is_valid(ti)) {
++                      /*
++                       * Must perform setup, that dm_done() requires,
++                       * before calling dm_kill_unmapped_request
++                       */
++                      DMERR_LIMIT("request attempted access beyond the end of device");
++                      clone = dm_start_request(md, rq);
++                      dm_kill_unmapped_request(clone, -EIO);
++                      continue;
++              }
+               if (ti->type->busy && ti->type->busy(ti))
+                       goto delay_and_out;
+-              blk_start_request(rq);
+-              clone = rq->special;
+-              atomic_inc(&md->pending[rq_data_dir(clone)]);
++              clone = dm_start_request(md, rq);
+               spin_unlock(q->queue_lock);
+               if (map_request(ti, clone, md))
+@@ -1658,8 +1680,6 @@ delay_and_out:
+       blk_delay_queue(q, HZ / 10);
+ out:
+       dm_table_put(map);
+-
+-      return;
+ }
+ int dm_underlying_device_busy(struct request_queue *q)
diff --git a/queue-3.0/series b/queue-3.0/series
new file mode 100644 (file)
index 0000000..d53aa90
--- /dev/null
@@ -0,0 +1,2 @@
+vfs-dcache-fix-deadlock-in-tree-traversal.patch
+dm-handle-requests-beyond-end-of-device-instead-of-using-bug_on.patch
diff --git a/queue-3.0/vfs-dcache-fix-deadlock-in-tree-traversal.patch b/queue-3.0/vfs-dcache-fix-deadlock-in-tree-traversal.patch
new file mode 100644 (file)
index 0000000..ca2b562
--- /dev/null
@@ -0,0 +1,70 @@
+From 8110e16d42d587997bcaee0c864179e6d93603fe Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <miklos@szeredi.hu>
+Date: Mon, 17 Sep 2012 22:23:30 +0200
+Subject: vfs: dcache: fix deadlock in tree traversal
+
+From: Miklos Szeredi <miklos@szeredi.hu>
+
+commit 8110e16d42d587997bcaee0c864179e6d93603fe upstream.
+
+IBM reported a deadlock in select_parent().  This was found to be caused
+by taking rename_lock when already locked when restarting the tree
+traversal.
+
+There are two cases when the traversal needs to be restarted:
+
+ 1) concurrent d_move(); this can only happen when not already locked,
+    since taking rename_lock protects against concurrent d_move().
+
+ 2) racing with final d_put() on child just at the moment of ascending
+    to parent; rename_lock doesn't protect against this rare race, so it
+    can happen when already locked.
+
+Because of case 2, we need to be able to handle restarting the traversal
+when rename_lock is already held.  This patch fixes all three callers of
+try_to_ascend().
+
+IBM reported that the deadlock is gone with this patch.
+
+[ I rewrote the patch to be smaller and just do the "goto again" if the
+  lock was already held, but credit goes to Miklos for the real work.
+   - Linus ]
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/dcache.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -1101,6 +1101,8 @@ positive:
+       return 1;
+ rename_retry:
++      if (locked)
++              goto again;
+       locked = 1;
+       write_seqlock(&rename_lock);
+       goto again;
+@@ -1203,6 +1205,8 @@ out:
+ rename_retry:
+       if (found)
+               return found;
++      if (locked)
++              goto again;
+       locked = 1;
+       write_seqlock(&rename_lock);
+       goto again;
+@@ -2990,6 +2994,8 @@ resume:
+       return;
+ rename_retry:
++      if (locked)
++              goto again;
+       locked = 1;
+       write_seqlock(&rename_lock);
+       goto again;