diff options
author | J. Bruce Fields <bfields@redhat.com> | 2012-08-13 17:03:00 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2012-08-21 14:08:40 -0400 |
commit | 719f8bcc883e7992615f4d5625922e24995e2d98 (patch) | |
tree | 537ba2ab2a43abad53caa83825b8efc897fd1df6 /net/sunrpc/svc_xprt.c | |
parent | 21179d81f1de37c93435dce10d2a4378c370ecca (diff) |
svcrpc: fix xpt_list traversal locking on shutdown
Server threads are not running at this point, but svc_age_temp_xprts
still may be, so we need this locking.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net/sunrpc/svc_xprt.c')
-rw-r--r-- | net/sunrpc/svc_xprt.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index bac973a31367..e1810b947dea 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -917,16 +917,18 @@ void svc_close_xprt(struct svc_xprt *xprt) | |||
917 | } | 917 | } |
918 | EXPORT_SYMBOL_GPL(svc_close_xprt); | 918 | EXPORT_SYMBOL_GPL(svc_close_xprt); |
919 | 919 | ||
920 | static void svc_close_list(struct list_head *xprt_list, struct net *net) | 920 | static void svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) |
921 | { | 921 | { |
922 | struct svc_xprt *xprt; | 922 | struct svc_xprt *xprt; |
923 | 923 | ||
924 | spin_lock(&serv->sv_lock); | ||
924 | list_for_each_entry(xprt, xprt_list, xpt_list) { | 925 | list_for_each_entry(xprt, xprt_list, xpt_list) { |
925 | if (xprt->xpt_net != net) | 926 | if (xprt->xpt_net != net) |
926 | continue; | 927 | continue; |
927 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | 928 | set_bit(XPT_CLOSE, &xprt->xpt_flags); |
928 | set_bit(XPT_BUSY, &xprt->xpt_flags); | 929 | set_bit(XPT_BUSY, &xprt->xpt_flags); |
929 | } | 930 | } |
931 | spin_unlock(&serv->sv_lock); | ||
930 | } | 932 | } |
931 | 933 | ||
932 | static void svc_clear_pools(struct svc_serv *serv, struct net *net) | 934 | static void svc_clear_pools(struct svc_serv *serv, struct net *net) |
@@ -949,24 +951,28 @@ static void svc_clear_pools(struct svc_serv *serv, struct net *net) | |||
949 | } | 951 | } |
950 | } | 952 | } |
951 | 953 | ||
952 | static void svc_clear_list(struct list_head *xprt_list, struct net *net) | 954 | static void svc_clear_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) |
953 | { | 955 | { |
954 | struct svc_xprt *xprt; | 956 | struct svc_xprt *xprt; |
955 | struct svc_xprt *tmp; | 957 | struct svc_xprt *tmp; |
958 | LIST_HEAD(victims); | ||
956 | 959 | ||
960 | spin_lock(&serv->sv_lock); | ||
957 | list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { | 961 | list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { |
958 | if (xprt->xpt_net != net) | 962 | if (xprt->xpt_net != net) |
959 | continue; | 963 | continue; |
960 | svc_delete_xprt(xprt); | 964 | list_move(&xprt->xpt_list, &victims); |
961 | } | 965 | } |
962 | list_for_each_entry(xprt, xprt_list, xpt_list) | 966 | spin_unlock(&serv->sv_lock); |
963 | BUG_ON(xprt->xpt_net == net); | 967 | |
968 | list_for_each_entry_safe(xprt, tmp, &victims, xpt_list) | ||
969 | svc_delete_xprt(xprt); | ||
964 | } | 970 | } |
965 | 971 | ||
966 | void svc_close_net(struct svc_serv *serv, struct net *net) | 972 | void svc_close_net(struct svc_serv *serv, struct net *net) |
967 | { | 973 | { |
968 | svc_close_list(&serv->sv_tempsocks, net); | 974 | svc_close_list(serv, &serv->sv_tempsocks, net); |
969 | svc_close_list(&serv->sv_permsocks, net); | 975 | svc_close_list(serv, &serv->sv_permsocks, net); |
970 | 976 | ||
971 | svc_clear_pools(serv, net); | 977 | svc_clear_pools(serv, net); |
972 | /* | 978 | /* |
@@ -974,8 +980,8 @@ void svc_close_net(struct svc_serv *serv, struct net *net) | |||
974 | * svc_xprt_enqueue will not add new entries without taking the | 980 | * svc_xprt_enqueue will not add new entries without taking the |
975 | * sp_lock and checking XPT_BUSY. | 981 | * sp_lock and checking XPT_BUSY. |
976 | */ | 982 | */ |
977 | svc_clear_list(&serv->sv_tempsocks, net); | 983 | svc_clear_list(serv, &serv->sv_tempsocks, net); |
978 | svc_clear_list(&serv->sv_permsocks, net); | 984 | svc_clear_list(serv, &serv->sv_permsocks, net); |
979 | } | 985 | } |
980 | 986 | ||
981 | /* | 987 | /* |