diff options
| author | NeilBrown <neilb@suse.de> | 2022-03-08 13:42:17 +1100 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-04-20 09:06:28 +0200 |
| commit | 6180bbce52739ec98cea60b1c35ab6d80351b19b (patch) | |
| tree | 72f9442c603765f89a137bc7e38e5fcc46247c60 /net | |
| parent | 4f96b94a8342fac058117962f1a76fc7ebd1c245 (diff) | |
| download | linux-6180bbce52739ec98cea60b1c35ab6d80351b19b.tar.gz linux-6180bbce52739ec98cea60b1c35ab6d80351b19b.tar.bz2 linux-6180bbce52739ec98cea60b1c35ab6d80351b19b.zip | |
SUNRPC: avoid race between mod_timer() and del_timer_sync()
commit 3848e96edf4788f772d83990022fa7023a233d83 upstream.
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: stable@vger.kernel.org
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
| -rw-r--r-- | net/sunrpc/xprt.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 9491fc81d50a..ff263ece44a7 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1446,7 +1446,14 @@ static void xprt_destroy(struct rpc_xprt *xprt) /* Exclude transport connect/disconnect handlers */ 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); rpc_xprt_debugfs_unregister(xprt); rpc_destroy_wait_queue(&xprt->binding); |
