mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
75dbb685f4
request_reinit() is not only ugly as the comment rightfully suggests, but also unsafe. Even though it is called with osdc->lock held for write in all cases, resetting the OSD request refcount can still race with handle_reply() and result in use-after-free. Taking linger ping as an example: handle_timeout thread handle_reply thread down_read(&osdc->lock) req = lookup_request(...) ... finish_request(req) # unregisters up_read(&osdc->lock) __complete_request(req) linger_ping_cb(req) # req->r_kref == 2 because handle_reply still holds its ref down_write(&osdc->lock) send_linger_ping(lreq) req = lreq->ping_req # same req # cancel_linger_request is NOT # called - handle_reply already # unregistered request_reinit(req) WARN_ON(req->r_kref != 1) # fires request_init(req) kref_init(req->r_kref) # req->r_kref == 1 after kref_init ceph_osdc_put_request(req) kref_put(req->r_kref) # req->r_kref == 0 after kref_put, req is freed <further req initialization/use> !!! This happens because send_linger_ping() always (re)uses the same OSD request for watch ping requests, relying on cancel_linger_request() to unregister it from the OSD client and rip its messages out from the messenger. send_linger() does the same for watch/notify registration and watch reconnect requests. Unfortunately cancel_request() doesn't guarantee that after it returns the OSD client would be completely done with the OSD request -- a ref could still be held and the callback (if specified) could still be invoked too. The original motivation for request_reinit() was inability to deal with allocation failures in send_linger() and send_linger_ping(). Switching to using osdc->req_mempool (currently only used by CephFS) respects that and allows us to get rid of request_reinit(). Cc: stable@vger.kernel.org Signed-off-by: Ilya Dryomov <idryomov@gmail.com> Reviewed-by: Xiubo Li <xiubli@redhat.com> Acked-by: Jeff Layton <jlayton@kernel.org> |
||
---|---|---|
.. | ||
crush | ||
armor.c | ||
auth_none.c | ||
auth_none.h | ||
auth_x_protocol.h | ||
auth_x.c | ||
auth_x.h | ||
auth.c | ||
buffer.c | ||
ceph_common.c | ||
ceph_hash.c | ||
ceph_strings.c | ||
cls_lock_client.c | ||
crypto.c | ||
crypto.h | ||
debugfs.c | ||
decode.c | ||
Kconfig | ||
Makefile | ||
messenger_v1.c | ||
messenger_v2.c | ||
messenger.c | ||
mon_client.c | ||
msgpool.c | ||
osd_client.c | ||
osdmap.c | ||
pagelist.c | ||
pagevec.c | ||
snapshot.c | ||
string_table.c | ||
striper.c |