On Tue, 2022-03-08 at 13:42 +1100, NeilBrown wrote: > > xprt_destory() claims XPRT_LOCKED and then calls del_timer_sync(). > Both xprt_unlock_connect() and xprt_release() call > ->release_xprt() > which drops XPRT_LOCKED and *then* xprt_schedule_autodisconnect() > which calls mod_timer(). > > This may result in mod_timer() being called *after* del_timer_sync(). > When this happens, the timer may fire long after the xprt has been > freed, > and run_timer_softirq() will probably crash. > > The pairing of ->release_xprt() and xprt_schedule_autodisconnect() is > always called under ->transport_lock. So if we take ->transport_lock > to > call del_timer_sync(), we can be sure that mod_timer() will run first > (if it runs at all). xprt_destroy() never releases XPRT_LOCKED, so how could the above race happen? > > Cc: stable@xxxxxxxxxxxxxxx > Signed-off-by: NeilBrown <neilb@xxxxxxx> > --- > net/sunrpc/xprt.c | 7 +++++++ > 1 file changed, 7 insertions(+) > > diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c > index a02de2bddb28..5388263f8fc8 100644 > --- a/net/sunrpc/xprt.c > +++ b/net/sunrpc/xprt.c > @@ -2112,7 +2112,14 @@ static void xprt_destroy(struct rpc_xprt > *xprt) > */ > wait_on_bit_lock(&xprt->state, XPRT_LOCKED, > TASK_UNINTERRUPTIBLE); > > + /* > + * xprt_schedule_autodisconnect() can run after XPRT_LOCKED > + * is cleared. We use ->transport_lock to ensure the > mod_timer() > + * can only run *before* del_time_sync(), never after. > + */ > + spin_lock(&xprt->transport_lock); > del_timer_sync(&xprt->timer); > + spin_unlock(&xprt->transport_lock); > > /* > * Destroy sockets etc from the system workqueue so they can -- Trond Myklebust Linux NFS client maintainer, Hammerspace trond.myklebust@xxxxxxxxxxxxxxx