diff options
author | J. Bruce Fields | 2013-02-10 10:33:48 -0600 |
---|---|---|
committer | Greg Kroah-Hartman | 2013-03-03 16:09:05 -0600 |
commit | 4bf6d0956ad678f3ef59362cb41dae05a2259f78 (patch) | |
tree | acb8da4042be24bb5912400ff11f5c8c828efec3 /net | |
parent | fd80f53550720f200ca0469e9419c750f895ab50 (diff) | |
download | kernel-common-4bf6d0956ad678f3ef59362cb41dae05a2259f78.tar.gz kernel-common-4bf6d0956ad678f3ef59362cb41dae05a2259f78.tar.xz kernel-common-4bf6d0956ad678f3ef59362cb41dae05a2259f78.zip |
svcrpc: make svc_age_temp_xprts enqueue under sv_lock
commit e75bafbff2270993926abcc31358361db74a9bc2 upstream.
svc_age_temp_xprts expires xprts in a two-step process: first it takes
the sv_lock and moves the xprts to expire off their server-wide list
(sv_tempsocks or sv_permsocks) to a local list. Then it drops the
sv_lock and enqueues and puts each one.
I see no reason for this: svc_xprt_enqueue() will take sp_lock, but the
sv_lock and sp_lock are not otherwise nested anywhere (and documentation
at the top of this file claims it's correct to nest these with sp_lock
inside.)
Tested-by: Jason Tibbitts <tibbs@math.uh.edu>
Tested-by: Paweł Sikora <pawel.sikora@agmk.net>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/svc_xprt.c | 15 |
1 files changed, 2 insertions, 13 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 05dbccf48f6..e47876cf618 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -824,7 +824,6 @@ static void svc_age_temp_xprts(unsigned long closure) | |||
824 | struct svc_serv *serv = (struct svc_serv *)closure; | 824 | struct svc_serv *serv = (struct svc_serv *)closure; |
825 | struct svc_xprt *xprt; | 825 | struct svc_xprt *xprt; |
826 | struct list_head *le, *next; | 826 | struct list_head *le, *next; |
827 | LIST_HEAD(to_be_aged); | ||
828 | 827 | ||
829 | dprintk("svc_age_temp_xprts\n"); | 828 | dprintk("svc_age_temp_xprts\n"); |
830 | 829 | ||
@@ -845,25 +844,15 @@ static void svc_age_temp_xprts(unsigned long closure) | |||
845 | if (atomic_read(&xprt->xpt_ref.refcount) > 1 || | 844 | if (atomic_read(&xprt->xpt_ref.refcount) > 1 || |
846 | test_bit(XPT_BUSY, &xprt->xpt_flags)) | 845 | test_bit(XPT_BUSY, &xprt->xpt_flags)) |
847 | continue; | 846 | continue; |
848 | svc_xprt_get(xprt); | 847 | list_del_init(le); |
849 | list_move(le, &to_be_aged); | ||
850 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | 848 | set_bit(XPT_CLOSE, &xprt->xpt_flags); |
851 | set_bit(XPT_DETACHED, &xprt->xpt_flags); | 849 | set_bit(XPT_DETACHED, &xprt->xpt_flags); |
852 | } | ||
853 | spin_unlock_bh(&serv->sv_lock); | ||
854 | |||
855 | while (!list_empty(&to_be_aged)) { | ||
856 | le = to_be_aged.next; | ||
857 | /* fiddling the xpt_list node is safe 'cos we're XPT_DETACHED */ | ||
858 | list_del_init(le); | ||
859 | xprt = list_entry(le, struct svc_xprt, xpt_list); | ||
860 | |||
861 | dprintk("queuing xprt %p for closing\n", xprt); | 850 | dprintk("queuing xprt %p for closing\n", xprt); |
862 | 851 | ||
863 | /* a thread will dequeue and close it soon */ | 852 | /* a thread will dequeue and close it soon */ |
864 | svc_xprt_enqueue(xprt); | 853 | svc_xprt_enqueue(xprt); |
865 | svc_xprt_put(xprt); | ||
866 | } | 854 | } |
855 | spin_unlock_bh(&serv->sv_lock); | ||
867 | 856 | ||
868 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); | 857 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); |
869 | } | 858 | } |