From: Greg Kroah-Hartman Date: Wed, 4 Mar 2015 18:26:41 +0000 (-0800) Subject: 3.10-stable patches X-Git-Tag: v3.10.71~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4591a1bc04e47b01d5a7c26c5310008b2c7416b7;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch libceph-fix-double-__remove_osd-problem.patch --- diff --git a/queue-3.10/libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch b/queue-3.10/libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch new file mode 100644 index 00000000000..7ce5b536085 --- /dev/null +++ b/queue-3.10/libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch @@ -0,0 +1,31 @@ +From 7c6e6fc53e7335570ed82f77656cedce1502744e Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Wed, 18 Jun 2014 13:02:12 +0400 +Subject: libceph: assert both regular and lingering lists in __remove_osd() + +From: Ilya Dryomov + +commit 7c6e6fc53e7335570ed82f77656cedce1502744e upstream. + +It is important that both regular and lingering requests lists are +empty when the OSD is removed. + +Signed-off-by: Ilya Dryomov +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman + +--- + net/ceph/osd_client.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -969,6 +969,8 @@ static void __remove_osd(struct ceph_osd + { + dout("__remove_osd %p\n", osd); + BUG_ON(!list_empty(&osd->o_requests)); ++ BUG_ON(!list_empty(&osd->o_linger_requests)); ++ + rb_erase(&osd->o_node, &osdc->osds); + list_del_init(&osd->o_osd_lru); + ceph_con_close(&osd->o_con); diff --git a/queue-3.10/libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch b/queue-3.10/libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch new file mode 100644 index 00000000000..bb3c56e98a4 --- /dev/null +++ b/queue-3.10/libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch @@ -0,0 +1,32 @@ +From cc9f1f518cec079289d11d732efa490306b1ddad Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Wed, 5 Nov 2014 19:33:44 +0300 +Subject: libceph: change from BUG to WARN for __remove_osd() asserts + +From: Ilya Dryomov + +commit cc9f1f518cec079289d11d732efa490306b1ddad upstream. + +No reason to use BUG_ON for osd request list assertions. + +Signed-off-by: Ilya Dryomov +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman + +--- + net/ceph/osd_client.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -968,8 +968,8 @@ static void put_osd(struct ceph_osd *osd + static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) + { + dout("__remove_osd %p\n", osd); +- BUG_ON(!list_empty(&osd->o_requests)); +- BUG_ON(!list_empty(&osd->o_linger_requests)); ++ WARN_ON(!list_empty(&osd->o_requests)); ++ WARN_ON(!list_empty(&osd->o_linger_requests)); + + rb_erase(&osd->o_node, &osdc->osds); + list_del_init(&osd->o_osd_lru); diff --git a/queue-3.10/libceph-fix-double-__remove_osd-problem.patch b/queue-3.10/libceph-fix-double-__remove_osd-problem.patch new file mode 100644 index 00000000000..5c4bb88b15e --- /dev/null +++ b/queue-3.10/libceph-fix-double-__remove_osd-problem.patch @@ -0,0 +1,118 @@ +From 7eb71e0351fbb1b242ae70abb7bb17107fe2f792 Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Tue, 17 Feb 2015 19:37:15 +0300 +Subject: libceph: fix double __remove_osd() problem + +From: Ilya Dryomov + +commit 7eb71e0351fbb1b242ae70abb7bb17107fe2f792 upstream. + +It turns out it's possible to get __remove_osd() called twice on the +same OSD. That doesn't sit well with rb_erase() - depending on the +shape of the tree we can get a NULL dereference, a soft lockup or +a random crash at some point in the future as we end up touching freed +memory. One scenario that I was able to reproduce is as follows: + + + +con_fault_finish() + osd_reset() + + ceph_osdc_handle_map() + + kick_requests() + + reset_changed_osds() + __reset_osd() + __remove_osd() + + + + + __kick_osd_requests() + __reset_osd() + __remove_osd() <-- !!! + +A case can be made that osd refcounting is imperfect and reworking it +would be a proper resolution, but for now Sage and I decided to fix +this by adding a safe guard around __remove_osd(). + +Fixes: http://tracker.ceph.com/issues/8087 + +Cc: Sage Weil +Signed-off-by: Ilya Dryomov +Reviewed-by: Sage Weil +Reviewed-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman + +--- + net/ceph/osd_client.c | 26 ++++++++++++++++++-------- + 1 file changed, 18 insertions(+), 8 deletions(-) + +--- a/net/ceph/osd_client.c ++++ b/net/ceph/osd_client.c +@@ -967,14 +967,24 @@ static void put_osd(struct ceph_osd *osd + */ + static void __remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) + { +- dout("__remove_osd %p\n", osd); ++ dout("%s %p osd%d\n", __func__, osd, osd->o_osd); + WARN_ON(!list_empty(&osd->o_requests)); + WARN_ON(!list_empty(&osd->o_linger_requests)); + +- rb_erase(&osd->o_node, &osdc->osds); + list_del_init(&osd->o_osd_lru); +- ceph_con_close(&osd->o_con); +- put_osd(osd); ++ rb_erase(&osd->o_node, &osdc->osds); ++ RB_CLEAR_NODE(&osd->o_node); ++} ++ ++static void remove_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd) ++{ ++ dout("%s %p osd%d\n", __func__, osd, osd->o_osd); ++ ++ if (!RB_EMPTY_NODE(&osd->o_node)) { ++ ceph_con_close(&osd->o_con); ++ __remove_osd(osdc, osd); ++ put_osd(osd); ++ } + } + + static void remove_all_osds(struct ceph_osd_client *osdc) +@@ -984,7 +994,7 @@ static void remove_all_osds(struct ceph_ + while (!RB_EMPTY_ROOT(&osdc->osds)) { + struct ceph_osd *osd = rb_entry(rb_first(&osdc->osds), + struct ceph_osd, o_node); +- __remove_osd(osdc, osd); ++ remove_osd(osdc, osd); + } + mutex_unlock(&osdc->request_mutex); + } +@@ -1014,7 +1024,7 @@ static void remove_old_osds(struct ceph_ + list_for_each_entry_safe(osd, nosd, &osdc->osd_lru, o_osd_lru) { + if (time_before(jiffies, osd->lru_ttl)) + break; +- __remove_osd(osdc, osd); ++ remove_osd(osdc, osd); + } + mutex_unlock(&osdc->request_mutex); + } +@@ -1029,8 +1039,7 @@ static int __reset_osd(struct ceph_osd_c + dout("__reset_osd %p osd%d\n", osd, osd->o_osd); + if (list_empty(&osd->o_requests) && + list_empty(&osd->o_linger_requests)) { +- __remove_osd(osdc, osd); +- ++ remove_osd(osdc, osd); + return -ENODEV; + } + +@@ -1612,6 +1621,7 @@ static void reset_changed_osds(struct ce + { + struct rb_node *p, *n; + ++ dout("%s %p\n", __func__, osdc); + for (p = rb_first(&osdc->osds); p; p = n) { + struct ceph_osd *osd = rb_entry(p, struct ceph_osd, o_node); + diff --git a/queue-3.10/series b/queue-3.10/series index 267fad85bf7..87f5f18fd8b 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -51,3 +51,6 @@ jffs2-fix-handling-of-corrupted-summary-length.patch blk-throttle-check-stats_cpu-before-reading-it-from-sysfs.patch x86-mm-aslr-fix-stack-randomization-on-64-bit-systems.patch mips-export-fp-functions-used-by-lose_fpu-1-for-kvm.patch +libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch +libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch +libceph-fix-double-__remove_osd-problem.patch