diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-11 23:11:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-11 23:11:28 -0500 |
commit | 31c1febd7a45229edb3e5d86f354e3c1df543cbb (patch) | |
tree | 9c96b4bb18d47c606d6d85d774d2523f3e47aec0 | |
parent | b4a237598aa740562f842db76d97465c44fb74c1 (diff) | |
parent | 0442f14b15f8e7a8b3778a9f8cf640ef89b2df26 (diff) |
Merge tag 'nfsd-4.4' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields:
"Apologies for coming a little late in the merge window. Fortunately
this is another fairly quiet one:
Mainly smaller bugfixes and cleanup. We're still finding some bugs
from the breakup of the big NFSv4 state lock in 3.17 -- thanks
especially to Andrew Elble and Jeff Layton for tracking down some of
the remaining races"
* tag 'nfsd-4.4' of git://linux-nfs.org/~bfields/linux:
svcrpc: document lack of some memory barriers
nfsd: fix race with open / open upgrade stateids
nfsd: eliminate sending duplicate and repeated delegations
nfsd: remove recurring workqueue job to clean DRC
SUNRPC: drop stale comment in svc_setup_socket()
nfsd: ensure that seqid morphing operations are atomic wrt to copies
nfsd: serialize layout stateid morphing operations
nfsd: improve client_has_state to check for unused openowners
nfsd: fix clid_inuse on mount with security change
sunrpc/cache: make cache flushing more reliable.
nfsd: move include of state.h from trace.c to trace.h
sunrpc: avoid warning in gss_key_timeout
lockd: get rid of reference-counted NSM RPC clients
SUNRPC: Use MSG_SENDPAGE_NOTLAST when calling sendpage()
lockd: create NSM handles per net namespace
nfsd: switch unsigned char flags in svc_fh to bools
nfsd: move svc_fh->fh_maxsize to just after fh_handle
nfsd: drop null test before destroy functions
nfsd: serialize state seqid morphing operations
-rw-r--r-- | fs/lockd/host.c | 8 | ||||
-rw-r--r-- | fs/lockd/mon.c | 125 | ||||
-rw-r--r-- | fs/lockd/netns.h | 4 | ||||
-rw-r--r-- | fs/lockd/svc.c | 2 | ||||
-rw-r--r-- | fs/lockd/svc4proc.c | 2 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4layouts.c | 34 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 265 | ||||
-rw-r--r-- | fs/nfsd/nfscache.c | 32 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.h | 20 | ||||
-rw-r--r-- | fs/nfsd/state.h | 43 | ||||
-rw-r--r-- | fs/nfsd/trace.c | 2 | ||||
-rw-r--r-- | fs/nfsd/trace.h | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 4 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 4 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 2 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 10 | ||||
-rw-r--r-- | include/linux/sunrpc/cache.h | 16 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 13 | ||||
-rw-r--r-- | net/sunrpc/cache.c | 53 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 40 |
24 files changed, 412 insertions, 284 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 969d589c848d..d716c9993a26 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, | |||
116 | atomic_inc(&nsm->sm_count); | 116 | atomic_inc(&nsm->sm_count); |
117 | else { | 117 | else { |
118 | host = NULL; | 118 | host = NULL; |
119 | nsm = nsm_get_handle(ni->sap, ni->salen, | 119 | nsm = nsm_get_handle(ni->net, ni->sap, ni->salen, |
120 | ni->hostname, ni->hostname_len); | 120 | ni->hostname, ni->hostname_len); |
121 | if (unlikely(nsm == NULL)) { | 121 | if (unlikely(nsm == NULL)) { |
122 | dprintk("lockd: %s failed; no nsm handle\n", | 122 | dprintk("lockd: %s failed; no nsm handle\n", |
@@ -161,6 +161,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, | |||
161 | host->h_nsmhandle = nsm; | 161 | host->h_nsmhandle = nsm; |
162 | host->h_addrbuf = nsm->sm_addrbuf; | 162 | host->h_addrbuf = nsm->sm_addrbuf; |
163 | host->net = ni->net; | 163 | host->net = ni->net; |
164 | strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename)); | ||
164 | 165 | ||
165 | out: | 166 | out: |
166 | return host; | 167 | return host; |
@@ -534,17 +535,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, | |||
534 | 535 | ||
535 | /** | 536 | /** |
536 | * nlm_host_rebooted - Release all resources held by rebooted host | 537 | * nlm_host_rebooted - Release all resources held by rebooted host |
538 | * @net: network namespace | ||
537 | * @info: pointer to decoded results of NLM_SM_NOTIFY call | 539 | * @info: pointer to decoded results of NLM_SM_NOTIFY call |
538 | * | 540 | * |
539 | * We were notified that the specified host has rebooted. Release | 541 | * We were notified that the specified host has rebooted. Release |
540 | * all resources held by that peer. | 542 | * all resources held by that peer. |
541 | */ | 543 | */ |
542 | void nlm_host_rebooted(const struct nlm_reboot *info) | 544 | void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info) |
543 | { | 545 | { |
544 | struct nsm_handle *nsm; | 546 | struct nsm_handle *nsm; |
545 | struct nlm_host *host; | 547 | struct nlm_host *host; |
546 | 548 | ||
547 | nsm = nsm_reboot_lookup(info); | 549 | nsm = nsm_reboot_lookup(net, info); |
548 | if (unlikely(nsm == NULL)) | 550 | if (unlikely(nsm == NULL)) |
549 | return; | 551 | return; |
550 | 552 | ||
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 47a32b6d9b90..19166d4a8d31 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -42,7 +42,7 @@ struct nsm_args { | |||
42 | u32 proc; | 42 | u32 proc; |
43 | 43 | ||
44 | char *mon_name; | 44 | char *mon_name; |
45 | char *nodename; | 45 | const char *nodename; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct nsm_res { | 48 | struct nsm_res { |
@@ -51,7 +51,6 @@ struct nsm_res { | |||
51 | }; | 51 | }; |
52 | 52 | ||
53 | static const struct rpc_program nsm_program; | 53 | static const struct rpc_program nsm_program; |
54 | static LIST_HEAD(nsm_handles); | ||
55 | static DEFINE_SPINLOCK(nsm_lock); | 54 | static DEFINE_SPINLOCK(nsm_lock); |
56 | 55 | ||
57 | /* | 56 | /* |
@@ -87,69 +86,18 @@ static struct rpc_clnt *nsm_create(struct net *net, const char *nodename) | |||
87 | return rpc_create(&args); | 86 | return rpc_create(&args); |
88 | } | 87 | } |
89 | 88 | ||
90 | static struct rpc_clnt *nsm_client_set(struct lockd_net *ln, | ||
91 | struct rpc_clnt *clnt) | ||
92 | { | ||
93 | spin_lock(&ln->nsm_clnt_lock); | ||
94 | if (ln->nsm_users == 0) { | ||
95 | if (clnt == NULL) | ||
96 | goto out; | ||
97 | ln->nsm_clnt = clnt; | ||
98 | } | ||
99 | clnt = ln->nsm_clnt; | ||
100 | ln->nsm_users++; | ||
101 | out: | ||
102 | spin_unlock(&ln->nsm_clnt_lock); | ||
103 | return clnt; | ||
104 | } | ||
105 | |||
106 | static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename) | ||
107 | { | ||
108 | struct rpc_clnt *clnt, *new; | ||
109 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
110 | |||
111 | clnt = nsm_client_set(ln, NULL); | ||
112 | if (clnt != NULL) | ||
113 | goto out; | ||
114 | |||
115 | clnt = new = nsm_create(net, nodename); | ||
116 | if (IS_ERR(clnt)) | ||
117 | goto out; | ||
118 | |||
119 | clnt = nsm_client_set(ln, new); | ||
120 | if (clnt != new) | ||
121 | rpc_shutdown_client(new); | ||
122 | out: | ||
123 | return clnt; | ||
124 | } | ||
125 | |||
126 | static void nsm_client_put(struct net *net) | ||
127 | { | ||
128 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
129 | struct rpc_clnt *clnt = NULL; | ||
130 | |||
131 | spin_lock(&ln->nsm_clnt_lock); | ||
132 | ln->nsm_users--; | ||
133 | if (ln->nsm_users == 0) { | ||
134 | clnt = ln->nsm_clnt; | ||
135 | ln->nsm_clnt = NULL; | ||
136 | } | ||
137 | spin_unlock(&ln->nsm_clnt_lock); | ||
138 | if (clnt != NULL) | ||
139 | rpc_shutdown_client(clnt); | ||
140 | } | ||
141 | |||
142 | static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, | 89 | static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, |
143 | struct rpc_clnt *clnt) | 90 | const struct nlm_host *host) |
144 | { | 91 | { |
145 | int status; | 92 | int status; |
93 | struct rpc_clnt *clnt; | ||
146 | struct nsm_args args = { | 94 | struct nsm_args args = { |
147 | .priv = &nsm->sm_priv, | 95 | .priv = &nsm->sm_priv, |
148 | .prog = NLM_PROGRAM, | 96 | .prog = NLM_PROGRAM, |
149 | .vers = 3, | 97 | .vers = 3, |
150 | .proc = NLMPROC_NSM_NOTIFY, | 98 | .proc = NLMPROC_NSM_NOTIFY, |
151 | .mon_name = nsm->sm_mon_name, | 99 | .mon_name = nsm->sm_mon_name, |
152 | .nodename = clnt->cl_nodename, | 100 | .nodename = host->nodename, |
153 | }; | 101 | }; |
154 | struct rpc_message msg = { | 102 | struct rpc_message msg = { |
155 | .rpc_argp = &args, | 103 | .rpc_argp = &args, |
@@ -158,6 +106,13 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, | |||
158 | 106 | ||
159 | memset(res, 0, sizeof(*res)); | 107 | memset(res, 0, sizeof(*res)); |
160 | 108 | ||
109 | clnt = nsm_create(host->net, host->nodename); | ||
110 | if (IS_ERR(clnt)) { | ||
111 | dprintk("lockd: failed to create NSM upcall transport, " | ||
112 | "status=%ld, net=%p\n", PTR_ERR(clnt), host->net); | ||
113 | return PTR_ERR(clnt); | ||
114 | } | ||
115 | |||
161 | msg.rpc_proc = &clnt->cl_procinfo[proc]; | 116 | msg.rpc_proc = &clnt->cl_procinfo[proc]; |
162 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN); | 117 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN); |
163 | if (status == -ECONNREFUSED) { | 118 | if (status == -ECONNREFUSED) { |
@@ -171,6 +126,8 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, | |||
171 | status); | 126 | status); |
172 | else | 127 | else |
173 | status = 0; | 128 | status = 0; |
129 | |||
130 | rpc_shutdown_client(clnt); | ||
174 | return status; | 131 | return status; |
175 | } | 132 | } |
176 | 133 | ||
@@ -190,32 +147,19 @@ int nsm_monitor(const struct nlm_host *host) | |||
190 | struct nsm_handle *nsm = host->h_nsmhandle; | 147 | struct nsm_handle *nsm = host->h_nsmhandle; |
191 | struct nsm_res res; | 148 | struct nsm_res res; |
192 | int status; | 149 | int status; |
193 | struct rpc_clnt *clnt; | ||
194 | const char *nodename = NULL; | ||
195 | 150 | ||
196 | dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); | 151 | dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); |
197 | 152 | ||
198 | if (nsm->sm_monitored) | 153 | if (nsm->sm_monitored) |
199 | return 0; | 154 | return 0; |
200 | 155 | ||
201 | if (host->h_rpcclnt) | ||
202 | nodename = host->h_rpcclnt->cl_nodename; | ||
203 | |||
204 | /* | 156 | /* |
205 | * Choose whether to record the caller_name or IP address of | 157 | * Choose whether to record the caller_name or IP address of |
206 | * this peer in the local rpc.statd's database. | 158 | * this peer in the local rpc.statd's database. |
207 | */ | 159 | */ |
208 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | 160 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; |
209 | 161 | ||
210 | clnt = nsm_client_get(host->net, nodename); | 162 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host); |
211 | if (IS_ERR(clnt)) { | ||
212 | status = PTR_ERR(clnt); | ||
213 | dprintk("lockd: failed to create NSM upcall transport, " | ||
214 | "status=%d, net=%p\n", status, host->net); | ||
215 | return status; | ||
216 | } | ||
217 | |||
218 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt); | ||
219 | if (unlikely(res.status != 0)) | 163 | if (unlikely(res.status != 0)) |
220 | status = -EIO; | 164 | status = -EIO; |
221 | if (unlikely(status < 0)) { | 165 | if (unlikely(status < 0)) { |
@@ -247,11 +191,9 @@ void nsm_unmonitor(const struct nlm_host *host) | |||
247 | 191 | ||
248 | if (atomic_read(&nsm->sm_count) == 1 | 192 | if (atomic_read(&nsm->sm_count) == 1 |
249 | && nsm->sm_monitored && !nsm->sm_sticky) { | 193 | && nsm->sm_monitored && !nsm->sm_sticky) { |
250 | struct lockd_net *ln = net_generic(host->net, lockd_net_id); | ||
251 | |||
252 | dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); | 194 | dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); |
253 | 195 | ||
254 | status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt); | 196 | status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host); |
255 | if (res.status != 0) | 197 | if (res.status != 0) |
256 | status = -EIO; | 198 | status = -EIO; |
257 | if (status < 0) | 199 | if (status < 0) |
@@ -259,38 +201,38 @@ void nsm_unmonitor(const struct nlm_host *host) | |||
259 | nsm->sm_name); | 201 | nsm->sm_name); |
260 | else | 202 | else |
261 | nsm->sm_monitored = 0; | 203 | nsm->sm_monitored = 0; |
262 | |||
263 | nsm_client_put(host->net); | ||
264 | } | 204 | } |
265 | } | 205 | } |
266 | 206 | ||
267 | static struct nsm_handle *nsm_lookup_hostname(const char *hostname, | 207 | static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles, |
268 | const size_t len) | 208 | const char *hostname, const size_t len) |
269 | { | 209 | { |
270 | struct nsm_handle *nsm; | 210 | struct nsm_handle *nsm; |
271 | 211 | ||
272 | list_for_each_entry(nsm, &nsm_handles, sm_link) | 212 | list_for_each_entry(nsm, nsm_handles, sm_link) |
273 | if (strlen(nsm->sm_name) == len && | 213 | if (strlen(nsm->sm_name) == len && |
274 | memcmp(nsm->sm_name, hostname, len) == 0) | 214 | memcmp(nsm->sm_name, hostname, len) == 0) |
275 | return nsm; | 215 | return nsm; |
276 | return NULL; | 216 | return NULL; |
277 | } | 217 | } |
278 | 218 | ||
279 | static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap) | 219 | static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles, |
220 | const struct sockaddr *sap) | ||
280 | { | 221 | { |
281 | struct nsm_handle *nsm; | 222 | struct nsm_handle *nsm; |
282 | 223 | ||
283 | list_for_each_entry(nsm, &nsm_handles, sm_link) | 224 | list_for_each_entry(nsm, nsm_handles, sm_link) |
284 | if (rpc_cmp_addr(nsm_addr(nsm), sap)) | 225 | if (rpc_cmp_addr(nsm_addr(nsm), sap)) |
285 | return nsm; | 226 | return nsm; |
286 | return NULL; | 227 | return NULL; |
287 | } | 228 | } |
288 | 229 | ||
289 | static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv) | 230 | static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles, |
231 | const struct nsm_private *priv) | ||
290 | { | 232 | { |
291 | struct nsm_handle *nsm; | 233 | struct nsm_handle *nsm; |
292 | 234 | ||
293 | list_for_each_entry(nsm, &nsm_handles, sm_link) | 235 | list_for_each_entry(nsm, nsm_handles, sm_link) |
294 | if (memcmp(nsm->sm_priv.data, priv->data, | 236 | if (memcmp(nsm->sm_priv.data, priv->data, |
295 | sizeof(priv->data)) == 0) | 237 | sizeof(priv->data)) == 0) |
296 | return nsm; | 238 | return nsm; |
@@ -353,6 +295,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, | |||
353 | 295 | ||
354 | /** | 296 | /** |
355 | * nsm_get_handle - Find or create a cached nsm_handle | 297 | * nsm_get_handle - Find or create a cached nsm_handle |
298 | * @net: network namespace | ||
356 | * @sap: pointer to socket address of handle to find | 299 | * @sap: pointer to socket address of handle to find |
357 | * @salen: length of socket address | 300 | * @salen: length of socket address |
358 | * @hostname: pointer to C string containing hostname to find | 301 | * @hostname: pointer to C string containing hostname to find |
@@ -365,11 +308,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, | |||
365 | * @hostname cannot be found in the handle cache. Returns NULL if | 308 | * @hostname cannot be found in the handle cache. Returns NULL if |
366 | * an error occurs. | 309 | * an error occurs. |
367 | */ | 310 | */ |
368 | struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, | 311 | struct nsm_handle *nsm_get_handle(const struct net *net, |
312 | const struct sockaddr *sap, | ||
369 | const size_t salen, const char *hostname, | 313 | const size_t salen, const char *hostname, |
370 | const size_t hostname_len) | 314 | const size_t hostname_len) |
371 | { | 315 | { |
372 | struct nsm_handle *cached, *new = NULL; | 316 | struct nsm_handle *cached, *new = NULL; |
317 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
373 | 318 | ||
374 | if (hostname && memchr(hostname, '/', hostname_len) != NULL) { | 319 | if (hostname && memchr(hostname, '/', hostname_len) != NULL) { |
375 | if (printk_ratelimit()) { | 320 | if (printk_ratelimit()) { |
@@ -384,9 +329,10 @@ retry: | |||
384 | spin_lock(&nsm_lock); | 329 | spin_lock(&nsm_lock); |
385 | 330 | ||
386 | if (nsm_use_hostnames && hostname != NULL) | 331 | if (nsm_use_hostnames && hostname != NULL) |
387 | cached = nsm_lookup_hostname(hostname, hostname_len); | 332 | cached = nsm_lookup_hostname(&ln->nsm_handles, |
333 | hostname, hostname_len); | ||
388 | else | 334 | else |
389 | cached = nsm_lookup_addr(sap); | 335 | cached = nsm_lookup_addr(&ln->nsm_handles, sap); |
390 | 336 | ||
391 | if (cached != NULL) { | 337 | if (cached != NULL) { |
392 | atomic_inc(&cached->sm_count); | 338 | atomic_inc(&cached->sm_count); |
@@ -400,7 +346,7 @@ retry: | |||
400 | } | 346 | } |
401 | 347 | ||
402 | if (new != NULL) { | 348 | if (new != NULL) { |
403 | list_add(&new->sm_link, &nsm_handles); | 349 | list_add(&new->sm_link, &ln->nsm_handles); |
404 | spin_unlock(&nsm_lock); | 350 | spin_unlock(&nsm_lock); |
405 | dprintk("lockd: created nsm_handle for %s (%s)\n", | 351 | dprintk("lockd: created nsm_handle for %s (%s)\n", |
406 | new->sm_name, new->sm_addrbuf); | 352 | new->sm_name, new->sm_addrbuf); |
@@ -417,19 +363,22 @@ retry: | |||
417 | 363 | ||
418 | /** | 364 | /** |
419 | * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle | 365 | * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle |
366 | * @net: network namespace | ||
420 | * @info: pointer to NLMPROC_SM_NOTIFY arguments | 367 | * @info: pointer to NLMPROC_SM_NOTIFY arguments |
421 | * | 368 | * |
422 | * Returns a matching nsm_handle if found in the nsm cache. The returned | 369 | * Returns a matching nsm_handle if found in the nsm cache. The returned |
423 | * nsm_handle's reference count is bumped. Otherwise returns NULL if some | 370 | * nsm_handle's reference count is bumped. Otherwise returns NULL if some |
424 | * error occurred. | 371 | * error occurred. |
425 | */ | 372 | */ |
426 | struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info) | 373 | struct nsm_handle *nsm_reboot_lookup(const struct net *net, |
374 | const struct nlm_reboot *info) | ||
427 | { | 375 | { |
428 | struct nsm_handle *cached; | 376 | struct nsm_handle *cached; |
377 | struct lockd_net *ln = net_generic(net, lockd_net_id); | ||
429 | 378 | ||
430 | spin_lock(&nsm_lock); | 379 | spin_lock(&nsm_lock); |
431 | 380 | ||
432 | cached = nsm_lookup_priv(&info->priv); | 381 | cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv); |
433 | if (unlikely(cached == NULL)) { | 382 | if (unlikely(cached == NULL)) { |
434 | spin_unlock(&nsm_lock); | 383 | spin_unlock(&nsm_lock); |
435 | dprintk("lockd: never saw rebooted peer '%.*s' before\n", | 384 | dprintk("lockd: never saw rebooted peer '%.*s' before\n", |
diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h index 097bfa3adb1c..5426189406c1 100644 --- a/fs/lockd/netns.h +++ b/fs/lockd/netns.h | |||
@@ -12,9 +12,7 @@ struct lockd_net { | |||
12 | struct delayed_work grace_period_end; | 12 | struct delayed_work grace_period_end; |
13 | struct lock_manager lockd_manager; | 13 | struct lock_manager lockd_manager; |
14 | 14 | ||
15 | spinlock_t nsm_clnt_lock; | 15 | struct list_head nsm_handles; |
16 | unsigned int nsm_users; | ||
17 | struct rpc_clnt *nsm_clnt; | ||
18 | }; | 16 | }; |
19 | 17 | ||
20 | extern int lockd_net_id; | 18 | extern int lockd_net_id; |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index d678bcc3cbcb..5f31ebd96c06 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -592,7 +592,7 @@ static int lockd_init_net(struct net *net) | |||
592 | INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender); | 592 | INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender); |
593 | INIT_LIST_HEAD(&ln->lockd_manager.list); | 593 | INIT_LIST_HEAD(&ln->lockd_manager.list); |
594 | ln->lockd_manager.block_opens = false; | 594 | ln->lockd_manager.block_opens = false; |
595 | spin_lock_init(&ln->nsm_clnt_lock); | 595 | INIT_LIST_HEAD(&ln->nsm_handles); |
596 | return 0; | 596 | return 0; |
597 | } | 597 | } |
598 | 598 | ||
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index b147d1ae71fd..09c576f26c7b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, | |||
421 | return rpc_system_err; | 421 | return rpc_system_err; |
422 | } | 422 | } |
423 | 423 | ||
424 | nlm_host_rebooted(argp); | 424 | nlm_host_rebooted(SVC_NET(rqstp), argp); |
425 | return rpc_success; | 425 | return rpc_success; |
426 | } | 426 | } |
427 | 427 | ||
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 21171f0c6477..fb26b9f522e7 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, | |||
464 | return rpc_system_err; | 464 | return rpc_system_err; |
465 | } | 465 | } |
466 | 466 | ||
467 | nlm_host_rebooted(argp); | 467 | nlm_host_rebooted(SVC_NET(rqstp), argp); |
468 | return rpc_success; | 468 | return rpc_success; |
469 | } | 469 | } |
470 | 470 | ||
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index f6e7cbabac5a..00575d776d91 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -262,11 +262,11 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
262 | err = fh_getattr(fhp, &fhp->fh_post_attr); | 262 | err = fh_getattr(fhp, &fhp->fh_post_attr); |
263 | fhp->fh_post_change = d_inode(fhp->fh_dentry)->i_version; | 263 | fhp->fh_post_change = d_inode(fhp->fh_dentry)->i_version; |
264 | if (err) { | 264 | if (err) { |
265 | fhp->fh_post_saved = 0; | 265 | fhp->fh_post_saved = false; |
266 | /* Grab the ctime anyway - set_change_info might use it */ | 266 | /* Grab the ctime anyway - set_change_info might use it */ |
267 | fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime; | 267 | fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime; |
268 | } else | 268 | } else |
269 | fhp->fh_post_saved = 1; | 269 | fhp->fh_post_saved = true; |
270 | } | 270 | } |
271 | 271 | ||
272 | /* | 272 | /* |
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index ebf90e487c75..9ffef06b30d5 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c | |||
@@ -201,6 +201,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, | |||
201 | INIT_LIST_HEAD(&ls->ls_perfile); | 201 | INIT_LIST_HEAD(&ls->ls_perfile); |
202 | spin_lock_init(&ls->ls_lock); | 202 | spin_lock_init(&ls->ls_lock); |
203 | INIT_LIST_HEAD(&ls->ls_layouts); | 203 | INIT_LIST_HEAD(&ls->ls_layouts); |
204 | mutex_init(&ls->ls_mutex); | ||
204 | ls->ls_layout_type = layout_type; | 205 | ls->ls_layout_type = layout_type; |
205 | nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops, | 206 | nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops, |
206 | NFSPROC4_CLNT_CB_LAYOUT); | 207 | NFSPROC4_CLNT_CB_LAYOUT); |
@@ -262,19 +263,23 @@ nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp, | |||
262 | status = nfserr_jukebox; | 263 | status = nfserr_jukebox; |
263 | if (!ls) | 264 | if (!ls) |
264 | goto out; | 265 | goto out; |
266 | mutex_lock(&ls->ls_mutex); | ||
265 | } else { | 267 | } else { |
266 | ls = container_of(stid, struct nfs4_layout_stateid, ls_stid); | 268 | ls = container_of(stid, struct nfs4_layout_stateid, ls_stid); |
267 | 269 | ||
268 | status = nfserr_bad_stateid; | 270 | status = nfserr_bad_stateid; |
271 | mutex_lock(&ls->ls_mutex); | ||
269 | if (stateid->si_generation > stid->sc_stateid.si_generation) | 272 | if (stateid->si_generation > stid->sc_stateid.si_generation) |
270 | goto out_put_stid; | 273 | goto out_unlock_stid; |
271 | if (layout_type != ls->ls_layout_type) | 274 | if (layout_type != ls->ls_layout_type) |
272 | goto out_put_stid; | 275 | goto out_unlock_stid; |
273 | } | 276 | } |
274 | 277 | ||
275 | *lsp = ls; | 278 | *lsp = ls; |
276 | return 0; | 279 | return 0; |
277 | 280 | ||
281 | out_unlock_stid: | ||
282 | mutex_unlock(&ls->ls_mutex); | ||
278 | out_put_stid: | 283 | out_put_stid: |
279 | nfs4_put_stid(stid); | 284 | nfs4_put_stid(stid); |
280 | out: | 285 | out: |
@@ -296,8 +301,6 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls) | |||
296 | trace_layout_recall(&ls->ls_stid.sc_stateid); | 301 | trace_layout_recall(&ls->ls_stid.sc_stateid); |
297 | 302 | ||
298 | atomic_inc(&ls->ls_stid.sc_count); | 303 | atomic_inc(&ls->ls_stid.sc_count); |
299 | update_stateid(&ls->ls_stid.sc_stateid); | ||
300 | memcpy(&ls->ls_recall_sid, &ls->ls_stid.sc_stateid, sizeof(stateid_t)); | ||
301 | nfsd4_run_cb(&ls->ls_recall); | 304 | nfsd4_run_cb(&ls->ls_recall); |
302 | 305 | ||
303 | out_unlock: | 306 | out_unlock: |
@@ -406,8 +409,7 @@ nfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls) | |||
406 | list_add_tail(&new->lo_perstate, &ls->ls_layouts); | 409 | list_add_tail(&new->lo_perstate, &ls->ls_layouts); |
407 | new = NULL; | 410 | new = NULL; |
408 | done: | 411 | done: |
409 | update_stateid(&ls->ls_stid.sc_stateid); | 412 | nfs4_inc_and_copy_stateid(&lgp->lg_sid, &ls->ls_stid); |
410 | memcpy(&lgp->lg_sid, &ls->ls_stid.sc_stateid, sizeof(stateid_t)); | ||
411 | spin_unlock(&ls->ls_lock); | 413 | spin_unlock(&ls->ls_lock); |
412 | out: | 414 | out: |
413 | spin_unlock(&fp->fi_lock); | 415 | spin_unlock(&fp->fi_lock); |
@@ -481,11 +483,8 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp, | |||
481 | } | 483 | } |
482 | } | 484 | } |
483 | if (!list_empty(&ls->ls_layouts)) { | 485 | if (!list_empty(&ls->ls_layouts)) { |
484 | if (found) { | 486 | if (found) |
485 | update_stateid(&ls->ls_stid.sc_stateid); | 487 | nfs4_inc_and_copy_stateid(&lrp->lr_sid, &ls->ls_stid); |
486 | memcpy(&lrp->lr_sid, &ls->ls_stid.sc_stateid, | ||
487 | sizeof(stateid_t)); | ||
488 | } | ||
489 | lrp->lrs_present = 1; | 488 | lrp->lrs_present = 1; |
490 | } else { | 489 | } else { |
491 | trace_layoutstate_unhash(&ls->ls_stid.sc_stateid); | 490 | trace_layoutstate_unhash(&ls->ls_stid.sc_stateid); |
@@ -494,6 +493,7 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp, | |||
494 | } | 493 | } |
495 | spin_unlock(&ls->ls_lock); | 494 | spin_unlock(&ls->ls_lock); |
496 | 495 | ||
496 | mutex_unlock(&ls->ls_mutex); | ||
497 | nfs4_put_stid(&ls->ls_stid); | 497 | nfs4_put_stid(&ls->ls_stid); |
498 | nfsd4_free_layouts(&reaplist); | 498 | nfsd4_free_layouts(&reaplist); |
499 | return nfs_ok; | 499 | return nfs_ok; |
@@ -608,6 +608,16 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls) | |||
608 | } | 608 | } |
609 | } | 609 | } |
610 | 610 | ||
611 | static void | ||
612 | nfsd4_cb_layout_prepare(struct nfsd4_callback *cb) | ||
613 | { | ||
614 | struct nfs4_layout_stateid *ls = | ||
615 | container_of(cb, struct nfs4_layout_stateid, ls_recall); | ||
616 | |||
617 | mutex_lock(&ls->ls_mutex); | ||
618 | nfs4_inc_and_copy_stateid(&ls->ls_recall_sid, &ls->ls_stid); | ||
619 | } | ||
620 | |||
611 | static int | 621 | static int |
612 | nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task) | 622 | nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task) |
613 | { | 623 | { |
@@ -649,12 +659,14 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb) | |||
649 | 659 | ||
650 | trace_layout_recall_release(&ls->ls_stid.sc_stateid); | 660 | trace_layout_recall_release(&ls->ls_stid.sc_stateid); |
651 | 661 | ||
662 | mutex_unlock(&ls->ls_mutex); | ||
652 | nfsd4_return_all_layouts(ls, &reaplist); | 663 | nfsd4_return_all_layouts(ls, &reaplist); |
653 | nfsd4_free_layouts(&reaplist); | 664 | nfsd4_free_layouts(&reaplist); |
654 | nfs4_put_stid(&ls->ls_stid); | 665 | nfs4_put_stid(&ls->ls_stid); |
655 | } | 666 | } |
656 | 667 | ||
657 | static struct nfsd4_callback_ops nfsd4_cb_layout_ops = { | 668 | static struct nfsd4_callback_ops nfsd4_cb_layout_ops = { |
669 | .prepare = nfsd4_cb_layout_prepare, | ||
658 | .done = nfsd4_cb_layout_done, | 670 | .done = nfsd4_cb_layout_done, |
659 | .release = nfsd4_cb_layout_release, | 671 | .release = nfsd4_cb_layout_release, |
660 | }; | 672 | }; |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 4ce6b97b31ad..a9f096c7e99f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -1309,6 +1309,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp, | |||
1309 | nfserr = nfsd4_insert_layout(lgp, ls); | 1309 | nfserr = nfsd4_insert_layout(lgp, ls); |
1310 | 1310 | ||
1311 | out_put_stid: | 1311 | out_put_stid: |
1312 | mutex_unlock(&ls->ls_mutex); | ||
1312 | nfs4_put_stid(&ls->ls_stid); | 1313 | nfs4_put_stid(&ls->ls_stid); |
1313 | out: | 1314 | out: |
1314 | return nfserr; | 1315 | return nfserr; |
@@ -1362,6 +1363,9 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, | |||
1362 | goto out; | 1363 | goto out; |
1363 | } | 1364 | } |
1364 | 1365 | ||
1366 | /* LAYOUTCOMMIT does not require any serialization */ | ||
1367 | mutex_unlock(&ls->ls_mutex); | ||
1368 | |||
1365 | if (new_size > i_size_read(inode)) { | 1369 | if (new_size > i_size_read(inode)) { |
1366 | lcp->lc_size_chg = 1; | 1370 | lcp->lc_size_chg = 1; |
1367 | lcp->lc_newsize = new_size; | 1371 | lcp->lc_newsize = new_size; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0f1d5691b795..6b800b5b8fed 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -575,6 +575,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | |||
575 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; | 575 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; |
576 | /* Will be incremented before return to client: */ | 576 | /* Will be incremented before return to client: */ |
577 | atomic_set(&stid->sc_count, 1); | 577 | atomic_set(&stid->sc_count, 1); |
578 | spin_lock_init(&stid->sc_lock); | ||
578 | 579 | ||
579 | /* | 580 | /* |
580 | * It shouldn't be a problem to reuse an opaque stateid value. | 581 | * It shouldn't be a problem to reuse an opaque stateid value. |
@@ -745,6 +746,18 @@ nfs4_put_stid(struct nfs4_stid *s) | |||
745 | put_nfs4_file(fp); | 746 | put_nfs4_file(fp); |
746 | } | 747 | } |
747 | 748 | ||
749 | void | ||
750 | nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) | ||
751 | { | ||
752 | stateid_t *src = &stid->sc_stateid; | ||
753 | |||
754 | spin_lock(&stid->sc_lock); | ||
755 | if (unlikely(++src->si_generation == 0)) | ||
756 | src->si_generation = 1; | ||
757 | memcpy(dst, src, sizeof(*dst)); | ||
758 | spin_unlock(&stid->sc_lock); | ||
759 | } | ||
760 | |||
748 | static void nfs4_put_deleg_lease(struct nfs4_file *fp) | 761 | static void nfs4_put_deleg_lease(struct nfs4_file *fp) |
749 | { | 762 | { |
750 | struct file *filp = NULL; | 763 | struct file *filp = NULL; |
@@ -765,16 +778,68 @@ void nfs4_unhash_stid(struct nfs4_stid *s) | |||
765 | s->sc_type = 0; | 778 | s->sc_type = 0; |
766 | } | 779 | } |
767 | 780 | ||
768 | static void | 781 | /** |
782 | * nfs4_get_existing_delegation - Discover if this delegation already exists | ||
783 | * @clp: a pointer to the nfs4_client we're granting a delegation to | ||
784 | * @fp: a pointer to the nfs4_file we're granting a delegation on | ||
785 | * | ||
786 | * Return: | ||
787 | * On success: NULL if an existing delegation was not found. | ||
788 | * | ||
789 | * On error: -EAGAIN if one was previously granted to this nfs4_client | ||
790 | * for this nfs4_file. | ||
791 | * | ||
792 | */ | ||
793 | |||
794 | static int | ||
795 | nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp) | ||
796 | { | ||
797 | struct nfs4_delegation *searchdp = NULL; | ||
798 | struct nfs4_client *searchclp = NULL; | ||
799 | |||
800 | lockdep_assert_held(&state_lock); | ||
801 | lockdep_assert_held(&fp->fi_lock); | ||
802 | |||
803 | list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { | ||
804 | searchclp = searchdp->dl_stid.sc_client; | ||
805 | if (clp == searchclp) { | ||
806 | return -EAGAIN; | ||
807 | } | ||
808 | } | ||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | /** | ||
813 | * hash_delegation_locked - Add a delegation to the appropriate lists | ||
814 | * @dp: a pointer to the nfs4_delegation we are adding. | ||
815 | * @fp: a pointer to the nfs4_file we're granting a delegation on | ||
816 | * | ||
817 | * Return: | ||
818 | * On success: NULL if the delegation was successfully hashed. | ||
819 | * | ||
820 | * On error: -EAGAIN if one was previously granted to this | ||
821 | * nfs4_client for this nfs4_file. Delegation is not hashed. | ||
822 | * | ||
823 | */ | ||
824 | |||
825 | static int | ||
769 | hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) | 826 | hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) |
770 | { | 827 | { |
828 | int status; | ||
829 | struct nfs4_client *clp = dp->dl_stid.sc_client; | ||
830 | |||
771 | lockdep_assert_held(&state_lock); | 831 | lockdep_assert_held(&state_lock); |
772 | lockdep_assert_held(&fp->fi_lock); | 832 | lockdep_assert_held(&fp->fi_lock); |
773 | 833 | ||
834 | status = nfs4_get_existing_delegation(clp, fp); | ||
835 | if (status) | ||
836 | return status; | ||
837 | ++fp->fi_delegees; | ||
774 | atomic_inc(&dp->dl_stid.sc_count); | 838 | atomic_inc(&dp->dl_stid.sc_count); |
775 | dp->dl_stid.sc_type = NFS4_DELEG_STID; | 839 | dp->dl_stid.sc_type = NFS4_DELEG_STID; |
776 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 840 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
777 | list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); | 841 | list_add(&dp->dl_perclnt, &clp->cl_delegations); |
842 | return 0; | ||
778 | } | 843 | } |
779 | 844 | ||
780 | static bool | 845 | static bool |
@@ -2256,15 +2321,20 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | |||
2256 | clid->flags = new->cl_exchange_flags; | 2321 | clid->flags = new->cl_exchange_flags; |
2257 | } | 2322 | } |
2258 | 2323 | ||
2324 | static bool client_has_openowners(struct nfs4_client *clp) | ||
2325 | { | ||
2326 | struct nfs4_openowner *oo; | ||
2327 | |||
2328 | list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { | ||
2329 | if (!list_empty(&oo->oo_owner.so_stateids)) | ||
2330 | return true; | ||
2331 | } | ||
2332 | return false; | ||
2333 | } | ||
2334 | |||
2259 | static bool client_has_state(struct nfs4_client *clp) | 2335 | static bool client_has_state(struct nfs4_client *clp) |
2260 | { | 2336 | { |
2261 | /* | 2337 | return client_has_openowners(clp) |
2262 | * Note clp->cl_openowners check isn't quite right: there's no | ||
2263 | * need to count owners without stateid's. | ||
2264 | * | ||
2265 | * Also note we should probably be using this in 4.0 case too. | ||
2266 | */ | ||
2267 | return !list_empty(&clp->cl_openowners) | ||
2268 | #ifdef CONFIG_NFSD_PNFS | 2338 | #ifdef CONFIG_NFSD_PNFS |
2269 | || !list_empty(&clp->cl_lo_states) | 2339 | || !list_empty(&clp->cl_lo_states) |
2270 | #endif | 2340 | #endif |
@@ -3049,7 +3119,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3049 | /* Cases below refer to rfc 3530 section 14.2.33: */ | 3119 | /* Cases below refer to rfc 3530 section 14.2.33: */ |
3050 | spin_lock(&nn->client_lock); | 3120 | spin_lock(&nn->client_lock); |
3051 | conf = find_confirmed_client_by_name(&clname, nn); | 3121 | conf = find_confirmed_client_by_name(&clname, nn); |
3052 | if (conf) { | 3122 | if (conf && client_has_state(conf)) { |
3053 | /* case 0: */ | 3123 | /* case 0: */ |
3054 | status = nfserr_clid_inuse; | 3124 | status = nfserr_clid_inuse; |
3055 | if (clp_used_exchangeid(conf)) | 3125 | if (clp_used_exchangeid(conf)) |
@@ -3136,6 +3206,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
3136 | } else { /* case 3: normal case; new or rebooted client */ | 3206 | } else { /* case 3: normal case; new or rebooted client */ |
3137 | old = find_confirmed_client_by_name(&unconf->cl_name, nn); | 3207 | old = find_confirmed_client_by_name(&unconf->cl_name, nn); |
3138 | if (old) { | 3208 | if (old) { |
3209 | status = nfserr_clid_inuse; | ||
3210 | if (client_has_state(old) | ||
3211 | && !same_creds(&unconf->cl_cred, | ||
3212 | &old->cl_cred)) | ||
3213 | goto out; | ||
3139 | status = mark_client_expired_locked(old); | 3214 | status = mark_client_expired_locked(old); |
3140 | if (status) { | 3215 | if (status) { |
3141 | old = NULL; | 3216 | old = NULL; |
@@ -3317,6 +3392,27 @@ static const struct nfs4_stateowner_operations openowner_ops = { | |||
3317 | .so_free = nfs4_free_openowner, | 3392 | .so_free = nfs4_free_openowner, |
3318 | }; | 3393 | }; |
3319 | 3394 | ||
3395 | static struct nfs4_ol_stateid * | ||
3396 | nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) | ||
3397 | { | ||
3398 | struct nfs4_ol_stateid *local, *ret = NULL; | ||
3399 | struct nfs4_openowner *oo = open->op_openowner; | ||
3400 | |||
3401 | lockdep_assert_held(&fp->fi_lock); | ||
3402 | |||
3403 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { | ||
3404 | /* ignore lock owners */ | ||
3405 | if (local->st_stateowner->so_is_open_owner == 0) | ||
3406 | continue; | ||
3407 | if (local->st_stateowner == &oo->oo_owner) { | ||
3408 | ret = local; | ||
3409 | atomic_inc(&ret->st_stid.sc_count); | ||
3410 | break; | ||
3411 | } | ||
3412 | } | ||
3413 | return ret; | ||
3414 | } | ||
3415 | |||
3320 | static struct nfs4_openowner * | 3416 | static struct nfs4_openowner * |
3321 | alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, | 3417 | alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, |
3322 | struct nfsd4_compound_state *cstate) | 3418 | struct nfsd4_compound_state *cstate) |
@@ -3348,9 +3444,20 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, | |||
3348 | return ret; | 3444 | return ret; |
3349 | } | 3445 | } |
3350 | 3446 | ||
3351 | static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { | 3447 | static struct nfs4_ol_stateid * |
3448 | init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | ||
3449 | struct nfsd4_open *open) | ||
3450 | { | ||
3451 | |||
3352 | struct nfs4_openowner *oo = open->op_openowner; | 3452 | struct nfs4_openowner *oo = open->op_openowner; |
3453 | struct nfs4_ol_stateid *retstp = NULL; | ||
3353 | 3454 | ||
3455 | spin_lock(&oo->oo_owner.so_client->cl_lock); | ||
3456 | spin_lock(&fp->fi_lock); | ||
3457 | |||
3458 | retstp = nfsd4_find_existing_open(fp, open); | ||
3459 | if (retstp) | ||
3460 | goto out_unlock; | ||
3354 | atomic_inc(&stp->st_stid.sc_count); | 3461 | atomic_inc(&stp->st_stid.sc_count); |
3355 | stp->st_stid.sc_type = NFS4_OPEN_STID; | 3462 | stp->st_stid.sc_type = NFS4_OPEN_STID; |
3356 | INIT_LIST_HEAD(&stp->st_locks); | 3463 | INIT_LIST_HEAD(&stp->st_locks); |
@@ -3360,12 +3467,14 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
3360 | stp->st_access_bmap = 0; | 3467 | stp->st_access_bmap = 0; |
3361 | stp->st_deny_bmap = 0; | 3468 | stp->st_deny_bmap = 0; |
3362 | stp->st_openstp = NULL; | 3469 | stp->st_openstp = NULL; |
3363 | spin_lock(&oo->oo_owner.so_client->cl_lock); | 3470 | init_rwsem(&stp->st_rwsem); |
3364 | list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); | 3471 | list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); |
3365 | spin_lock(&fp->fi_lock); | ||
3366 | list_add(&stp->st_perfile, &fp->fi_stateids); | 3472 | list_add(&stp->st_perfile, &fp->fi_stateids); |
3473 | |||
3474 | out_unlock: | ||
3367 | spin_unlock(&fp->fi_lock); | 3475 | spin_unlock(&fp->fi_lock); |
3368 | spin_unlock(&oo->oo_owner.so_client->cl_lock); | 3476 | spin_unlock(&oo->oo_owner.so_client->cl_lock); |
3477 | return retstp; | ||
3369 | } | 3478 | } |
3370 | 3479 | ||
3371 | /* | 3480 | /* |
@@ -3776,27 +3885,6 @@ out: | |||
3776 | return nfs_ok; | 3885 | return nfs_ok; |
3777 | } | 3886 | } |
3778 | 3887 | ||
3779 | static struct nfs4_ol_stateid * | ||
3780 | nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) | ||
3781 | { | ||
3782 | struct nfs4_ol_stateid *local, *ret = NULL; | ||
3783 | struct nfs4_openowner *oo = open->op_openowner; | ||
3784 | |||
3785 | spin_lock(&fp->fi_lock); | ||
3786 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { | ||
3787 | /* ignore lock owners */ | ||
3788 | if (local->st_stateowner->so_is_open_owner == 0) | ||
3789 | continue; | ||
3790 | if (local->st_stateowner == &oo->oo_owner) { | ||
3791 | ret = local; | ||
3792 | atomic_inc(&ret->st_stid.sc_count); | ||
3793 | break; | ||
3794 | } | ||
3795 | } | ||
3796 | spin_unlock(&fp->fi_lock); | ||
3797 | return ret; | ||
3798 | } | ||
3799 | |||
3800 | static inline int nfs4_access_to_access(u32 nfs4_access) | 3888 | static inline int nfs4_access_to_access(u32 nfs4_access) |
3801 | { | 3889 | { |
3802 | int flags = 0; | 3890 | int flags = 0; |
@@ -3945,6 +4033,18 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag) | |||
3945 | return fl; | 4033 | return fl; |
3946 | } | 4034 | } |
3947 | 4035 | ||
4036 | /** | ||
4037 | * nfs4_setlease - Obtain a delegation by requesting lease from vfs layer | ||
4038 | * @dp: a pointer to the nfs4_delegation we're adding. | ||
4039 | * | ||
4040 | * Return: | ||
4041 | * On success: Return code will be 0 on success. | ||
4042 | * | ||
4043 | * On error: -EAGAIN if there was an existing delegation. | ||
4044 | * nonzero if there is an error in other cases. | ||
4045 | * | ||
4046 | */ | ||
4047 | |||
3948 | static int nfs4_setlease(struct nfs4_delegation *dp) | 4048 | static int nfs4_setlease(struct nfs4_delegation *dp) |
3949 | { | 4049 | { |
3950 | struct nfs4_file *fp = dp->dl_stid.sc_file; | 4050 | struct nfs4_file *fp = dp->dl_stid.sc_file; |
@@ -3976,16 +4076,19 @@ static int nfs4_setlease(struct nfs4_delegation *dp) | |||
3976 | goto out_unlock; | 4076 | goto out_unlock; |
3977 | /* Race breaker */ | 4077 | /* Race breaker */ |
3978 | if (fp->fi_deleg_file) { | 4078 | if (fp->fi_deleg_file) { |
3979 | status = 0; | 4079 | status = hash_delegation_locked(dp, fp); |
3980 | ++fp->fi_delegees; | ||
3981 | hash_delegation_locked(dp, fp); | ||
3982 | goto out_unlock; | 4080 | goto out_unlock; |
3983 | } | 4081 | } |
3984 | fp->fi_deleg_file = filp; | 4082 | fp->fi_deleg_file = filp; |
3985 | fp->fi_delegees = 1; | 4083 | fp->fi_delegees = 0; |
3986 | hash_delegation_locked(dp, fp); | 4084 | status = hash_delegation_locked(dp, fp); |
3987 | spin_unlock(&fp->fi_lock); | 4085 | spin_unlock(&fp->fi_lock); |
3988 | spin_unlock(&state_lock); | 4086 | spin_unlock(&state_lock); |
4087 | if (status) { | ||
4088 | /* Should never happen, this is a new fi_deleg_file */ | ||
4089 | WARN_ON_ONCE(1); | ||
4090 | goto out_fput; | ||
4091 | } | ||
3989 | return 0; | 4092 | return 0; |
3990 | out_unlock: | 4093 | out_unlock: |
3991 | spin_unlock(&fp->fi_lock); | 4094 | spin_unlock(&fp->fi_lock); |
@@ -4005,6 +4108,15 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, | |||
4005 | if (fp->fi_had_conflict) | 4108 | if (fp->fi_had_conflict) |
4006 | return ERR_PTR(-EAGAIN); | 4109 | return ERR_PTR(-EAGAIN); |
4007 | 4110 | ||
4111 | spin_lock(&state_lock); | ||
4112 | spin_lock(&fp->fi_lock); | ||
4113 | status = nfs4_get_existing_delegation(clp, fp); | ||
4114 | spin_unlock(&fp->fi_lock); | ||
4115 | spin_unlock(&state_lock); | ||
4116 | |||
4117 | if (status) | ||
4118 | return ERR_PTR(status); | ||
4119 | |||
4008 | dp = alloc_init_deleg(clp, fh, odstate); | 4120 | dp = alloc_init_deleg(clp, fh, odstate); |
4009 | if (!dp) | 4121 | if (!dp) |
4010 | return ERR_PTR(-ENOMEM); | 4122 | return ERR_PTR(-ENOMEM); |
@@ -4023,9 +4135,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, | |||
4023 | status = -EAGAIN; | 4135 | status = -EAGAIN; |
4024 | goto out_unlock; | 4136 | goto out_unlock; |
4025 | } | 4137 | } |
4026 | ++fp->fi_delegees; | 4138 | status = hash_delegation_locked(dp, fp); |
4027 | hash_delegation_locked(dp, fp); | ||
4028 | status = 0; | ||
4029 | out_unlock: | 4139 | out_unlock: |
4030 | spin_unlock(&fp->fi_lock); | 4140 | spin_unlock(&fp->fi_lock); |
4031 | spin_unlock(&state_lock); | 4141 | spin_unlock(&state_lock); |
@@ -4160,6 +4270,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
4160 | struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; | 4270 | struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; |
4161 | struct nfs4_file *fp = NULL; | 4271 | struct nfs4_file *fp = NULL; |
4162 | struct nfs4_ol_stateid *stp = NULL; | 4272 | struct nfs4_ol_stateid *stp = NULL; |
4273 | struct nfs4_ol_stateid *swapstp = NULL; | ||
4163 | struct nfs4_delegation *dp = NULL; | 4274 | struct nfs4_delegation *dp = NULL; |
4164 | __be32 status; | 4275 | __be32 status; |
4165 | 4276 | ||
@@ -4173,7 +4284,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
4173 | status = nfs4_check_deleg(cl, open, &dp); | 4284 | status = nfs4_check_deleg(cl, open, &dp); |
4174 | if (status) | 4285 | if (status) |
4175 | goto out; | 4286 | goto out; |
4287 | spin_lock(&fp->fi_lock); | ||
4176 | stp = nfsd4_find_existing_open(fp, open); | 4288 | stp = nfsd4_find_existing_open(fp, open); |
4289 | spin_unlock(&fp->fi_lock); | ||
4177 | } else { | 4290 | } else { |
4178 | open->op_file = NULL; | 4291 | open->op_file = NULL; |
4179 | status = nfserr_bad_stateid; | 4292 | status = nfserr_bad_stateid; |
@@ -4187,15 +4300,32 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
4187 | */ | 4300 | */ |
4188 | if (stp) { | 4301 | if (stp) { |
4189 | /* Stateid was found, this is an OPEN upgrade */ | 4302 | /* Stateid was found, this is an OPEN upgrade */ |
4303 | down_read(&stp->st_rwsem); | ||
4190 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); | 4304 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
4191 | if (status) | 4305 | if (status) { |
4306 | up_read(&stp->st_rwsem); | ||
4192 | goto out; | 4307 | goto out; |
4308 | } | ||
4193 | } else { | 4309 | } else { |
4194 | stp = open->op_stp; | 4310 | stp = open->op_stp; |
4195 | open->op_stp = NULL; | 4311 | open->op_stp = NULL; |
4196 | init_open_stateid(stp, fp, open); | 4312 | swapstp = init_open_stateid(stp, fp, open); |
4313 | if (swapstp) { | ||
4314 | nfs4_put_stid(&stp->st_stid); | ||
4315 | stp = swapstp; | ||
4316 | down_read(&stp->st_rwsem); | ||
4317 | status = nfs4_upgrade_open(rqstp, fp, current_fh, | ||
4318 | stp, open); | ||
4319 | if (status) { | ||
4320 | up_read(&stp->st_rwsem); | ||
4321 | goto out; | ||
4322 | } | ||
4323 | goto upgrade_out; | ||
4324 | } | ||
4325 | down_read(&stp->st_rwsem); | ||
4197 | status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); | 4326 | status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); |
4198 | if (status) { | 4327 | if (status) { |
4328 | up_read(&stp->st_rwsem); | ||
4199 | release_open_stateid(stp); | 4329 | release_open_stateid(stp); |
4200 | goto out; | 4330 | goto out; |
4201 | } | 4331 | } |
@@ -4205,8 +4335,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
4205 | if (stp->st_clnt_odstate == open->op_odstate) | 4335 | if (stp->st_clnt_odstate == open->op_odstate) |
4206 | open->op_odstate = NULL; | 4336 | open->op_odstate = NULL; |
4207 | } | 4337 | } |
4208 | update_stateid(&stp->st_stid.sc_stateid); | 4338 | upgrade_out: |
4209 | memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 4339 | nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); |
4340 | up_read(&stp->st_rwsem); | ||
4210 | 4341 | ||
4211 | if (nfsd4_has_session(&resp->cstate)) { | 4342 | if (nfsd4_has_session(&resp->cstate)) { |
4212 | if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { | 4343 | if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { |
@@ -4819,10 +4950,13 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_ | |||
4819 | * revoked delegations are kept only for free_stateid. | 4950 | * revoked delegations are kept only for free_stateid. |
4820 | */ | 4951 | */ |
4821 | return nfserr_bad_stateid; | 4952 | return nfserr_bad_stateid; |
4953 | down_write(&stp->st_rwsem); | ||
4822 | status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); | 4954 | status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); |
4823 | if (status) | 4955 | if (status == nfs_ok) |
4824 | return status; | 4956 | status = nfs4_check_fh(current_fh, &stp->st_stid); |
4825 | return nfs4_check_fh(current_fh, &stp->st_stid); | 4957 | if (status != nfs_ok) |
4958 | up_write(&stp->st_rwsem); | ||
4959 | return status; | ||
4826 | } | 4960 | } |
4827 | 4961 | ||
4828 | /* | 4962 | /* |
@@ -4869,6 +5003,7 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs | |||
4869 | return status; | 5003 | return status; |
4870 | oo = openowner(stp->st_stateowner); | 5004 | oo = openowner(stp->st_stateowner); |
4871 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { | 5005 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { |
5006 | up_write(&stp->st_rwsem); | ||
4872 | nfs4_put_stid(&stp->st_stid); | 5007 | nfs4_put_stid(&stp->st_stid); |
4873 | return nfserr_bad_stateid; | 5008 | return nfserr_bad_stateid; |
4874 | } | 5009 | } |
@@ -4899,11 +5034,13 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4899 | goto out; | 5034 | goto out; |
4900 | oo = openowner(stp->st_stateowner); | 5035 | oo = openowner(stp->st_stateowner); |
4901 | status = nfserr_bad_stateid; | 5036 | status = nfserr_bad_stateid; |
4902 | if (oo->oo_flags & NFS4_OO_CONFIRMED) | 5037 | if (oo->oo_flags & NFS4_OO_CONFIRMED) { |
5038 | up_write(&stp->st_rwsem); | ||
4903 | goto put_stateid; | 5039 | goto put_stateid; |
5040 | } | ||
4904 | oo->oo_flags |= NFS4_OO_CONFIRMED; | 5041 | oo->oo_flags |= NFS4_OO_CONFIRMED; |
4905 | update_stateid(&stp->st_stid.sc_stateid); | 5042 | nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); |
4906 | memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 5043 | up_write(&stp->st_rwsem); |
4907 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", | 5044 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", |
4908 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); | 5045 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); |
4909 | 5046 | ||
@@ -4975,13 +5112,11 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
4975 | goto put_stateid; | 5112 | goto put_stateid; |
4976 | } | 5113 | } |
4977 | nfs4_stateid_downgrade(stp, od->od_share_access); | 5114 | nfs4_stateid_downgrade(stp, od->od_share_access); |
4978 | |||
4979 | reset_union_bmap_deny(od->od_share_deny, stp); | 5115 | reset_union_bmap_deny(od->od_share_deny, stp); |
4980 | 5116 | nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); | |
4981 | update_stateid(&stp->st_stid.sc_stateid); | ||
4982 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | ||
4983 | status = nfs_ok; | 5117 | status = nfs_ok; |
4984 | put_stateid: | 5118 | put_stateid: |
5119 | up_write(&stp->st_rwsem); | ||
4985 | nfs4_put_stid(&stp->st_stid); | 5120 | nfs4_put_stid(&stp->st_stid); |
4986 | out: | 5121 | out: |
4987 | nfsd4_bump_seqid(cstate, status); | 5122 | nfsd4_bump_seqid(cstate, status); |
@@ -5033,8 +5168,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5033 | nfsd4_bump_seqid(cstate, status); | 5168 | nfsd4_bump_seqid(cstate, status); |
5034 | if (status) | 5169 | if (status) |
5035 | goto out; | 5170 | goto out; |
5036 | update_stateid(&stp->st_stid.sc_stateid); | 5171 | nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); |
5037 | memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 5172 | up_write(&stp->st_rwsem); |
5038 | 5173 | ||
5039 | nfsd4_close_open_stateid(stp); | 5174 | nfsd4_close_open_stateid(stp); |
5040 | 5175 | ||
@@ -5260,6 +5395,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, | |||
5260 | stp->st_access_bmap = 0; | 5395 | stp->st_access_bmap = 0; |
5261 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 5396 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
5262 | stp->st_openstp = open_stp; | 5397 | stp->st_openstp = open_stp; |
5398 | init_rwsem(&stp->st_rwsem); | ||
5263 | list_add(&stp->st_locks, &open_stp->st_locks); | 5399 | list_add(&stp->st_locks, &open_stp->st_locks); |
5264 | list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); | 5400 | list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); |
5265 | spin_lock(&fp->fi_lock); | 5401 | spin_lock(&fp->fi_lock); |
@@ -5428,6 +5564,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5428 | &open_stp, nn); | 5564 | &open_stp, nn); |
5429 | if (status) | 5565 | if (status) |
5430 | goto out; | 5566 | goto out; |
5567 | up_write(&open_stp->st_rwsem); | ||
5431 | open_sop = openowner(open_stp->st_stateowner); | 5568 | open_sop = openowner(open_stp->st_stateowner); |
5432 | status = nfserr_bad_stateid; | 5569 | status = nfserr_bad_stateid; |
5433 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, | 5570 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, |
@@ -5435,6 +5572,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5435 | goto out; | 5572 | goto out; |
5436 | status = lookup_or_create_lock_state(cstate, open_stp, lock, | 5573 | status = lookup_or_create_lock_state(cstate, open_stp, lock, |
5437 | &lock_stp, &new); | 5574 | &lock_stp, &new); |
5575 | if (status == nfs_ok) | ||
5576 | down_write(&lock_stp->st_rwsem); | ||
5438 | } else { | 5577 | } else { |
5439 | status = nfs4_preprocess_seqid_op(cstate, | 5578 | status = nfs4_preprocess_seqid_op(cstate, |
5440 | lock->lk_old_lock_seqid, | 5579 | lock->lk_old_lock_seqid, |
@@ -5512,9 +5651,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5512 | err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); | 5651 | err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); |
5513 | switch (-err) { | 5652 | switch (-err) { |
5514 | case 0: /* success! */ | 5653 | case 0: /* success! */ |
5515 | update_stateid(&lock_stp->st_stid.sc_stateid); | 5654 | nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); |
5516 | memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, | ||
5517 | sizeof(stateid_t)); | ||
5518 | status = 0; | 5655 | status = 0; |
5519 | break; | 5656 | break; |
5520 | case (EAGAIN): /* conflock holds conflicting lock */ | 5657 | case (EAGAIN): /* conflock holds conflicting lock */ |
@@ -5540,6 +5677,8 @@ out: | |||
5540 | seqid_mutating_err(ntohl(status))) | 5677 | seqid_mutating_err(ntohl(status))) |
5541 | lock_sop->lo_owner.so_seqid++; | 5678 | lock_sop->lo_owner.so_seqid++; |
5542 | 5679 | ||
5680 | up_write(&lock_stp->st_rwsem); | ||
5681 | |||
5543 | /* | 5682 | /* |
5544 | * If this is a new, never-before-used stateid, and we are | 5683 | * If this is a new, never-before-used stateid, and we are |
5545 | * returning an error, then just go ahead and release it. | 5684 | * returning an error, then just go ahead and release it. |
@@ -5704,11 +5843,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5704 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); | 5843 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); |
5705 | goto out_nfserr; | 5844 | goto out_nfserr; |
5706 | } | 5845 | } |
5707 | update_stateid(&stp->st_stid.sc_stateid); | 5846 | nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); |
5708 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | ||
5709 | fput: | 5847 | fput: |
5710 | fput(filp); | 5848 | fput(filp); |
5711 | put_stateid: | 5849 | put_stateid: |
5850 | up_write(&stp->st_rwsem); | ||
5712 | nfs4_put_stid(&stp->st_stid); | 5851 | nfs4_put_stid(&stp->st_stid); |
5713 | out: | 5852 | out: |
5714 | nfsd4_bump_seqid(cstate, status); | 5853 | nfsd4_bump_seqid(cstate, status); |
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 46ec934f5dee..54cde9a5864e 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c | |||
@@ -63,7 +63,6 @@ static unsigned int longest_chain; | |||
63 | static unsigned int longest_chain_cachesize; | 63 | static unsigned int longest_chain_cachesize; |
64 | 64 | ||
65 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); | 65 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); |
66 | static void cache_cleaner_func(struct work_struct *unused); | ||
67 | static unsigned long nfsd_reply_cache_count(struct shrinker *shrink, | 66 | static unsigned long nfsd_reply_cache_count(struct shrinker *shrink, |
68 | struct shrink_control *sc); | 67 | struct shrink_control *sc); |
69 | static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink, | 68 | static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink, |
@@ -76,13 +75,6 @@ static struct shrinker nfsd_reply_cache_shrinker = { | |||
76 | }; | 75 | }; |
77 | 76 | ||
78 | /* | 77 | /* |
79 | * locking for the reply cache: | ||
80 | * A cache entry is "single use" if c_state == RC_INPROG | ||
81 | * Otherwise, it when accessing _prev or _next, the lock must be held. | ||
82 | */ | ||
83 | static DECLARE_DELAYED_WORK(cache_cleaner, cache_cleaner_func); | ||
84 | |||
85 | /* | ||
86 | * Put a cap on the size of the DRC based on the amount of available | 78 | * Put a cap on the size of the DRC based on the amount of available |
87 | * low memory in the machine. | 79 | * low memory in the machine. |
88 | * | 80 | * |
@@ -203,7 +195,6 @@ void nfsd_reply_cache_shutdown(void) | |||
203 | unsigned int i; | 195 | unsigned int i; |
204 | 196 | ||
205 | unregister_shrinker(&nfsd_reply_cache_shrinker); | 197 | unregister_shrinker(&nfsd_reply_cache_shrinker); |
206 | cancel_delayed_work_sync(&cache_cleaner); | ||
207 | 198 | ||
208 | for (i = 0; i < drc_hashsize; i++) { | 199 | for (i = 0; i < drc_hashsize; i++) { |
209 | struct list_head *head = &drc_hashtbl[i].lru_head; | 200 | struct list_head *head = &drc_hashtbl[i].lru_head; |
@@ -217,10 +208,8 @@ void nfsd_reply_cache_shutdown(void) | |||
217 | drc_hashtbl = NULL; | 208 | drc_hashtbl = NULL; |
218 | drc_hashsize = 0; | 209 | drc_hashsize = 0; |
219 | 210 | ||
220 | if (drc_slab) { | 211 | kmem_cache_destroy(drc_slab); |
221 | kmem_cache_destroy(drc_slab); | 212 | drc_slab = NULL; |
222 | drc_slab = NULL; | ||
223 | } | ||
224 | } | 213 | } |
225 | 214 | ||
226 | /* | 215 | /* |
@@ -232,7 +221,6 @@ lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp) | |||
232 | { | 221 | { |
233 | rp->c_timestamp = jiffies; | 222 | rp->c_timestamp = jiffies; |
234 | list_move_tail(&rp->c_lru, &b->lru_head); | 223 | list_move_tail(&rp->c_lru, &b->lru_head); |
235 | schedule_delayed_work(&cache_cleaner, RC_EXPIRE); | ||
236 | } | 224 | } |
237 | 225 | ||
238 | static long | 226 | static long |
@@ -266,7 +254,6 @@ prune_cache_entries(void) | |||
266 | { | 254 | { |
267 | unsigned int i; | 255 | unsigned int i; |
268 | long freed = 0; | 256 | long freed = 0; |
269 | bool cancel = true; | ||
270 | 257 | ||
271 | for (i = 0; i < drc_hashsize; i++) { | 258 | for (i = 0; i < drc_hashsize; i++) { |
272 | struct nfsd_drc_bucket *b = &drc_hashtbl[i]; | 259 | struct nfsd_drc_bucket *b = &drc_hashtbl[i]; |
@@ -275,26 +262,11 @@ prune_cache_entries(void) | |||
275 | continue; | 262 | continue; |
276 | spin_lock(&b->cache_lock); | 263 | spin_lock(&b->cache_lock); |
277 | freed += prune_bucket(b); | 264 | freed += prune_bucket(b); |
278 | if (!list_empty(&b->lru_head)) | ||
279 | cancel = false; | ||
280 | spin_unlock(&b->cache_lock); | 265 | spin_unlock(&b->cache_lock); |
281 | } | 266 | } |
282 | |||
283 | /* | ||
284 | * Conditionally rearm the job to run in RC_EXPIRE since we just | ||
285 | * ran the pruner. | ||
286 | */ | ||
287 | if (!cancel) | ||
288 | mod_delayed_work(system_wq, &cache_cleaner, RC_EXPIRE); | ||
289 | return freed; | 267 | return freed; |
290 | } | 268 | } |
291 | 269 | ||
292 | static void | ||
293 | cache_cleaner_func(struct work_struct *unused) | ||
294 | { | ||
295 | prune_cache_entries(); | ||
296 | } | ||
297 | |||
298 | static unsigned long | 270 | static unsigned long |
299 | nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc) | 271 | nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc) |
300 | { | 272 | { |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 350041a40fe5..c1681ce894c5 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -631,10 +631,7 @@ fh_put(struct svc_fh *fhp) | |||
631 | fh_unlock(fhp); | 631 | fh_unlock(fhp); |
632 | fhp->fh_dentry = NULL; | 632 | fhp->fh_dentry = NULL; |
633 | dput(dentry); | 633 | dput(dentry); |
634 | #ifdef CONFIG_NFSD_V3 | 634 | fh_clear_wcc(fhp); |
635 | fhp->fh_pre_saved = 0; | ||
636 | fhp->fh_post_saved = 0; | ||
637 | #endif | ||
638 | } | 635 | } |
639 | fh_drop_write(fhp); | 636 | fh_drop_write(fhp); |
640 | if (exp) { | 637 | if (exp) { |
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 1e90dad4926b..2087bae17582 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h | |||
@@ -26,16 +26,16 @@ static inline ino_t u32_to_ino_t(__u32 uino) | |||
26 | */ | 26 | */ |
27 | typedef struct svc_fh { | 27 | typedef struct svc_fh { |
28 | struct knfsd_fh fh_handle; /* FH data */ | 28 | struct knfsd_fh fh_handle; /* FH data */ |
29 | int fh_maxsize; /* max size for fh_handle */ | ||
29 | struct dentry * fh_dentry; /* validated dentry */ | 30 | struct dentry * fh_dentry; /* validated dentry */ |
30 | struct svc_export * fh_export; /* export pointer */ | 31 | struct svc_export * fh_export; /* export pointer */ |
31 | int fh_maxsize; /* max size for fh_handle */ | ||
32 | 32 | ||
33 | unsigned char fh_locked; /* inode locked by us */ | 33 | bool fh_locked; /* inode locked by us */ |
34 | unsigned char fh_want_write; /* remount protection taken */ | 34 | bool fh_want_write; /* remount protection taken */ |
35 | 35 | ||
36 | #ifdef CONFIG_NFSD_V3 | 36 | #ifdef CONFIG_NFSD_V3 |
37 | unsigned char fh_post_saved; /* post-op attrs saved */ | 37 | bool fh_post_saved; /* post-op attrs saved */ |
38 | unsigned char fh_pre_saved; /* pre-op attrs saved */ | 38 | bool fh_pre_saved; /* pre-op attrs saved */ |
39 | 39 | ||
40 | /* Pre-op attributes saved during fh_lock */ | 40 | /* Pre-op attributes saved during fh_lock */ |
41 | __u64 fh_pre_size; /* size before operation */ | 41 | __u64 fh_pre_size; /* size before operation */ |
@@ -213,8 +213,8 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) | |||
213 | static inline void | 213 | static inline void |
214 | fh_clear_wcc(struct svc_fh *fhp) | 214 | fh_clear_wcc(struct svc_fh *fhp) |
215 | { | 215 | { |
216 | fhp->fh_post_saved = 0; | 216 | fhp->fh_post_saved = false; |
217 | fhp->fh_pre_saved = 0; | 217 | fhp->fh_pre_saved = false; |
218 | } | 218 | } |
219 | 219 | ||
220 | /* | 220 | /* |
@@ -231,7 +231,7 @@ fill_pre_wcc(struct svc_fh *fhp) | |||
231 | fhp->fh_pre_ctime = inode->i_ctime; | 231 | fhp->fh_pre_ctime = inode->i_ctime; |
232 | fhp->fh_pre_size = inode->i_size; | 232 | fhp->fh_pre_size = inode->i_size; |
233 | fhp->fh_pre_change = inode->i_version; | 233 | fhp->fh_pre_change = inode->i_version; |
234 | fhp->fh_pre_saved = 1; | 234 | fhp->fh_pre_saved = true; |
235 | } | 235 | } |
236 | } | 236 | } |
237 | 237 | ||
@@ -267,7 +267,7 @@ fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) | |||
267 | inode = d_inode(dentry); | 267 | inode = d_inode(dentry); |
268 | mutex_lock_nested(&inode->i_mutex, subclass); | 268 | mutex_lock_nested(&inode->i_mutex, subclass); |
269 | fill_pre_wcc(fhp); | 269 | fill_pre_wcc(fhp); |
270 | fhp->fh_locked = 1; | 270 | fhp->fh_locked = true; |
271 | } | 271 | } |
272 | 272 | ||
273 | static inline void | 273 | static inline void |
@@ -285,7 +285,7 @@ fh_unlock(struct svc_fh *fhp) | |||
285 | if (fhp->fh_locked) { | 285 | if (fhp->fh_locked) { |
286 | fill_post_wcc(fhp); | 286 | fill_post_wcc(fhp); |
287 | mutex_unlock(&d_inode(fhp->fh_dentry)->i_mutex); | 287 | mutex_unlock(&d_inode(fhp->fh_dentry)->i_mutex); |
288 | fhp->fh_locked = 0; | 288 | fhp->fh_locked = false; |
289 | } | 289 | } |
290 | } | 290 | } |
291 | 291 | ||
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 583ffc13cae2..77fdf4de91ba 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -84,7 +84,7 @@ struct nfsd4_callback_ops { | |||
84 | * fields that are of general use to any stateid. | 84 | * fields that are of general use to any stateid. |
85 | */ | 85 | */ |
86 | struct nfs4_stid { | 86 | struct nfs4_stid { |
87 | atomic_t sc_count; | 87 | atomic_t sc_count; |
88 | #define NFS4_OPEN_STID 1 | 88 | #define NFS4_OPEN_STID 1 |
89 | #define NFS4_LOCK_STID 2 | 89 | #define NFS4_LOCK_STID 2 |
90 | #define NFS4_DELEG_STID 4 | 90 | #define NFS4_DELEG_STID 4 |
@@ -94,11 +94,12 @@ struct nfs4_stid { | |||
94 | #define NFS4_REVOKED_DELEG_STID 16 | 94 | #define NFS4_REVOKED_DELEG_STID 16 |
95 | #define NFS4_CLOSED_DELEG_STID 32 | 95 | #define NFS4_CLOSED_DELEG_STID 32 |
96 | #define NFS4_LAYOUT_STID 64 | 96 | #define NFS4_LAYOUT_STID 64 |
97 | unsigned char sc_type; | 97 | unsigned char sc_type; |
98 | stateid_t sc_stateid; | 98 | stateid_t sc_stateid; |
99 | struct nfs4_client *sc_client; | 99 | spinlock_t sc_lock; |
100 | struct nfs4_file *sc_file; | 100 | struct nfs4_client *sc_client; |
101 | void (*sc_free)(struct nfs4_stid *); | 101 | struct nfs4_file *sc_file; |
102 | void (*sc_free)(struct nfs4_stid *); | ||
102 | }; | 103 | }; |
103 | 104 | ||
104 | /* | 105 | /* |
@@ -364,15 +365,6 @@ struct nfs4_client_reclaim { | |||
364 | char cr_recdir[HEXDIR_LEN]; /* recover dir */ | 365 | char cr_recdir[HEXDIR_LEN]; /* recover dir */ |
365 | }; | 366 | }; |
366 | 367 | ||
367 | static inline void | ||
368 | update_stateid(stateid_t *stateid) | ||
369 | { | ||
370 | stateid->si_generation++; | ||
371 | /* Wraparound recommendation from 3530bis-13 9.1.3.2: */ | ||
372 | if (stateid->si_generation == 0) | ||
373 | stateid->si_generation = 1; | ||
374 | } | ||
375 | |||
376 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: | 368 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: |
377 | * The OPEN response, typically the largest, requires | 369 | * The OPEN response, typically the largest, requires |
378 | * 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) + 8(verifier) + | 370 | * 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) + 8(verifier) + |
@@ -534,15 +526,16 @@ struct nfs4_file { | |||
534 | * Better suggestions welcome. | 526 | * Better suggestions welcome. |
535 | */ | 527 | */ |
536 | struct nfs4_ol_stateid { | 528 | struct nfs4_ol_stateid { |
537 | struct nfs4_stid st_stid; /* must be first field */ | 529 | struct nfs4_stid st_stid; |
538 | struct list_head st_perfile; | 530 | struct list_head st_perfile; |
539 | struct list_head st_perstateowner; | 531 | struct list_head st_perstateowner; |
540 | struct list_head st_locks; | 532 | struct list_head st_locks; |
541 | struct nfs4_stateowner * st_stateowner; | 533 | struct nfs4_stateowner *st_stateowner; |
542 | struct nfs4_clnt_odstate * st_clnt_odstate; | 534 | struct nfs4_clnt_odstate *st_clnt_odstate; |
543 | unsigned char st_access_bmap; | 535 | unsigned char st_access_bmap; |
544 | unsigned char st_deny_bmap; | 536 | unsigned char st_deny_bmap; |
545 | struct nfs4_ol_stateid * st_openstp; | 537 | struct nfs4_ol_stateid *st_openstp; |
538 | struct rw_semaphore st_rwsem; | ||
546 | }; | 539 | }; |
547 | 540 | ||
548 | static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) | 541 | static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) |
@@ -561,6 +554,7 @@ struct nfs4_layout_stateid { | |||
561 | struct nfsd4_callback ls_recall; | 554 | struct nfsd4_callback ls_recall; |
562 | stateid_t ls_recall_sid; | 555 | stateid_t ls_recall_sid; |
563 | bool ls_recalled; | 556 | bool ls_recalled; |
557 | struct mutex ls_mutex; | ||
564 | }; | 558 | }; |
565 | 559 | ||
566 | static inline struct nfs4_layout_stateid *layoutstateid(struct nfs4_stid *s) | 560 | static inline struct nfs4_layout_stateid *layoutstateid(struct nfs4_stid *s) |
@@ -593,6 +587,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | |||
593 | struct kmem_cache *slab); | 587 | struct kmem_cache *slab); |
594 | void nfs4_unhash_stid(struct nfs4_stid *s); | 588 | void nfs4_unhash_stid(struct nfs4_stid *s); |
595 | void nfs4_put_stid(struct nfs4_stid *s); | 589 | void nfs4_put_stid(struct nfs4_stid *s); |
590 | void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); | ||
596 | void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); | 591 | void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); |
597 | extern void nfs4_release_reclaim(struct nfsd_net *); | 592 | extern void nfs4_release_reclaim(struct nfsd_net *); |
598 | extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, | 593 | extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, |
diff --git a/fs/nfsd/trace.c b/fs/nfsd/trace.c index 82f89070594c..90967466a1e5 100644 --- a/fs/nfsd/trace.c +++ b/fs/nfsd/trace.c | |||
@@ -1,5 +1,3 @@ | |||
1 | 1 | ||
2 | #include "state.h" | ||
3 | |||
4 | #define CREATE_TRACE_POINTS | 2 | #define CREATE_TRACE_POINTS |
5 | #include "trace.h" | 3 | #include "trace.h" |
diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index c668520c344b..0befe762762b 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h | |||
@@ -9,6 +9,8 @@ | |||
9 | 9 | ||
10 | #include <linux/tracepoint.h> | 10 | #include <linux/tracepoint.h> |
11 | 11 | ||
12 | #include "state.h" | ||
13 | |||
12 | DECLARE_EVENT_CLASS(nfsd_stateid_class, | 14 | DECLARE_EVENT_CLASS(nfsd_stateid_class, |
13 | TP_PROTO(stateid_t *stp), | 15 | TP_PROTO(stateid_t *stp), |
14 | TP_ARGS(stp), | 16 | TP_ARGS(stp), |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 45c04979e7b3..994d66fbb446 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1631,7 +1631,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1631 | /* cannot use fh_lock as we need deadlock protective ordering | 1631 | /* cannot use fh_lock as we need deadlock protective ordering |
1632 | * so do it by hand */ | 1632 | * so do it by hand */ |
1633 | trap = lock_rename(tdentry, fdentry); | 1633 | trap = lock_rename(tdentry, fdentry); |
1634 | ffhp->fh_locked = tfhp->fh_locked = 1; | 1634 | ffhp->fh_locked = tfhp->fh_locked = true; |
1635 | fill_pre_wcc(ffhp); | 1635 | fill_pre_wcc(ffhp); |
1636 | fill_pre_wcc(tfhp); | 1636 | fill_pre_wcc(tfhp); |
1637 | 1637 | ||
@@ -1681,7 +1681,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1681 | fill_post_wcc(ffhp); | 1681 | fill_post_wcc(ffhp); |
1682 | fill_post_wcc(tfhp); | 1682 | fill_post_wcc(tfhp); |
1683 | unlock_rename(tdentry, fdentry); | 1683 | unlock_rename(tdentry, fdentry); |
1684 | ffhp->fh_locked = tfhp->fh_locked = 0; | 1684 | ffhp->fh_locked = tfhp->fh_locked = false; |
1685 | fh_drop_write(ffhp); | 1685 | fh_drop_write(ffhp); |
1686 | 1686 | ||
1687 | out: | 1687 | out: |
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index fee2451ae248..fcfc48cbe136 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -112,14 +112,14 @@ static inline int fh_want_write(struct svc_fh *fh) | |||
112 | int ret = mnt_want_write(fh->fh_export->ex_path.mnt); | 112 | int ret = mnt_want_write(fh->fh_export->ex_path.mnt); |
113 | 113 | ||
114 | if (!ret) | 114 | if (!ret) |
115 | fh->fh_want_write = 1; | 115 | fh->fh_want_write = true; |
116 | return ret; | 116 | return ret; |
117 | } | 117 | } |
118 | 118 | ||
119 | static inline void fh_drop_write(struct svc_fh *fh) | 119 | static inline void fh_drop_write(struct svc_fh *fh) |
120 | { | 120 | { |
121 | if (fh->fh_want_write) { | 121 | if (fh->fh_want_write) { |
122 | fh->fh_want_write = 0; | 122 | fh->fh_want_write = false; |
123 | mnt_drop_write(fh->fh_export->ex_path.mnt); | 123 | mnt_drop_write(fh->fh_export->ex_path.mnt); |
124 | } | 124 | } |
125 | } | 125 | } |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 9f991007a578..ce7362c88b48 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -632,7 +632,7 @@ static inline void | |||
632 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) | 632 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) |
633 | { | 633 | { |
634 | BUG_ON(!fhp->fh_pre_saved); | 634 | BUG_ON(!fhp->fh_pre_saved); |
635 | cinfo->atomic = fhp->fh_post_saved; | 635 | cinfo->atomic = (u32)fhp->fh_post_saved; |
636 | cinfo->change_supported = IS_I_VERSION(d_inode(fhp->fh_dentry)); | 636 | cinfo->change_supported = IS_I_VERSION(d_inode(fhp->fh_dentry)); |
637 | 637 | ||
638 | cinfo->before_change = fhp->fh_pre_change; | 638 | cinfo->before_change = fhp->fh_pre_change; |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index ff82a32871b5..c15373894a42 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -68,6 +68,7 @@ struct nlm_host { | |||
68 | struct nsm_handle *h_nsmhandle; /* NSM status handle */ | 68 | struct nsm_handle *h_nsmhandle; /* NSM status handle */ |
69 | char *h_addrbuf; /* address eyecatcher */ | 69 | char *h_addrbuf; /* address eyecatcher */ |
70 | struct net *net; /* host net */ | 70 | struct net *net; /* host net */ |
71 | char nodename[UNX_MAXNODENAME + 1]; | ||
71 | }; | 72 | }; |
72 | 73 | ||
73 | /* | 74 | /* |
@@ -235,7 +236,8 @@ void nlm_rebind_host(struct nlm_host *); | |||
235 | struct nlm_host * nlm_get_host(struct nlm_host *); | 236 | struct nlm_host * nlm_get_host(struct nlm_host *); |
236 | void nlm_shutdown_hosts(void); | 237 | void nlm_shutdown_hosts(void); |
237 | void nlm_shutdown_hosts_net(struct net *net); | 238 | void nlm_shutdown_hosts_net(struct net *net); |
238 | void nlm_host_rebooted(const struct nlm_reboot *); | 239 | void nlm_host_rebooted(const struct net *net, |
240 | const struct nlm_reboot *); | ||
239 | 241 | ||
240 | /* | 242 | /* |
241 | * Host monitoring | 243 | * Host monitoring |
@@ -243,11 +245,13 @@ void nlm_host_rebooted(const struct nlm_reboot *); | |||
243 | int nsm_monitor(const struct nlm_host *host); | 245 | int nsm_monitor(const struct nlm_host *host); |
244 | void nsm_unmonitor(const struct nlm_host *host); | 246 | void nsm_unmonitor(const struct nlm_host *host); |
245 | 247 | ||
246 | struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, | 248 | struct nsm_handle *nsm_get_handle(const struct net *net, |
249 | const struct sockaddr *sap, | ||
247 | const size_t salen, | 250 | const size_t salen, |
248 | const char *hostname, | 251 | const char *hostname, |
249 | const size_t hostname_len); | 252 | const size_t hostname_len); |
250 | struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info); | 253 | struct nsm_handle *nsm_reboot_lookup(const struct net *net, |
254 | const struct nlm_reboot *info); | ||
251 | void nsm_release(struct nsm_handle *nsm); | 255 | void nsm_release(struct nsm_handle *nsm); |
252 | 256 | ||
253 | /* | 257 | /* |
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 03d3b4c92d9f..ed03c9f7f908 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h | |||
@@ -48,8 +48,10 @@ | |||
48 | struct cache_head { | 48 | struct cache_head { |
49 | struct hlist_node cache_list; | 49 | struct hlist_node cache_list; |
50 | time_t expiry_time; /* After time time, don't use the data */ | 50 | time_t expiry_time; /* After time time, don't use the data */ |
51 | time_t last_refresh; /* If CACHE_PENDING, this is when upcall | 51 | time_t last_refresh; /* If CACHE_PENDING, this is when upcall was |
52 | * was sent, else this is when update was received | 52 | * sent, else this is when update was |
53 | * received, though it is alway set to | ||
54 | * be *after* ->flush_time. | ||
53 | */ | 55 | */ |
54 | struct kref ref; | 56 | struct kref ref; |
55 | unsigned long flags; | 57 | unsigned long flags; |
@@ -105,8 +107,12 @@ struct cache_detail { | |||
105 | /* fields below this comment are for internal use | 107 | /* fields below this comment are for internal use |
106 | * and should not be touched by cache owners | 108 | * and should not be touched by cache owners |
107 | */ | 109 | */ |
108 | time_t flush_time; /* flush all cache items with last_refresh | 110 | time_t flush_time; /* flush all cache items with |
109 | * earlier than this */ | 111 | * last_refresh at or earlier |
112 | * than this. last_refresh | ||
113 | * is never set at or earlier | ||
114 | * than this. | ||
115 | */ | ||
110 | struct list_head others; | 116 | struct list_head others; |
111 | time_t nextcheck; | 117 | time_t nextcheck; |
112 | int entries; | 118 | int entries; |
@@ -203,7 +209,7 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd) | |||
203 | static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) | 209 | static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) |
204 | { | 210 | { |
205 | return (h->expiry_time < seconds_since_boot()) || | 211 | return (h->expiry_time < seconds_since_boot()) || |
206 | (detail->flush_time > h->last_refresh); | 212 | (detail->flush_time >= h->last_refresh); |
207 | } | 213 | } |
208 | 214 | ||
209 | extern int cache_check(struct cache_detail *detail, | 215 | extern int cache_check(struct cache_detail *detail, |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index dace13d7638e..799e65b944b9 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1411,17 +1411,16 @@ gss_key_timeout(struct rpc_cred *rc) | |||
1411 | { | 1411 | { |
1412 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 1412 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
1413 | struct gss_cl_ctx *ctx; | 1413 | struct gss_cl_ctx *ctx; |
1414 | unsigned long now = jiffies; | 1414 | unsigned long timeout = jiffies + (gss_key_expire_timeo * HZ); |
1415 | unsigned long expire; | 1415 | int ret = 0; |
1416 | 1416 | ||
1417 | rcu_read_lock(); | 1417 | rcu_read_lock(); |
1418 | ctx = rcu_dereference(gss_cred->gc_ctx); | 1418 | ctx = rcu_dereference(gss_cred->gc_ctx); |
1419 | if (ctx) | 1419 | if (!ctx || time_after(timeout, ctx->gc_expiry)) |
1420 | expire = ctx->gc_expiry - (gss_key_expire_timeo * HZ); | 1420 | ret = -EACCES; |
1421 | rcu_read_unlock(); | 1421 | rcu_read_unlock(); |
1422 | if (!ctx || time_after(now, expire)) | 1422 | |
1423 | return -EACCES; | 1423 | return ret; |
1424 | return 0; | ||
1425 | } | 1424 | } |
1426 | 1425 | ||
1427 | static int | 1426 | static int |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 4a2340a54401..5e4f815c2b34 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -41,13 +41,16 @@ | |||
41 | static bool cache_defer_req(struct cache_req *req, struct cache_head *item); | 41 | static bool cache_defer_req(struct cache_req *req, struct cache_head *item); |
42 | static void cache_revisit_request(struct cache_head *item); | 42 | static void cache_revisit_request(struct cache_head *item); |
43 | 43 | ||
44 | static void cache_init(struct cache_head *h) | 44 | static void cache_init(struct cache_head *h, struct cache_detail *detail) |
45 | { | 45 | { |
46 | time_t now = seconds_since_boot(); | 46 | time_t now = seconds_since_boot(); |
47 | INIT_HLIST_NODE(&h->cache_list); | 47 | INIT_HLIST_NODE(&h->cache_list); |
48 | h->flags = 0; | 48 | h->flags = 0; |
49 | kref_init(&h->ref); | 49 | kref_init(&h->ref); |
50 | h->expiry_time = now + CACHE_NEW_EXPIRY; | 50 | h->expiry_time = now + CACHE_NEW_EXPIRY; |
51 | if (now <= detail->flush_time) | ||
52 | /* ensure it isn't already expired */ | ||
53 | now = detail->flush_time + 1; | ||
51 | h->last_refresh = now; | 54 | h->last_refresh = now; |
52 | } | 55 | } |
53 | 56 | ||
@@ -81,7 +84,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | |||
81 | * we might get lose if we need to | 84 | * we might get lose if we need to |
82 | * cache_put it soon. | 85 | * cache_put it soon. |
83 | */ | 86 | */ |
84 | cache_init(new); | 87 | cache_init(new, detail); |
85 | detail->init(new, key); | 88 | detail->init(new, key); |
86 | 89 | ||
87 | write_lock(&detail->hash_lock); | 90 | write_lock(&detail->hash_lock); |
@@ -116,10 +119,15 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); | |||
116 | 119 | ||
117 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); | 120 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); |
118 | 121 | ||
119 | static void cache_fresh_locked(struct cache_head *head, time_t expiry) | 122 | static void cache_fresh_locked(struct cache_head *head, time_t expiry, |
123 | struct cache_detail *detail) | ||
120 | { | 124 | { |
125 | time_t now = seconds_since_boot(); | ||
126 | if (now <= detail->flush_time) | ||
127 | /* ensure it isn't immediately treated as expired */ | ||
128 | now = detail->flush_time + 1; | ||
121 | head->expiry_time = expiry; | 129 | head->expiry_time = expiry; |
122 | head->last_refresh = seconds_since_boot(); | 130 | head->last_refresh = now; |
123 | smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */ | 131 | smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */ |
124 | set_bit(CACHE_VALID, &head->flags); | 132 | set_bit(CACHE_VALID, &head->flags); |
125 | } | 133 | } |
@@ -149,7 +157,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | |||
149 | set_bit(CACHE_NEGATIVE, &old->flags); | 157 | set_bit(CACHE_NEGATIVE, &old->flags); |
150 | else | 158 | else |
151 | detail->update(old, new); | 159 | detail->update(old, new); |
152 | cache_fresh_locked(old, new->expiry_time); | 160 | cache_fresh_locked(old, new->expiry_time, detail); |
153 | write_unlock(&detail->hash_lock); | 161 | write_unlock(&detail->hash_lock); |
154 | cache_fresh_unlocked(old, detail); | 162 | cache_fresh_unlocked(old, detail); |
155 | return old; | 163 | return old; |
@@ -162,7 +170,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | |||
162 | cache_put(old, detail); | 170 | cache_put(old, detail); |
163 | return NULL; | 171 | return NULL; |
164 | } | 172 | } |
165 | cache_init(tmp); | 173 | cache_init(tmp, detail); |
166 | detail->init(tmp, old); | 174 | detail->init(tmp, old); |
167 | 175 | ||
168 | write_lock(&detail->hash_lock); | 176 | write_lock(&detail->hash_lock); |
@@ -173,8 +181,8 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | |||
173 | hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]); | 181 | hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]); |
174 | detail->entries++; | 182 | detail->entries++; |
175 | cache_get(tmp); | 183 | cache_get(tmp); |
176 | cache_fresh_locked(tmp, new->expiry_time); | 184 | cache_fresh_locked(tmp, new->expiry_time, detail); |
177 | cache_fresh_locked(old, 0); | 185 | cache_fresh_locked(old, 0, detail); |
178 | write_unlock(&detail->hash_lock); | 186 | write_unlock(&detail->hash_lock); |
179 | cache_fresh_unlocked(tmp, detail); | 187 | cache_fresh_unlocked(tmp, detail); |
180 | cache_fresh_unlocked(old, detail); | 188 | cache_fresh_unlocked(old, detail); |
@@ -219,7 +227,8 @@ static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h | |||
219 | rv = cache_is_valid(h); | 227 | rv = cache_is_valid(h); |
220 | if (rv == -EAGAIN) { | 228 | if (rv == -EAGAIN) { |
221 | set_bit(CACHE_NEGATIVE, &h->flags); | 229 | set_bit(CACHE_NEGATIVE, &h->flags); |
222 | cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); | 230 | cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY, |
231 | detail); | ||
223 | rv = -ENOENT; | 232 | rv = -ENOENT; |
224 | } | 233 | } |
225 | write_unlock(&detail->hash_lock); | 234 | write_unlock(&detail->hash_lock); |
@@ -487,10 +496,13 @@ EXPORT_SYMBOL_GPL(cache_flush); | |||
487 | 496 | ||
488 | void cache_purge(struct cache_detail *detail) | 497 | void cache_purge(struct cache_detail *detail) |
489 | { | 498 | { |
490 | detail->flush_time = LONG_MAX; | 499 | time_t now = seconds_since_boot(); |
500 | if (detail->flush_time >= now) | ||
501 | now = detail->flush_time + 1; | ||
502 | /* 'now' is the maximum value any 'last_refresh' can have */ | ||
503 | detail->flush_time = now; | ||
491 | detail->nextcheck = seconds_since_boot(); | 504 | detail->nextcheck = seconds_since_boot(); |
492 | cache_flush(); | 505 | cache_flush(); |
493 | detail->flush_time = 1; | ||
494 | } | 506 | } |
495 | EXPORT_SYMBOL_GPL(cache_purge); | 507 | EXPORT_SYMBOL_GPL(cache_purge); |
496 | 508 | ||
@@ -1436,6 +1448,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf, | |||
1436 | { | 1448 | { |
1437 | char tbuf[20]; | 1449 | char tbuf[20]; |
1438 | char *bp, *ep; | 1450 | char *bp, *ep; |
1451 | time_t then, now; | ||
1439 | 1452 | ||
1440 | if (*ppos || count > sizeof(tbuf)-1) | 1453 | if (*ppos || count > sizeof(tbuf)-1) |
1441 | return -EINVAL; | 1454 | return -EINVAL; |
@@ -1447,8 +1460,22 @@ static ssize_t write_flush(struct file *file, const char __user *buf, | |||
1447 | return -EINVAL; | 1460 | return -EINVAL; |
1448 | 1461 | ||
1449 | bp = tbuf; | 1462 | bp = tbuf; |
1450 | cd->flush_time = get_expiry(&bp); | 1463 | then = get_expiry(&bp); |
1451 | cd->nextcheck = seconds_since_boot(); | 1464 | now = seconds_since_boot(); |
1465 | cd->nextcheck = now; | ||
1466 | /* Can only set flush_time to 1 second beyond "now", or | ||
1467 | * possibly 1 second beyond flushtime. This is because | ||
1468 | * flush_time never goes backwards so it mustn't get too far | ||
1469 | * ahead of time. | ||
1470 | */ | ||
1471 | if (then >= now) { | ||
1472 | /* Want to flush everything, so behave like cache_purge() */ | ||
1473 | if (cd->flush_time >= now) | ||
1474 | now = cd->flush_time + 1; | ||
1475 | then = now; | ||
1476 | } | ||
1477 | |||
1478 | cd->flush_time = then; | ||
1452 | cache_flush(); | 1479 | cache_flush(); |
1453 | 1480 | ||
1454 | *ppos += count; | 1481 | *ppos += count; |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 0c8120229a03..1413cdcc131c 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -181,7 +181,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr, | |||
181 | struct page **ppage = xdr->pages; | 181 | struct page **ppage = xdr->pages; |
182 | size_t base = xdr->page_base; | 182 | size_t base = xdr->page_base; |
183 | unsigned int pglen = xdr->page_len; | 183 | unsigned int pglen = xdr->page_len; |
184 | unsigned int flags = MSG_MORE; | 184 | unsigned int flags = MSG_MORE | MSG_SENDPAGE_NOTLAST; |
185 | int slen; | 185 | int slen; |
186 | int len = 0; | 186 | int len = 0; |
187 | 187 | ||
@@ -399,6 +399,31 @@ static int svc_sock_secure_port(struct svc_rqst *rqstp) | |||
399 | return svc_port_is_privileged(svc_addr(rqstp)); | 399 | return svc_port_is_privileged(svc_addr(rqstp)); |
400 | } | 400 | } |
401 | 401 | ||
402 | static bool sunrpc_waitqueue_active(wait_queue_head_t *wq) | ||
403 | { | ||
404 | if (!wq) | ||
405 | return false; | ||
406 | /* | ||
407 | * There should normally be a memory * barrier here--see | ||
408 | * wq_has_sleeper(). | ||
409 | * | ||
410 | * It appears that isn't currently necessary, though, basically | ||
411 | * because callers all appear to have sufficient memory barriers | ||
412 | * between the time the relevant change is made and the | ||
413 | * time they call these callbacks. | ||
414 | * | ||
415 | * The nfsd code itself doesn't actually explicitly wait on | ||
416 | * these waitqueues, but it may wait on them for example in | ||
417 | * sendpage() or sendmsg() calls. (And those may be the only | ||
418 | * places, since it it uses nonblocking reads.) | ||
419 | * | ||
420 | * Maybe we should add the memory barriers anyway, but these are | ||
421 | * hot paths so we'd need to be convinced there's no sigificant | ||
422 | * penalty. | ||
423 | */ | ||
424 | return waitqueue_active(wq); | ||
425 | } | ||
426 | |||
402 | /* | 427 | /* |
403 | * INET callback when data has been received on the socket. | 428 | * INET callback when data has been received on the socket. |
404 | */ | 429 | */ |
@@ -414,7 +439,7 @@ static void svc_udp_data_ready(struct sock *sk) | |||
414 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | 439 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); |
415 | svc_xprt_enqueue(&svsk->sk_xprt); | 440 | svc_xprt_enqueue(&svsk->sk_xprt); |
416 | } | 441 | } |
417 | if (wq && waitqueue_active(wq)) | 442 | if (sunrpc_waitqueue_active(wq)) |
418 | wake_up_interruptible(wq); | 443 | wake_up_interruptible(wq); |
419 | } | 444 | } |
420 | 445 | ||
@@ -432,7 +457,7 @@ static void svc_write_space(struct sock *sk) | |||
432 | svc_xprt_enqueue(&svsk->sk_xprt); | 457 | svc_xprt_enqueue(&svsk->sk_xprt); |
433 | } | 458 | } |
434 | 459 | ||
435 | if (wq && waitqueue_active(wq)) { | 460 | if (sunrpc_waitqueue_active(wq)) { |
436 | dprintk("RPC svc_write_space: someone sleeping on %p\n", | 461 | dprintk("RPC svc_write_space: someone sleeping on %p\n", |
437 | svsk); | 462 | svsk); |
438 | wake_up_interruptible(wq); | 463 | wake_up_interruptible(wq); |
@@ -787,7 +812,7 @@ static void svc_tcp_listen_data_ready(struct sock *sk) | |||
787 | } | 812 | } |
788 | 813 | ||
789 | wq = sk_sleep(sk); | 814 | wq = sk_sleep(sk); |
790 | if (wq && waitqueue_active(wq)) | 815 | if (sunrpc_waitqueue_active(wq)) |
791 | wake_up_interruptible_all(wq); | 816 | wake_up_interruptible_all(wq); |
792 | } | 817 | } |
793 | 818 | ||
@@ -808,7 +833,7 @@ static void svc_tcp_state_change(struct sock *sk) | |||
808 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | 833 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); |
809 | svc_xprt_enqueue(&svsk->sk_xprt); | 834 | svc_xprt_enqueue(&svsk->sk_xprt); |
810 | } | 835 | } |
811 | if (wq && waitqueue_active(wq)) | 836 | if (sunrpc_waitqueue_active(wq)) |
812 | wake_up_interruptible_all(wq); | 837 | wake_up_interruptible_all(wq); |
813 | } | 838 | } |
814 | 839 | ||
@@ -823,7 +848,7 @@ static void svc_tcp_data_ready(struct sock *sk) | |||
823 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | 848 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); |
824 | svc_xprt_enqueue(&svsk->sk_xprt); | 849 | svc_xprt_enqueue(&svsk->sk_xprt); |
825 | } | 850 | } |
826 | if (wq && waitqueue_active(wq)) | 851 | if (sunrpc_waitqueue_active(wq)) |
827 | wake_up_interruptible(wq); | 852 | wake_up_interruptible(wq); |
828 | } | 853 | } |
829 | 854 | ||
@@ -1367,7 +1392,6 @@ EXPORT_SYMBOL_GPL(svc_sock_update_bufs); | |||
1367 | 1392 | ||
1368 | /* | 1393 | /* |
1369 | * Initialize socket for RPC use and create svc_sock struct | 1394 | * Initialize socket for RPC use and create svc_sock struct |
1370 | * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF. | ||
1371 | */ | 1395 | */ |
1372 | static struct svc_sock *svc_setup_socket(struct svc_serv *serv, | 1396 | static struct svc_sock *svc_setup_socket(struct svc_serv *serv, |
1373 | struct socket *sock, | 1397 | struct socket *sock, |
@@ -1594,7 +1618,7 @@ static void svc_sock_detach(struct svc_xprt *xprt) | |||
1594 | sk->sk_write_space = svsk->sk_owspace; | 1618 | sk->sk_write_space = svsk->sk_owspace; |
1595 | 1619 | ||
1596 | wq = sk_sleep(sk); | 1620 | wq = sk_sleep(sk); |
1597 | if (wq && waitqueue_active(wq)) | 1621 | if (sunrpc_waitqueue_active(wq)) |
1598 | wake_up_interruptible(wq); | 1622 | wake_up_interruptible(wq); |
1599 | } | 1623 | } |
1600 | 1624 | ||