Skip to content

Commit 719f8bc

Browse files
author
J. Bruce Fields
committed
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>
1 parent 21179d8 commit 719f8bc

File tree

1 file changed

+15
-9
lines changed

1 file changed

+15
-9
lines changed

net/sunrpc/svc_xprt.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -917,16 +917,18 @@ void svc_close_xprt(struct svc_xprt *xprt)
917917
}
918918
EXPORT_SYMBOL_GPL(svc_close_xprt);
919919

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)
921921
{
922922
struct svc_xprt *xprt;
923923

924+
spin_lock(&serv->sv_lock);
924925
list_for_each_entry(xprt, xprt_list, xpt_list) {
925926
if (xprt->xpt_net != net)
926927
continue;
927928
set_bit(XPT_CLOSE, &xprt->xpt_flags);
928929
set_bit(XPT_BUSY, &xprt->xpt_flags);
929930
}
931+
spin_unlock(&serv->sv_lock);
930932
}
931933

932934
static void svc_clear_pools(struct svc_serv *serv, struct net *net)
@@ -949,33 +951,37 @@ static void svc_clear_pools(struct svc_serv *serv, struct net *net)
949951
}
950952
}
951953

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)
953955
{
954956
struct svc_xprt *xprt;
955957
struct svc_xprt *tmp;
958+
LIST_HEAD(victims);
956959

960+
spin_lock(&serv->sv_lock);
957961
list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
958962
if (xprt->xpt_net != net)
959963
continue;
960-
svc_delete_xprt(xprt);
964+
list_move(&xprt->xpt_list, &victims);
961965
}
962-
list_for_each_entry(xprt, xprt_list, xpt_list)
963-
BUG_ON(xprt->xpt_net == net);
966+
spin_unlock(&serv->sv_lock);
967+
968+
list_for_each_entry_safe(xprt, tmp, &victims, xpt_list)
969+
svc_delete_xprt(xprt);
964970
}
965971

966972
void svc_close_net(struct svc_serv *serv, struct net *net)
967973
{
968-
svc_close_list(&serv->sv_tempsocks, net);
969-
svc_close_list(&serv->sv_permsocks, net);
974+
svc_close_list(serv, &serv->sv_tempsocks, net);
975+
svc_close_list(serv, &serv->sv_permsocks, net);
970976

971977
svc_clear_pools(serv, net);
972978
/*
973979
* At this point the sp_sockets lists will stay empty, since
974980
* svc_xprt_enqueue will not add new entries without taking the
975981
* sp_lock and checking XPT_BUSY.
976982
*/
977-
svc_clear_list(&serv->sv_tempsocks, net);
978-
svc_clear_list(&serv->sv_permsocks, net);
983+
svc_clear_list(serv, &serv->sv_tempsocks, net);
984+
svc_clear_list(serv, &serv->sv_permsocks, net);
979985
}
980986

981987
/*

0 commit comments

Comments
 (0)