diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2015-02-17 19:37:15 +0300 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2015-02-19 14:27:50 +0300 |
commit | 7eb71e0351fbb1b242ae70abb7bb17107fe2f792 (patch) | |
tree | a5b06178c59e77df73f6c86dbf4b160f18dbf62c /crypto/khazad.c | |
parent | 7ad18afad02f9802f1eeade91cf880b97e7a9902 (diff) |
libceph: fix double __remove_osd() problem
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:
<osd3 is idle, on the osd lru list>
<con reset - osd3>
con_fault_finish()
osd_reset()
<osdmap - osd3 down>
ceph_osdc_handle_map()
<takes map_sem>
kick_requests()
<takes request_mutex>
reset_changed_osds()
__reset_osd()
__remove_osd()
<releases request_mutex>
<releases map_sem>
<takes map_sem>
<takes request_mutex>
__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 <sage@redhat.com>
Cc: stable@vger.kernel.org # 3.9+: 7c6e6fc53e73: libceph: assert both regular and lingering lists in __remove_osd()
Cc: stable@vger.kernel.org # 3.9+: cc9f1f518cec: libceph: change from BUG to WARN for __remove_osd() asserts
Cc: stable@vger.kernel.org # 3.9+
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Sage Weil <sage@redhat.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Diffstat (limited to 'crypto/khazad.c')
0 files changed, 0 insertions, 0 deletions