aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-02-10 16:08:11 -0500
committerJ. Bruce Fields <bfields@redhat.com>2013-02-17 10:53:51 -0500
commitcc630d9f476445927fca599f81182c7f06f79058 (patch)
tree3b7f67264ba2868ed4921a86af9b5d266e6019ed /net
parente75bafbff2270993926abcc31358361db74a9bc2 (diff)
svcrpc: fix rpc server shutdown races
Rewrite server shutdown to remove the assumption that there are no longer any threads running (no longer true, for example, when shutting down the service in one network namespace while it's still running in others). Do that by doing what we'd do in normal circumstances: just CLOSE each socket, then enqueue it. Since there may not be threads to handle the resulting queued xprts, also run a simplified version of the svc_recv() loop run by a server to clean up any closed xprts afterwards. Cc: stable@kernel.org Tested-by: Jason Tibbitts <tibbs@math.uh.edu> Tested-by: Paweł Sikora <pawel.sikora@agmk.net> Acked-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/svc.c9
-rw-r--r--net/sunrpc/svc_xprt.c57
2 files changed, 32 insertions, 34 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b9ba2a8c1c19..89a588b4478b 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -515,15 +515,6 @@ EXPORT_SYMBOL_GPL(svc_create_pooled);
515 515
516void svc_shutdown_net(struct svc_serv *serv, struct net *net) 516void svc_shutdown_net(struct svc_serv *serv, struct net *net)
517{ 517{
518 /*
519 * The set of xprts (contained in the sv_tempsocks and
520 * sv_permsocks lists) is now constant, since it is modified
521 * only by accepting new sockets (done by service threads in
522 * svc_recv) or aging old ones (done by sv_temptimer), or
523 * configuration changes (excluded by whatever locking the
524 * caller is using--nfsd_mutex in the case of nfsd). So it's
525 * safe to traverse those lists and shut everything down:
526 */
527 svc_close_net(serv, net); 518 svc_close_net(serv, net);
528 519
529 if (serv->sv_shutdown) 520 if (serv->sv_shutdown)
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 11a33c874848..80a6640f329b 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -955,21 +955,24 @@ void svc_close_xprt(struct svc_xprt *xprt)
955} 955}
956EXPORT_SYMBOL_GPL(svc_close_xprt); 956EXPORT_SYMBOL_GPL(svc_close_xprt);
957 957
958static void svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) 958static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net)
959{ 959{
960 struct svc_xprt *xprt; 960 struct svc_xprt *xprt;
961 int ret = 0;
961 962
962 spin_lock(&serv->sv_lock); 963 spin_lock(&serv->sv_lock);
963 list_for_each_entry(xprt, xprt_list, xpt_list) { 964 list_for_each_entry(xprt, xprt_list, xpt_list) {
964 if (xprt->xpt_net != net) 965 if (xprt->xpt_net != net)
965 continue; 966 continue;
967 ret++;
966 set_bit(XPT_CLOSE, &xprt->xpt_flags); 968 set_bit(XPT_CLOSE, &xprt->xpt_flags);
967 set_bit(XPT_BUSY, &xprt->xpt_flags); 969 svc_xprt_enqueue(xprt);
968 } 970 }
969 spin_unlock(&serv->sv_lock); 971 spin_unlock(&serv->sv_lock);
972 return ret;
970} 973}
971 974
972static void svc_clear_pools(struct svc_serv *serv, struct net *net) 975static struct svc_xprt *svc_dequeue_net(struct svc_serv *serv, struct net *net)
973{ 976{
974 struct svc_pool *pool; 977 struct svc_pool *pool;
975 struct svc_xprt *xprt; 978 struct svc_xprt *xprt;
@@ -984,42 +987,46 @@ static void svc_clear_pools(struct svc_serv *serv, struct net *net)
984 if (xprt->xpt_net != net) 987 if (xprt->xpt_net != net)
985 continue; 988 continue;
986 list_del_init(&xprt->xpt_ready); 989 list_del_init(&xprt->xpt_ready);
990 spin_unlock_bh(&pool->sp_lock);
991 return xprt;
987 } 992 }
988 spin_unlock_bh(&pool->sp_lock); 993 spin_unlock_bh(&pool->sp_lock);
989 } 994 }
995 return NULL;
990} 996}
991 997
992static void svc_clear_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) 998static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net)
993{ 999{
994 struct svc_xprt *xprt; 1000 struct svc_xprt *xprt;
995 struct svc_xprt *tmp;
996 LIST_HEAD(victims);
997
998 spin_lock(&serv->sv_lock);
999 list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
1000 if (xprt->xpt_net != net)
1001 continue;
1002 list_move(&xprt->xpt_list, &victims);
1003 }
1004 spin_unlock(&serv->sv_lock);
1005 1001
1006 list_for_each_entry_safe(xprt, tmp, &victims, xpt_list) 1002 while ((xprt = svc_dequeue_net(serv, net))) {
1003 set_bit(XPT_CLOSE, &xprt->xpt_flags);
1007 svc_delete_xprt(xprt); 1004 svc_delete_xprt(xprt);
1005 }
1008} 1006}
1009 1007
1008/*
1009 * Server threads may still be running (especially in the case where the
1010 * service is still running in other network namespaces).
1011 *
1012 * So we shut down sockets the same way we would on a running server, by
1013 * setting XPT_CLOSE, enqueuing, and letting a thread pick it up to do
1014 * the close. In the case there are no such other threads,
1015 * threads running, svc_clean_up_xprts() does a simple version of a
1016 * server's main event loop, and in the case where there are other
1017 * threads, we may need to wait a little while and then check again to
1018 * see if they're done.
1019 */
1010void svc_close_net(struct svc_serv *serv, struct net *net) 1020void svc_close_net(struct svc_serv *serv, struct net *net)
1011{ 1021{
1012 svc_close_list(serv, &serv->sv_tempsocks, net); 1022 int delay = 0;
1013 svc_close_list(serv, &serv->sv_permsocks, net);
1014 1023
1015 svc_clear_pools(serv, net); 1024 while (svc_close_list(serv, &serv->sv_permsocks, net) +
1016 /* 1025 svc_close_list(serv, &serv->sv_tempsocks, net)) {
1017 * At this point the sp_sockets lists will stay empty, since 1026
1018 * svc_xprt_enqueue will not add new entries without taking the 1027 svc_clean_up_xprts(serv, net);
1019 * sp_lock and checking XPT_BUSY. 1028 msleep(delay++);
1020 */ 1029 }
1021 svc_clear_list(serv, &serv->sv_tempsocks, net);
1022 svc_clear_list(serv, &serv->sv_permsocks, net);
1023} 1030}
1024 1031
1025/* 1032/*