From 31ee022827f433708f3f04f6ab35fb8de687b74a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 4 Mar 2015 10:26:51 -0800 Subject: [PATCH] 3.14-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 --- ...-and-lingering-lists-in-__remove_osd.patch | 31 +++++ ...bug-to-warn-for-__remove_osd-asserts.patch | 32 +++++ ...ceph-fix-double-__remove_osd-problem.patch | 118 ++++++++++++++++++ queue-3.14/series | 3 + 4 files changed, 184 insertions(+) create mode 100644 queue-3.14/libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch create mode 100644 queue-3.14/libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch create mode 100644 queue-3.14/libceph-fix-double-__remove_osd-problem.patch diff --git a/queue-3.14/libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch b/queue-3.14/libceph-assert-both-regular-and-lingering-lists-in-__remove_osd.patch new file mode 100644 index 00000000000..6bb07a4fd2d --- /dev/null +++ b/queue-3.14/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 +@@ -979,6 +979,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.14/libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch b/queue-3.14/libceph-change-from-bug-to-warn-for-__remove_osd-asserts.patch new file mode 100644 index 00000000000..66ab1d15bcf --- /dev/null +++ b/queue-3.14/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 +@@ -978,8 +978,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.14/libceph-fix-double-__remove_osd-problem.patch b/queue-3.14/libceph-fix-double-__remove_osd-problem.patch new file mode 100644 index 00000000000..089aaa86f5c --- /dev/null +++ b/queue-3.14/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 +@@ -977,14 +977,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) +@@ -994,7 +1004,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); + } +@@ -1024,7 +1034,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); + } +@@ -1039,8 +1049,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; + } + +@@ -1842,6 +1851,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.14/series b/queue-3.14/series index 54ad37831bb..eeff7aa18b9 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -18,6 +18,9 @@ lmedm04-fix-usb_submit_urb-bogus-urb-xfer-pipe-1-type-3-in-interrupt-urb.patch alsa-off-by-one-bug-in-snd_riptide_joystick_probe.patch alsa-hdspm-constrain-periods-to-2-on-older-cards.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 power_supply-88pm860x-fix-leaked-power-supply-on-probe-fail.patch power-bq24190-fix-ignored-supplicants.patch power-gpio-charger-balance-enable-disable_irq_wake-calls.patch -- 2.47.3