]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.15/nfsd-simplify-locking-for-network-notifier.patch
Fixes for 5.15
[thirdparty/kernel/stable-queue.git] / queue-5.15 / nfsd-simplify-locking-for-network-notifier.patch
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.
5
6 From: NeilBrown <neilb@suse.de>
7
8 [ Upstream commit d057cfec4940ce6eeffa22b4a71dec203b06cd55 ]
9
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.
13
14 This is excessive. As there is unlikely to be contention between
15 notifiers and they run without sleeping, a single spinlock is sufficient
16 to avoid problems.
17
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>
21 ---
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(-)
26
27 diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
28 index 1fd59eb0730bb..021acdc0d03bb 100644
29 --- a/fs/nfsd/netns.h
30 +++ b/fs/nfsd/netns.h
31 @@ -131,9 +131,6 @@ struct nfsd_net {
32 */
33 int keep_active;
34
35 - wait_queue_head_t ntf_wq;
36 - atomic_t ntf_refcnt;
37 -
38 /*
39 * clientid and stateid data for construction of net unique COPY
40 * stateids.
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++;
48
49 - atomic_set(&nn->ntf_refcnt, 0);
50 - init_waitqueue_head(&nn->ntf_wq);
51 seqlock_init(&nn->boot_lock);
52
53 return 0;
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();
60 }
61
62 +static DEFINE_SPINLOCK(nfsd_notifier_lock);
63 static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event,
64 void *ptr)
65 {
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;
69
70 - if ((event != NETDEV_DOWN) ||
71 - !atomic_inc_not_zero(&nn->ntf_refcnt))
72 + if (event != NETDEV_DOWN || !nn->nfsd_serv)
73 goto out;
74
75 + spin_lock(&nfsd_notifier_lock);
76 if (nn->nfsd_serv) {
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);
81 }
82 - atomic_dec(&nn->ntf_refcnt);
83 - wake_up(&nn->ntf_wq);
84 + spin_unlock(&nfsd_notifier_lock);
85
86 out:
87 return NOTIFY_DONE;
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;
91
92 - if ((event != NETDEV_DOWN) ||
93 - !atomic_inc_not_zero(&nn->ntf_refcnt))
94 + if (event != NETDEV_DOWN || !nn->nfsd_serv)
95 goto out;
96
97 + spin_lock(&nfsd_notifier_lock);
98 if (nn->nfsd_serv) {
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);
104 }
105 - atomic_dec(&nn->ntf_refcnt);
106 - wake_up(&nn->ntf_wq);
107 + spin_unlock(&nfsd_notifier_lock);
108 +
109 out:
110 return NOTIFY_DONE;
111 }
112 @@ -504,7 +504,6 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
113 {
114 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
115
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);
122 #endif
123 }
124 - wait_event(nn->ntf_wq, atomic_read(&nn->ntf_refcnt) == 0);
125
126 /*
127 * write_ports can create the server without actually starting
128 @@ -624,6 +622,7 @@ int nfsd_create_serv(struct net *net)
129 {
130 int error;
131 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
132 + struct svc_serv *serv;
133
134 WARN_ON(!mutex_is_locked(&nfsd_mutex));
135 if (nn->nfsd_serv) {
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);
145 + if (serv == NULL)
146 return -ENOMEM;
147
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);
152 if (error < 0) {
153 /* NOT nfsd_put() as notifiers (see below) haven't
154 * been set up yet.
155 */
156 - svc_put(nn->nfsd_serv);
157 - nn->nfsd_serv = NULL;
158 + svc_put(serv);
159 return error;
160 }
161 + spin_lock(&nfsd_notifier_lock);
162 + nn->nfsd_serv = serv;
163 + spin_unlock(&nfsd_notifier_lock);
164
165 set_max_drc();
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);
169 #endif
170 }
171 - atomic_inc(&nn->ntf_refcnt);
172 nfsd_reset_boot_verifier(nn);
173 return 0;
174 }
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);
182 }
183 }
184
185 --
186 2.43.0
187