From: Greg Kroah-Hartman Date: Wed, 3 Oct 2012 17:22:47 +0000 (-0700) Subject: 3.0-stable patches X-Git-Tag: v3.0.45~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4cab6d68a7afc180ad5ae32f7b2539e7be6be247;p=thirdparty%2Fkernel%2Fstable-queue.git 3.0-stable patches added patches: dm-handle-requests-beyond-end-of-device-instead-of-using-bug_on.patch vfs-dcache-fix-deadlock-in-tree-traversal.patch --- 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 index 00000000000..29c44e85349 --- /dev/null +++ b/queue-3.0/dm-handle-requests-beyond-end-of-device-instead-of-using-bug_on.patch @@ -0,0 +1,131 @@ +From ba1cbad93dd47223b1f3b8edd50dd9ef2abcb2ed Mon Sep 17 00:00:00 2001 +From: Mike Snitzer +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 + +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 +Signed-off-by: Mike Snitzer +Signed-off-by: Jun'ichi Nomura +Signed-off-by: Alasdair G Kergon +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..d53aa90a576 --- /dev/null +++ b/queue-3.0/series @@ -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 index 00000000000..ca2b5621c60 --- /dev/null +++ b/queue-3.0/vfs-dcache-fix-deadlock-in-tree-traversal.patch @@ -0,0 +1,70 @@ +From 8110e16d42d587997bcaee0c864179e6d93603fe Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Mon, 17 Sep 2012 22:23:30 +0200 +Subject: vfs: dcache: fix deadlock in tree traversal + +From: Miklos Szeredi + +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 +Cc: Al Viro +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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;