Re: [PATCH] libceph: Always remove requests from ceph_osdc_handle_map() structures
Viacheslav Dubeyko <[email protected]>
| Newsgroups | org.kernel.vger.ceph-devel |
|---|---|
| Message-ID | <[email protected]> |
CC: [email protected] On Wed, 2026-06-17 at 15:13 +0200, Raphael Zimmer wrote: > ceph_osdc_handle_map() creates two local stack variables that track > (linger) requests that need to be resent. For requests, this is an > rb_root, and for linger requests, a list_head. Subsequently, > handle_one_map() is called, which calls scan_requests() for each osd. > In scan_requests, the new target is calculated for each (linger) > request, and, in case of CALC_TARGET_NEED_RESEND, they are inserted > into > the previously created list/rbtree. All requests in these structures > are > kicked off to their new target osd after processing all osdmaps. If > an > error occurs during processing, e.g., because an osdmap is corrupted, > ceph_osdc_handle_map() jumps to the bad label and doesn't call > kick_requests(). Therefore, the (linger) requests are still inserted > in > the list/rbtree, which now doesn't have a head/root anymore. This > results in requests containing invalid pointers to stack memory. > Subsequently, this can have multiple effects, ranging from not being > able to insert linger requests again because they still have prev and > next pointers or triggering a BUG_ON() assertion when trying to > insert a > non-empty rb_node again, to overwriting stack memory. > > This patch fixes the issue by making sure all (linger) requests are > removed from the list/rbtree in case the osdmap processing returns an > error. This is accomplished by adding logic that is executed after a > jump to the bad label performing the removal similar to > kick_requests. > > Fixes: 5aea3dcd5021 ("libceph: a major OSD client update") > Fixes: 922dab613417 ("libceph, rbd: ceph_osd_linger_request, > watch/notify v2") > Signed-off-by: Raphael Zimmer <[email protected]> > --- > net/ceph/osd_client.c | 21 +++++++++++++++++++++ > 1 file changed, 21 insertions(+) > > diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c > index 5fc79c29aab0..a4d3cbfd27a3 100644 > --- a/net/ceph/osd_client.c > +++ b/net/ceph/osd_client.c > @@ -4129,6 +4129,26 @@ static void kick_requests(struct > ceph_osd_client *osdc, > } > } > > +static void clear_resend_requests(struct ceph_osd_client *osdc, > + struct rb_root *need_resend, > + struct list_head > *need_resend_linger) > +{ > + struct ceph_osd_linger_request *lreq, *nlreq; > + struct rb_node *n; > + > + for (n = rb_first(need_resend); n; ) { > + struct ceph_osd_request *req = > + rb_entry(n, struct ceph_osd_request, r_node); > + > + n = rb_next(n); > + erase_request(need_resend, req); > + } > + > + list_for_each_entry_safe(lreq, nlreq, need_resend_linger, > scan_item) { > + list_del_init(&lreq->scan_item); > + } > +} > + > /* > * Process updated osd map. > * > @@ -4243,6 +4263,7 @@ void ceph_osdc_handle_map(struct > ceph_osd_client *osdc, struct ceph_msg *msg) > bad: > pr_err("osdc handle_map corrupt msg\n"); > ceph_msg_dump(msg); > + clear_resend_requests(osdc, &need_resend, > &need_resend_linger); > up_write(&osdc->lock); > } >