1 From 9b3db1e18b4fb74efea1110fbb757aaa240559c0 Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Mon, 29 Nov 2021 15:51:25 +1100
4 Subject: NFSD: simplify locking for network notifier.
6 From: NeilBrown <neilb@suse.de>
8 [ Upstream commit d057cfec4940ce6eeffa22b4a71dec203b06cd55 ]
10 nfsd currently maintains an open-coded read/write semaphore (refcount
11 and wait queue) for each network namespace to ensure the nfs service
12 isn't shut down while the notifier is running.
14 This is excessive. As there is unlikely to be contention between
15 notifiers and they run without sleeping, a single spinlock is sufficient
18 Signed-off-by: NeilBrown <neilb@suse.de>
19 [ cel: ensure nfsd_notifier_lock is static ]
20 Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
22 fs/nfsd/netns.h | 3 ---
23 fs/nfsd/nfsctl.c | 2 --
24 fs/nfsd/nfssvc.c | 38 ++++++++++++++++++++------------------
25 3 files changed, 20 insertions(+), 23 deletions(-)
27 diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
28 index 1fd59eb0730bb..021acdc0d03bb 100644
31 @@ -131,9 +131,6 @@ struct nfsd_net {
35 - wait_queue_head_t ntf_wq;
36 - atomic_t ntf_refcnt;
39 * clientid and stateid data for construction of net unique COPY
41 diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
42 index 53076c5afe62c..504b169d27881 100644
43 --- a/fs/nfsd/nfsctl.c
44 +++ b/fs/nfsd/nfsctl.c
45 @@ -1484,8 +1484,6 @@ static __net_init int nfsd_init_net(struct net *net)
46 nn->clientid_counter = nn->clientid_base + 1;
47 nn->s2s_cp_cl_id = nn->clientid_counter++;
49 - atomic_set(&nn->ntf_refcnt, 0);
50 - init_waitqueue_head(&nn->ntf_wq);
51 seqlock_init(&nn->boot_lock);
54 diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
55 index 8d49dfbe03f85..8554bc7ff4322 100644
56 --- a/fs/nfsd/nfssvc.c
57 +++ b/fs/nfsd/nfssvc.c
58 @@ -434,6 +434,7 @@ static void nfsd_shutdown_net(struct net *net)
59 nfsd_shutdown_generic();
62 +static DEFINE_SPINLOCK(nfsd_notifier_lock);
63 static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event,
66 @@ -443,18 +444,17 @@ static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event,
67 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
68 struct sockaddr_in sin;
70 - if ((event != NETDEV_DOWN) ||
71 - !atomic_inc_not_zero(&nn->ntf_refcnt))
72 + if (event != NETDEV_DOWN || !nn->nfsd_serv)
75 + spin_lock(&nfsd_notifier_lock);
77 dprintk("nfsd_inetaddr_event: removed %pI4\n", &ifa->ifa_local);
78 sin.sin_family = AF_INET;
79 sin.sin_addr.s_addr = ifa->ifa_local;
80 svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin);
82 - atomic_dec(&nn->ntf_refcnt);
83 - wake_up(&nn->ntf_wq);
84 + spin_unlock(&nfsd_notifier_lock);
88 @@ -474,10 +474,10 @@ static int nfsd_inet6addr_event(struct notifier_block *this,
89 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
90 struct sockaddr_in6 sin6;
92 - if ((event != NETDEV_DOWN) ||
93 - !atomic_inc_not_zero(&nn->ntf_refcnt))
94 + if (event != NETDEV_DOWN || !nn->nfsd_serv)
97 + spin_lock(&nfsd_notifier_lock);
99 dprintk("nfsd_inet6addr_event: removed %pI6\n", &ifa->addr);
100 sin6.sin6_family = AF_INET6;
101 @@ -486,8 +486,8 @@ static int nfsd_inet6addr_event(struct notifier_block *this,
102 sin6.sin6_scope_id = ifa->idev->dev->ifindex;
103 svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6);
105 - atomic_dec(&nn->ntf_refcnt);
106 - wake_up(&nn->ntf_wq);
107 + spin_unlock(&nfsd_notifier_lock);
112 @@ -504,7 +504,6 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
114 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
116 - atomic_dec(&nn->ntf_refcnt);
117 /* check if the notifier still has clients */
118 if (atomic_dec_return(&nfsd_notifier_refcount) == 0) {
119 unregister_inetaddr_notifier(&nfsd_inetaddr_notifier);
120 @@ -512,7 +511,6 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
121 unregister_inet6addr_notifier(&nfsd_inet6addr_notifier);
124 - wait_event(nn->ntf_wq, atomic_read(&nn->ntf_refcnt) == 0);
127 * write_ports can create the server without actually starting
128 @@ -624,6 +622,7 @@ int nfsd_create_serv(struct net *net)
131 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
132 + struct svc_serv *serv;
134 WARN_ON(!mutex_is_locked(&nfsd_mutex));
136 @@ -633,21 +632,23 @@ int nfsd_create_serv(struct net *net)
137 if (nfsd_max_blksize == 0)
138 nfsd_max_blksize = nfsd_get_default_max_blksize();
139 nfsd_reset_versions(nn);
140 - nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
141 - &nfsd_thread_sv_ops);
142 - if (nn->nfsd_serv == NULL)
143 + serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
144 + &nfsd_thread_sv_ops);
148 - nn->nfsd_serv->sv_maxconn = nn->max_connections;
149 - error = svc_bind(nn->nfsd_serv, net);
150 + serv->sv_maxconn = nn->max_connections;
151 + error = svc_bind(serv, net);
153 /* NOT nfsd_put() as notifiers (see below) haven't
156 - svc_put(nn->nfsd_serv);
157 - nn->nfsd_serv = NULL;
161 + spin_lock(&nfsd_notifier_lock);
162 + nn->nfsd_serv = serv;
163 + spin_unlock(&nfsd_notifier_lock);
166 /* check if the notifier is already set */
167 @@ -657,7 +658,6 @@ int nfsd_create_serv(struct net *net)
168 register_inet6addr_notifier(&nfsd_inet6addr_notifier);
171 - atomic_inc(&nn->ntf_refcnt);
172 nfsd_reset_boot_verifier(nn);
175 @@ -701,7 +701,9 @@ void nfsd_put(struct net *net)
176 if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) {
177 svc_shutdown_net(nn->nfsd_serv, net);
178 svc_destroy(&nn->nfsd_serv->sv_refcnt);
179 + spin_lock(&nfsd_notifier_lock);
180 nn->nfsd_serv = NULL;
181 + spin_unlock(&nfsd_notifier_lock);