Skip to content

Commit

Permalink
SUNRPC: avoid race between mod_timer() and del_timer_sync()
Browse files Browse the repository at this point in the history
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).

Cc: [email protected]
Signed-off-by: NeilBrown <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
  • Loading branch information
neilbrown authored and Trond Myklebust committed Mar 23, 2022
1 parent a245832 commit 3848e96
Showing 1 changed file with 7 additions and 0 deletions.
7 changes: 7 additions & 0 deletions net/sunrpc/xprt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2104,7 +2104,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
Expand Down

0 comments on commit 3848e96

Please sign in to comment.