Commit 0d9f9e122c74583de15a86d1c660c08dc298f2c8
Exists in
master
and in
4 other branches
Merge branch 'for-2.6.36' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.36' of git://linux-nfs.org/~bfields/linux: (34 commits) nfsd4: fix file open accounting for RDWR opens nfsd: don't allow setting maxblksize after svc created nfsd: initialize nfsd versions before creating svc net: sunrpc: removed duplicated #include nfsd41: Fix a crash when a callback is retried nfsd: fix startup/shutdown order bug nfsd: minor nfsd read api cleanup gcc-4.6: nfsd: fix initialized but not read warnings nfsd4: share file descriptors between stateid's nfsd4: fix openmode checking on IO using lock stateid nfsd4: miscellaneous process_open2 cleanup nfsd4: don't pretend to support write delegations nfsd: bypass readahead cache when have struct file nfsd: minor nfsd_svc() cleanup nfsd: move more into nfsd_startup() nfsd: just keep single lockd reference for nfsd nfsd: clean up nfsd_create_serv error handling nfsd: fix error handling in __write_ports_addxprt nfsd: fix error handling when starting nfsd with rpcbind down nfsd4: fix v4 state shutdown error paths ...
Showing 14 changed files Side-by-side Diff
fs/nfsd/nfs3proc.c
... | ... | @@ -168,7 +168,7 @@ |
168 | 168 | svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); |
169 | 169 | |
170 | 170 | fh_copy(&resp->fh, &argp->fh); |
171 | - nfserr = nfsd_read(rqstp, &resp->fh, NULL, | |
171 | + nfserr = nfsd_read(rqstp, &resp->fh, | |
172 | 172 | argp->offset, |
173 | 173 | rqstp->rq_vec, argp->vlen, |
174 | 174 | &resp->count); |
... | ... | @@ -271,7 +271,7 @@ |
271 | 271 | fh_init(&resp->fh, NFS3_FHSIZE); |
272 | 272 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, |
273 | 273 | &argp->attrs, S_IFDIR, 0, &resp->fh); |
274 | - | |
274 | + fh_unlock(&resp->dirfh); | |
275 | 275 | RETURN_STATUS(nfserr); |
276 | 276 | } |
277 | 277 | |
... | ... | @@ -327,7 +327,7 @@ |
327 | 327 | type = nfs3_ftypes[argp->ftype]; |
328 | 328 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, |
329 | 329 | &argp->attrs, type, rdev, &resp->fh); |
330 | - | |
330 | + fh_unlock(&resp->dirfh); | |
331 | 331 | RETURN_STATUS(nfserr); |
332 | 332 | } |
333 | 333 | |
... | ... | @@ -348,6 +348,7 @@ |
348 | 348 | /* Unlink. -S_IFDIR means file must not be a directory */ |
349 | 349 | fh_copy(&resp->fh, &argp->fh); |
350 | 350 | nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); |
351 | + fh_unlock(&resp->fh); | |
351 | 352 | RETURN_STATUS(nfserr); |
352 | 353 | } |
353 | 354 | |
... | ... | @@ -367,6 +368,7 @@ |
367 | 368 | |
368 | 369 | fh_copy(&resp->fh, &argp->fh); |
369 | 370 | nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); |
371 | + fh_unlock(&resp->fh); | |
370 | 372 | RETURN_STATUS(nfserr); |
371 | 373 | } |
372 | 374 |
fs/nfsd/nfs4callback.c
... | ... | @@ -143,8 +143,6 @@ |
143 | 143 | u32 minorversion; |
144 | 144 | /* res */ |
145 | 145 | int status; |
146 | - u32 taglen; | |
147 | - char *tag; | |
148 | 146 | }; |
149 | 147 | |
150 | 148 | static struct { |
... | ... | @@ -205,6 +203,16 @@ |
205 | 203 | */ |
206 | 204 | |
207 | 205 | static void |
206 | +encode_stateid(struct xdr_stream *xdr, stateid_t *sid) | |
207 | +{ | |
208 | + __be32 *p; | |
209 | + | |
210 | + RESERVE_SPACE(sizeof(stateid_t)); | |
211 | + WRITE32(sid->si_generation); | |
212 | + WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); | |
213 | +} | |
214 | + | |
215 | +static void | |
208 | 216 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) |
209 | 217 | { |
210 | 218 | __be32 * p; |
211 | 219 | |
... | ... | @@ -229,10 +237,10 @@ |
229 | 237 | __be32 *p; |
230 | 238 | int len = dp->dl_fh.fh_size; |
231 | 239 | |
232 | - RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); | |
240 | + RESERVE_SPACE(4); | |
233 | 241 | WRITE32(OP_CB_RECALL); |
234 | - WRITE32(dp->dl_stateid.si_generation); | |
235 | - WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); | |
242 | + encode_stateid(xdr, &dp->dl_stateid); | |
243 | + RESERVE_SPACE(8 + (XDR_QUADLEN(len) << 2)); | |
236 | 244 | WRITE32(0); /* truncate optimization not implemented */ |
237 | 245 | WRITE32(len); |
238 | 246 | WRITEMEM(&dp->dl_fh.fh_base, len); |
239 | 247 | |
... | ... | @@ -293,13 +301,14 @@ |
293 | 301 | static int |
294 | 302 | decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ |
295 | 303 | __be32 *p; |
304 | + u32 taglen; | |
296 | 305 | |
297 | 306 | READ_BUF(8); |
298 | 307 | READ32(hdr->status); |
299 | - READ32(hdr->taglen); | |
300 | - READ_BUF(hdr->taglen + 4); | |
301 | - hdr->tag = (char *)p; | |
302 | - p += XDR_QUADLEN(hdr->taglen); | |
308 | + /* We've got no use for the tag; ignore it: */ | |
309 | + READ32(taglen); | |
310 | + READ_BUF(taglen + 4); | |
311 | + p += XDR_QUADLEN(taglen); | |
303 | 312 | READ32(hdr->nops); |
304 | 313 | return 0; |
305 | 314 | } |
306 | 315 | |
307 | 316 | |
308 | 317 | |
... | ... | @@ -667,28 +676,28 @@ |
667 | 676 | } |
668 | 677 | |
669 | 678 | switch (task->tk_status) { |
670 | - case -EIO: | |
679 | + case 0: | |
680 | + return; | |
681 | + case -EBADHANDLE: | |
682 | + case -NFS4ERR_BAD_STATEID: | |
683 | + /* Race: client probably got cb_recall | |
684 | + * before open reply granting delegation */ | |
685 | + break; | |
686 | + default: | |
671 | 687 | /* Network partition? */ |
672 | 688 | atomic_set(&clp->cl_cb_set, 0); |
673 | 689 | warn_no_callback_path(clp, task->tk_status); |
674 | 690 | if (current_rpc_client != task->tk_client) { |
675 | 691 | /* queue a callback on the new connection: */ |
692 | + atomic_inc(&dp->dl_count); | |
676 | 693 | nfsd4_cb_recall(dp); |
677 | 694 | return; |
678 | 695 | } |
679 | - case -EBADHANDLE: | |
680 | - case -NFS4ERR_BAD_STATEID: | |
681 | - /* Race: client probably got cb_recall | |
682 | - * before open reply granting delegation */ | |
683 | - break; | |
684 | - default: | |
685 | - /* success, or error we can't handle */ | |
686 | - return; | |
687 | 696 | } |
688 | 697 | if (dp->dl_retries--) { |
689 | 698 | rpc_delay(task, 2*HZ); |
690 | 699 | task->tk_status = 0; |
691 | - rpc_restart_call(task); | |
700 | + rpc_restart_call_prepare(task); | |
692 | 701 | return; |
693 | 702 | } else { |
694 | 703 | atomic_set(&clp->cl_cb_set, 0); |
695 | 704 | |
696 | 705 | |
697 | 706 | |
... | ... | @@ -752,18 +761,16 @@ |
752 | 761 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
753 | 762 | .rpc_cred = callback_cred |
754 | 763 | }; |
755 | - int status; | |
756 | 764 | |
757 | - if (clnt == NULL) | |
765 | + if (clnt == NULL) { | |
766 | + nfs4_put_delegation(dp); | |
758 | 767 | return; /* Client is shutting down; give up. */ |
768 | + } | |
759 | 769 | |
760 | 770 | args->args_op = dp; |
761 | 771 | msg.rpc_argp = args; |
762 | 772 | dp->dl_retries = 1; |
763 | - status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, | |
764 | - &nfsd4_cb_recall_ops, dp); | |
765 | - if (status) | |
766 | - nfs4_put_delegation(dp); | |
773 | + rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp); | |
767 | 774 | } |
768 | 775 | |
769 | 776 | void nfsd4_do_callback_rpc(struct work_struct *w) |
fs/nfsd/nfs4state.c
... | ... | @@ -51,7 +51,6 @@ |
51 | 51 | static u32 current_ownerid = 1; |
52 | 52 | static u32 current_fileid = 1; |
53 | 53 | static u32 current_delegid = 1; |
54 | -static u32 nfs4_init; | |
55 | 54 | static stateid_t zerostateid; /* bits all 0 */ |
56 | 55 | static stateid_t onestateid; /* bits all 1 */ |
57 | 56 | static u64 current_sessionid = 1; |
... | ... | @@ -163,6 +162,46 @@ |
163 | 162 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; |
164 | 163 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; |
165 | 164 | |
165 | +static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) | |
166 | +{ | |
167 | + BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); | |
168 | + atomic_inc(&fp->fi_access[oflag]); | |
169 | +} | |
170 | + | |
171 | +static void nfs4_file_get_access(struct nfs4_file *fp, int oflag) | |
172 | +{ | |
173 | + if (oflag == O_RDWR) { | |
174 | + __nfs4_file_get_access(fp, O_RDONLY); | |
175 | + __nfs4_file_get_access(fp, O_WRONLY); | |
176 | + } else | |
177 | + __nfs4_file_get_access(fp, oflag); | |
178 | +} | |
179 | + | |
180 | +static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) | |
181 | +{ | |
182 | + if (fp->fi_fds[oflag]) { | |
183 | + fput(fp->fi_fds[oflag]); | |
184 | + fp->fi_fds[oflag] = NULL; | |
185 | + } | |
186 | +} | |
187 | + | |
188 | +static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) | |
189 | +{ | |
190 | + if (atomic_dec_and_test(&fp->fi_access[oflag])) { | |
191 | + nfs4_file_put_fd(fp, O_RDWR); | |
192 | + nfs4_file_put_fd(fp, oflag); | |
193 | + } | |
194 | +} | |
195 | + | |
196 | +static void nfs4_file_put_access(struct nfs4_file *fp, int oflag) | |
197 | +{ | |
198 | + if (oflag == O_RDWR) { | |
199 | + __nfs4_file_put_access(fp, O_RDONLY); | |
200 | + __nfs4_file_put_access(fp, O_WRONLY); | |
201 | + } else | |
202 | + __nfs4_file_put_access(fp, oflag); | |
203 | +} | |
204 | + | |
166 | 205 | static struct nfs4_delegation * |
167 | 206 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
168 | 207 | { |
... | ... | @@ -171,6 +210,13 @@ |
171 | 210 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
172 | 211 | |
173 | 212 | dprintk("NFSD alloc_init_deleg\n"); |
213 | + /* | |
214 | + * Major work on the lease subsystem (for example, to support | |
215 | + * calbacks on stat) will be required before we can support | |
216 | + * write delegations properly. | |
217 | + */ | |
218 | + if (type != NFS4_OPEN_DELEGATE_READ) | |
219 | + return NULL; | |
174 | 220 | if (fp->fi_had_conflict) |
175 | 221 | return NULL; |
176 | 222 | if (num_delegations > max_delegations) |
177 | 223 | |
... | ... | @@ -185,9 +231,8 @@ |
185 | 231 | dp->dl_client = clp; |
186 | 232 | get_nfs4_file(fp); |
187 | 233 | dp->dl_file = fp; |
234 | + nfs4_file_get_access(fp, O_RDONLY); | |
188 | 235 | dp->dl_flock = NULL; |
189 | - get_file(stp->st_vfs_file); | |
190 | - dp->dl_vfs_file = stp->st_vfs_file; | |
191 | 236 | dp->dl_type = type; |
192 | 237 | dp->dl_ident = cb->cb_ident; |
193 | 238 | dp->dl_stateid.si_boot = boot_time; |
194 | 239 | |
195 | 240 | |
... | ... | @@ -222,15 +267,12 @@ |
222 | 267 | static void |
223 | 268 | nfs4_close_delegation(struct nfs4_delegation *dp) |
224 | 269 | { |
225 | - struct file *filp = dp->dl_vfs_file; | |
270 | + struct file *filp = find_readable_file(dp->dl_file); | |
226 | 271 | |
227 | 272 | dprintk("NFSD: close_delegation dp %p\n",dp); |
228 | - dp->dl_vfs_file = NULL; | |
229 | - /* The following nfsd_close may not actually close the file, | |
230 | - * but we want to remove the lease in any case. */ | |
231 | 273 | if (dp->dl_flock) |
232 | 274 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); |
233 | - nfsd_close(filp); | |
275 | + nfs4_file_put_access(dp->dl_file, O_RDONLY); | |
234 | 276 | } |
235 | 277 | |
236 | 278 | /* Called under the state lock. */ |
237 | 279 | |
... | ... | @@ -302,8 +344,12 @@ |
302 | 344 | |
303 | 345 | static void release_lock_stateid(struct nfs4_stateid *stp) |
304 | 346 | { |
347 | + struct file *file; | |
348 | + | |
305 | 349 | unhash_generic_stateid(stp); |
306 | - locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner); | |
350 | + file = find_any_file(stp->st_file); | |
351 | + if (file) | |
352 | + locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | |
307 | 353 | free_generic_stateid(stp); |
308 | 354 | } |
309 | 355 | |
310 | 356 | |
311 | 357 | |
... | ... | @@ -341,11 +387,85 @@ |
341 | 387 | } |
342 | 388 | } |
343 | 389 | |
390 | +/* | |
391 | + * We store the NONE, READ, WRITE, and BOTH bits separately in the | |
392 | + * st_{access,deny}_bmap field of the stateid, in order to track not | |
393 | + * only what share bits are currently in force, but also what | |
394 | + * combinations of share bits previous opens have used. This allows us | |
395 | + * to enforce the recommendation of rfc 3530 14.2.19 that the server | |
396 | + * return an error if the client attempt to downgrade to a combination | |
397 | + * of share bits not explicable by closing some of its previous opens. | |
398 | + * | |
399 | + * XXX: This enforcement is actually incomplete, since we don't keep | |
400 | + * track of access/deny bit combinations; so, e.g., we allow: | |
401 | + * | |
402 | + * OPEN allow read, deny write | |
403 | + * OPEN allow both, deny none | |
404 | + * DOWNGRADE allow read, deny none | |
405 | + * | |
406 | + * which we should reject. | |
407 | + */ | |
408 | +static void | |
409 | +set_access(unsigned int *access, unsigned long bmap) { | |
410 | + int i; | |
411 | + | |
412 | + *access = 0; | |
413 | + for (i = 1; i < 4; i++) { | |
414 | + if (test_bit(i, &bmap)) | |
415 | + *access |= i; | |
416 | + } | |
417 | +} | |
418 | + | |
419 | +static void | |
420 | +set_deny(unsigned int *deny, unsigned long bmap) { | |
421 | + int i; | |
422 | + | |
423 | + *deny = 0; | |
424 | + for (i = 0; i < 4; i++) { | |
425 | + if (test_bit(i, &bmap)) | |
426 | + *deny |= i ; | |
427 | + } | |
428 | +} | |
429 | + | |
430 | +static int | |
431 | +test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | |
432 | + unsigned int access, deny; | |
433 | + | |
434 | + set_access(&access, stp->st_access_bmap); | |
435 | + set_deny(&deny, stp->st_deny_bmap); | |
436 | + if ((access & open->op_share_deny) || (deny & open->op_share_access)) | |
437 | + return 0; | |
438 | + return 1; | |
439 | +} | |
440 | + | |
441 | +static int nfs4_access_to_omode(u32 access) | |
442 | +{ | |
443 | + switch (access) { | |
444 | + case NFS4_SHARE_ACCESS_READ: | |
445 | + return O_RDONLY; | |
446 | + case NFS4_SHARE_ACCESS_WRITE: | |
447 | + return O_WRONLY; | |
448 | + case NFS4_SHARE_ACCESS_BOTH: | |
449 | + return O_RDWR; | |
450 | + } | |
451 | + BUG(); | |
452 | +} | |
453 | + | |
454 | +static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | |
455 | +{ | |
456 | + unsigned int access; | |
457 | + | |
458 | + set_access(&access, stp->st_access_bmap); | |
459 | + return nfs4_access_to_omode(access); | |
460 | +} | |
461 | + | |
344 | 462 | static void release_open_stateid(struct nfs4_stateid *stp) |
345 | 463 | { |
464 | + int oflag = nfs4_access_bmap_to_omode(stp); | |
465 | + | |
346 | 466 | unhash_generic_stateid(stp); |
347 | 467 | release_stateid_lockowners(stp); |
348 | - nfsd_close(stp->st_vfs_file); | |
468 | + nfs4_file_put_access(stp->st_file, oflag); | |
349 | 469 | free_generic_stateid(stp); |
350 | 470 | } |
351 | 471 | |
... | ... | @@ -457,7 +577,7 @@ |
457 | 577 | spin_unlock(&nfsd_drc_lock); |
458 | 578 | |
459 | 579 | if (fchan->maxreqs == 0) |
460 | - return nfserr_serverfault; | |
580 | + return nfserr_jukebox; | |
461 | 581 | |
462 | 582 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; |
463 | 583 | return 0; |
... | ... | @@ -542,7 +662,7 @@ |
542 | 662 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) |
543 | 663 | + sizeof(struct nfsd4_session) > PAGE_SIZE); |
544 | 664 | |
545 | - status = nfserr_serverfault; | |
665 | + status = nfserr_jukebox; | |
546 | 666 | /* allocate struct nfsd4_session and slot table pointers in one piece */ |
547 | 667 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); |
548 | 668 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
549 | 669 | |
... | ... | @@ -591,10 +711,8 @@ |
591 | 711 | |
592 | 712 | dump_sessionid(__func__, sessionid); |
593 | 713 | idx = hash_sessionid(sessionid); |
594 | - dprintk("%s: idx is %d\n", __func__, idx); | |
595 | 714 | /* Search in the appropriate list */ |
596 | 715 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { |
597 | - dump_sessionid("list traversal", &elem->se_sessionid); | |
598 | 716 | if (!memcmp(elem->se_sessionid.data, sessionid->data, |
599 | 717 | NFS4_MAX_SESSIONID_LEN)) { |
600 | 718 | return elem; |
... | ... | @@ -714,7 +832,6 @@ |
714 | 832 | } else |
715 | 833 | renew_client_locked(clp); |
716 | 834 | spin_unlock(&client_lock); |
717 | - nfsd4_put_session(session); | |
718 | 835 | } |
719 | 836 | |
720 | 837 | /* must be called under the client_lock */ |
... | ... | @@ -1220,7 +1337,7 @@ |
1220 | 1337 | /* Normal case */ |
1221 | 1338 | new = create_client(exid->clname, dname, rqstp, &verf); |
1222 | 1339 | if (new == NULL) { |
1223 | - status = nfserr_serverfault; | |
1340 | + status = nfserr_jukebox; | |
1224 | 1341 | goto out; |
1225 | 1342 | } |
1226 | 1343 | |
... | ... | @@ -1760,6 +1877,8 @@ |
1760 | 1877 | fp->fi_inode = igrab(ino); |
1761 | 1878 | fp->fi_id = current_fileid++; |
1762 | 1879 | fp->fi_had_conflict = false; |
1880 | + memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | |
1881 | + memset(fp->fi_access, 0, sizeof(fp->fi_access)); | |
1763 | 1882 | spin_lock(&recall_lock); |
1764 | 1883 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
1765 | 1884 | spin_unlock(&recall_lock); |
... | ... | @@ -1971,57 +2090,6 @@ |
1971 | 2090 | } |
1972 | 2091 | |
1973 | 2092 | /* |
1974 | - * We store the NONE, READ, WRITE, and BOTH bits separately in the | |
1975 | - * st_{access,deny}_bmap field of the stateid, in order to track not | |
1976 | - * only what share bits are currently in force, but also what | |
1977 | - * combinations of share bits previous opens have used. This allows us | |
1978 | - * to enforce the recommendation of rfc 3530 14.2.19 that the server | |
1979 | - * return an error if the client attempt to downgrade to a combination | |
1980 | - * of share bits not explicable by closing some of its previous opens. | |
1981 | - * | |
1982 | - * XXX: This enforcement is actually incomplete, since we don't keep | |
1983 | - * track of access/deny bit combinations; so, e.g., we allow: | |
1984 | - * | |
1985 | - * OPEN allow read, deny write | |
1986 | - * OPEN allow both, deny none | |
1987 | - * DOWNGRADE allow read, deny none | |
1988 | - * | |
1989 | - * which we should reject. | |
1990 | - */ | |
1991 | -static void | |
1992 | -set_access(unsigned int *access, unsigned long bmap) { | |
1993 | - int i; | |
1994 | - | |
1995 | - *access = 0; | |
1996 | - for (i = 1; i < 4; i++) { | |
1997 | - if (test_bit(i, &bmap)) | |
1998 | - *access |= i; | |
1999 | - } | |
2000 | -} | |
2001 | - | |
2002 | -static void | |
2003 | -set_deny(unsigned int *deny, unsigned long bmap) { | |
2004 | - int i; | |
2005 | - | |
2006 | - *deny = 0; | |
2007 | - for (i = 0; i < 4; i++) { | |
2008 | - if (test_bit(i, &bmap)) | |
2009 | - *deny |= i ; | |
2010 | - } | |
2011 | -} | |
2012 | - | |
2013 | -static int | |
2014 | -test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | |
2015 | - unsigned int access, deny; | |
2016 | - | |
2017 | - set_access(&access, stp->st_access_bmap); | |
2018 | - set_deny(&deny, stp->st_deny_bmap); | |
2019 | - if ((access & open->op_share_deny) || (deny & open->op_share_access)) | |
2020 | - return 0; | |
2021 | - return 1; | |
2022 | -} | |
2023 | - | |
2024 | -/* | |
2025 | 2093 | * Called to check deny when READ with all zero stateid or |
2026 | 2094 | * WRITE with all zero or all one stateid |
2027 | 2095 | */ |
2028 | 2096 | |
... | ... | @@ -2052,14 +2120,12 @@ |
2052 | 2120 | } |
2053 | 2121 | |
2054 | 2122 | static inline void |
2055 | -nfs4_file_downgrade(struct file *filp, unsigned int share_access) | |
2123 | +nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) | |
2056 | 2124 | { |
2057 | - if (share_access & NFS4_SHARE_ACCESS_WRITE) { | |
2058 | - drop_file_write_access(filp); | |
2059 | - spin_lock(&filp->f_lock); | |
2060 | - filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; | |
2061 | - spin_unlock(&filp->f_lock); | |
2062 | - } | |
2125 | + if (share_access & NFS4_SHARE_ACCESS_WRITE) | |
2126 | + nfs4_file_put_access(fp, O_WRONLY); | |
2127 | + if (share_access & NFS4_SHARE_ACCESS_READ) | |
2128 | + nfs4_file_put_access(fp, O_RDONLY); | |
2063 | 2129 | } |
2064 | 2130 | |
2065 | 2131 | /* |
... | ... | @@ -2255,6 +2321,13 @@ |
2255 | 2321 | return NULL; |
2256 | 2322 | } |
2257 | 2323 | |
2324 | +int share_access_to_flags(u32 share_access) | |
2325 | +{ | |
2326 | + share_access &= ~NFS4_SHARE_WANT_MASK; | |
2327 | + | |
2328 | + return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; | |
2329 | +} | |
2330 | + | |
2258 | 2331 | static __be32 |
2259 | 2332 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, |
2260 | 2333 | struct nfs4_delegation **dp) |
... | ... | @@ -2265,8 +2338,7 @@ |
2265 | 2338 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); |
2266 | 2339 | if (*dp == NULL) |
2267 | 2340 | goto out; |
2268 | - flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ? | |
2269 | - RD_STATE : WR_STATE; | |
2341 | + flags = share_access_to_flags(open->op_share_access); | |
2270 | 2342 | status = nfs4_check_delegmode(*dp, flags); |
2271 | 2343 | if (status) |
2272 | 2344 | *dp = NULL; |
2273 | 2345 | |
2274 | 2346 | |
2275 | 2347 | |
... | ... | @@ -2308,30 +2380,53 @@ |
2308 | 2380 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); |
2309 | 2381 | } |
2310 | 2382 | |
2383 | +static inline int nfs4_access_to_access(u32 nfs4_access) | |
2384 | +{ | |
2385 | + int flags = 0; | |
2386 | + | |
2387 | + if (nfs4_access & NFS4_SHARE_ACCESS_READ) | |
2388 | + flags |= NFSD_MAY_READ; | |
2389 | + if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) | |
2390 | + flags |= NFSD_MAY_WRITE; | |
2391 | + return flags; | |
2392 | +} | |
2393 | + | |
2394 | +static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | |
2395 | +*fp, struct svc_fh *cur_fh, u32 nfs4_access) | |
2396 | +{ | |
2397 | + __be32 status; | |
2398 | + int oflag = nfs4_access_to_omode(nfs4_access); | |
2399 | + int access = nfs4_access_to_access(nfs4_access); | |
2400 | + | |
2401 | + if (!fp->fi_fds[oflag]) { | |
2402 | + status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | |
2403 | + &fp->fi_fds[oflag]); | |
2404 | + if (status == nfserr_dropit) | |
2405 | + status = nfserr_jukebox; | |
2406 | + if (status) | |
2407 | + return status; | |
2408 | + } | |
2409 | + nfs4_file_get_access(fp, oflag); | |
2410 | + | |
2411 | + return nfs_ok; | |
2412 | +} | |
2413 | + | |
2311 | 2414 | static __be32 |
2312 | 2415 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, |
2313 | - struct nfs4_delegation *dp, | |
2314 | - struct svc_fh *cur_fh, int flags) | |
2416 | + struct nfs4_file *fp, struct svc_fh *cur_fh, | |
2417 | + struct nfsd4_open *open) | |
2315 | 2418 | { |
2316 | 2419 | struct nfs4_stateid *stp; |
2420 | + __be32 status; | |
2317 | 2421 | |
2318 | 2422 | stp = nfs4_alloc_stateid(); |
2319 | 2423 | if (stp == NULL) |
2320 | 2424 | return nfserr_resource; |
2321 | 2425 | |
2322 | - if (dp) { | |
2323 | - get_file(dp->dl_vfs_file); | |
2324 | - stp->st_vfs_file = dp->dl_vfs_file; | |
2325 | - } else { | |
2326 | - __be32 status; | |
2327 | - status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, | |
2328 | - &stp->st_vfs_file); | |
2329 | - if (status) { | |
2330 | - if (status == nfserr_dropit) | |
2331 | - status = nfserr_jukebox; | |
2332 | - kmem_cache_free(stateid_slab, stp); | |
2333 | - return status; | |
2334 | - } | |
2426 | + status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); | |
2427 | + if (status) { | |
2428 | + kmem_cache_free(stateid_slab, stp); | |
2429 | + return status; | |
2335 | 2430 | } |
2336 | 2431 | *stpp = stp; |
2337 | 2432 | return 0; |
2338 | 2433 | |
2339 | 2434 | |
2340 | 2435 | |
2341 | 2436 | |
2342 | 2437 | |
... | ... | @@ -2353,35 +2448,30 @@ |
2353 | 2448 | } |
2354 | 2449 | |
2355 | 2450 | static __be32 |
2356 | -nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) | |
2451 | +nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) | |
2357 | 2452 | { |
2358 | - struct file *filp = stp->st_vfs_file; | |
2359 | - struct inode *inode = filp->f_path.dentry->d_inode; | |
2360 | - unsigned int share_access, new_writer; | |
2453 | + u32 op_share_access, new_access; | |
2361 | 2454 | __be32 status; |
2362 | 2455 | |
2363 | - set_access(&share_access, stp->st_access_bmap); | |
2364 | - new_writer = (~share_access) & open->op_share_access | |
2365 | - & NFS4_SHARE_ACCESS_WRITE; | |
2456 | + set_access(&new_access, stp->st_access_bmap); | |
2457 | + new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; | |
2366 | 2458 | |
2367 | - if (new_writer) { | |
2368 | - int err = get_write_access(inode); | |
2369 | - if (err) | |
2370 | - return nfserrno(err); | |
2371 | - err = mnt_want_write(cur_fh->fh_export->ex_path.mnt); | |
2372 | - if (err) | |
2373 | - return nfserrno(err); | |
2374 | - file_take_write(filp); | |
2459 | + if (new_access) { | |
2460 | + status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access); | |
2461 | + if (status) | |
2462 | + return status; | |
2375 | 2463 | } |
2376 | 2464 | status = nfsd4_truncate(rqstp, cur_fh, open); |
2377 | 2465 | if (status) { |
2378 | - if (new_writer) | |
2379 | - put_write_access(inode); | |
2466 | + if (new_access) { | |
2467 | + int oflag = nfs4_access_to_omode(new_access); | |
2468 | + nfs4_file_put_access(fp, oflag); | |
2469 | + } | |
2380 | 2470 | return status; |
2381 | 2471 | } |
2382 | 2472 | /* remember the open */ |
2383 | - filp->f_mode |= open->op_share_access; | |
2384 | - __set_bit(open->op_share_access, &stp->st_access_bmap); | |
2473 | + op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; | |
2474 | + __set_bit(op_share_access, &stp->st_access_bmap); | |
2385 | 2475 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2386 | 2476 | |
2387 | 2477 | return nfs_ok; |
2388 | 2478 | |
... | ... | @@ -2444,13 +2534,14 @@ |
2444 | 2534 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; |
2445 | 2535 | fl.fl_end = OFFSET_MAX; |
2446 | 2536 | fl.fl_owner = (fl_owner_t)dp; |
2447 | - fl.fl_file = stp->st_vfs_file; | |
2537 | + fl.fl_file = find_readable_file(stp->st_file); | |
2538 | + BUG_ON(!fl.fl_file); | |
2448 | 2539 | fl.fl_pid = current->tgid; |
2449 | 2540 | |
2450 | 2541 | /* vfs_setlease checks to see if delegation should be handed out. |
2451 | 2542 | * the lock_manager callbacks fl_mylease and fl_change are used |
2452 | 2543 | */ |
2453 | - if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) { | |
2544 | + if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) { | |
2454 | 2545 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
2455 | 2546 | unhash_delegation(dp); |
2456 | 2547 | flag = NFS4_OPEN_DELEGATE_NONE; |
2457 | 2548 | |
... | ... | @@ -2514,18 +2605,12 @@ |
2514 | 2605 | */ |
2515 | 2606 | if (stp) { |
2516 | 2607 | /* Stateid was found, this is an OPEN upgrade */ |
2517 | - status = nfs4_upgrade_open(rqstp, current_fh, stp, open); | |
2608 | + status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); | |
2518 | 2609 | if (status) |
2519 | 2610 | goto out; |
2520 | 2611 | update_stateid(&stp->st_stateid); |
2521 | 2612 | } else { |
2522 | - /* Stateid was not found, this is a new OPEN */ | |
2523 | - int flags = 0; | |
2524 | - if (open->op_share_access & NFS4_SHARE_ACCESS_READ) | |
2525 | - flags |= NFSD_MAY_READ; | |
2526 | - if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | |
2527 | - flags |= NFSD_MAY_WRITE; | |
2528 | - status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); | |
2613 | + status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); | |
2529 | 2614 | if (status) |
2530 | 2615 | goto out; |
2531 | 2616 | init_stateid(stp, fp, open); |
... | ... | @@ -2727,7 +2812,7 @@ |
2727 | 2812 | static inline int |
2728 | 2813 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) |
2729 | 2814 | { |
2730 | - return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode; | |
2815 | + return fhp->fh_dentry->d_inode != stp->st_file->fi_inode; | |
2731 | 2816 | } |
2732 | 2817 | |
2733 | 2818 | static int |
... | ... | @@ -2760,6 +2845,9 @@ |
2760 | 2845 | { |
2761 | 2846 | __be32 status = nfserr_openmode; |
2762 | 2847 | |
2848 | + /* For lock stateid's, we test the parent open, not the lock: */ | |
2849 | + if (stp->st_openstp) | |
2850 | + stp = stp->st_openstp; | |
2763 | 2851 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) |
2764 | 2852 | goto out; |
2765 | 2853 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) |
... | ... | @@ -2872,7 +2960,8 @@ |
2872 | 2960 | goto out; |
2873 | 2961 | renew_client(dp->dl_client); |
2874 | 2962 | if (filpp) |
2875 | - *filpp = dp->dl_vfs_file; | |
2963 | + *filpp = find_readable_file(dp->dl_file); | |
2964 | + BUG_ON(!*filpp); | |
2876 | 2965 | } else { /* open or lock stateid */ |
2877 | 2966 | stp = find_stateid(stateid, flags); |
2878 | 2967 | if (!stp) |
... | ... | @@ -2889,8 +2978,13 @@ |
2889 | 2978 | if (status) |
2890 | 2979 | goto out; |
2891 | 2980 | renew_client(stp->st_stateowner->so_client); |
2892 | - if (filpp) | |
2893 | - *filpp = stp->st_vfs_file; | |
2981 | + if (filpp) { | |
2982 | + if (flags & RD_STATE) | |
2983 | + *filpp = find_readable_file(stp->st_file); | |
2984 | + else | |
2985 | + *filpp = find_writeable_file(stp->st_file); | |
2986 | + BUG_ON(!*filpp); /* assured by check_openmode */ | |
2987 | + } | |
2894 | 2988 | } |
2895 | 2989 | status = nfs_ok; |
2896 | 2990 | out: |
... | ... | @@ -3126,8 +3220,7 @@ |
3126 | 3220 | goto out; |
3127 | 3221 | } |
3128 | 3222 | set_access(&share_access, stp->st_access_bmap); |
3129 | - nfs4_file_downgrade(stp->st_vfs_file, | |
3130 | - share_access & ~od->od_share_access); | |
3223 | + nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); | |
3131 | 3224 | |
3132 | 3225 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); |
3133 | 3226 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
3134 | 3227 | |
... | ... | @@ -3346,11 +3439,9 @@ |
3346 | 3439 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) |
3347 | 3440 | { |
3348 | 3441 | struct nfs4_stateowner *sop; |
3349 | - unsigned int hval; | |
3350 | 3442 | |
3351 | 3443 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { |
3352 | 3444 | sop = (struct nfs4_stateowner *) fl->fl_owner; |
3353 | - hval = lockownerid_hashval(sop->so_id); | |
3354 | 3445 | kref_get(&sop->so_ref); |
3355 | 3446 | deny->ld_sop = sop; |
3356 | 3447 | deny->ld_clientid = sop->so_client->cl_clientid; |
... | ... | @@ -3446,8 +3537,6 @@ |
3446 | 3537 | stp->st_stateid.si_stateownerid = sop->so_id; |
3447 | 3538 | stp->st_stateid.si_fileid = fp->fi_id; |
3448 | 3539 | stp->st_stateid.si_generation = 0; |
3449 | - stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ | |
3450 | - stp->st_access_bmap = open_stp->st_access_bmap; | |
3451 | 3540 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3452 | 3541 | stp->st_openstp = open_stp; |
3453 | 3542 | |
... | ... | @@ -3547,7 +3636,6 @@ |
3547 | 3636 | lock_sop = lock->lk_replay_owner; |
3548 | 3637 | } |
3549 | 3638 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
3550 | - filp = lock_stp->st_vfs_file; | |
3551 | 3639 | |
3552 | 3640 | status = nfserr_grace; |
3553 | 3641 | if (locks_in_grace() && !lock->lk_reclaim) |
3554 | 3642 | |
... | ... | @@ -3560,11 +3648,13 @@ |
3560 | 3648 | switch (lock->lk_type) { |
3561 | 3649 | case NFS4_READ_LT: |
3562 | 3650 | case NFS4_READW_LT: |
3651 | + filp = find_readable_file(lock_stp->st_file); | |
3563 | 3652 | file_lock.fl_type = F_RDLCK; |
3564 | 3653 | cmd = F_SETLK; |
3565 | 3654 | break; |
3566 | 3655 | case NFS4_WRITE_LT: |
3567 | 3656 | case NFS4_WRITEW_LT: |
3657 | + filp = find_writeable_file(lock_stp->st_file); | |
3568 | 3658 | file_lock.fl_type = F_WRLCK; |
3569 | 3659 | cmd = F_SETLK; |
3570 | 3660 | break; |
... | ... | @@ -3572,6 +3662,10 @@ |
3572 | 3662 | status = nfserr_inval; |
3573 | 3663 | goto out; |
3574 | 3664 | } |
3665 | + if (!filp) { | |
3666 | + status = nfserr_openmode; | |
3667 | + goto out; | |
3668 | + } | |
3575 | 3669 | file_lock.fl_owner = (fl_owner_t)lock_sop; |
3576 | 3670 | file_lock.fl_pid = current->tgid; |
3577 | 3671 | file_lock.fl_file = filp; |
... | ... | @@ -3740,7 +3834,11 @@ |
3740 | 3834 | &locku->lu_stateowner, &stp, NULL))) |
3741 | 3835 | goto out; |
3742 | 3836 | |
3743 | - filp = stp->st_vfs_file; | |
3837 | + filp = find_any_file(stp->st_file); | |
3838 | + if (!filp) { | |
3839 | + status = nfserr_lock_range; | |
3840 | + goto out; | |
3841 | + } | |
3744 | 3842 | BUG_ON(!filp); |
3745 | 3843 | locks_init_lock(&file_lock); |
3746 | 3844 | file_lock.fl_type = F_UNLCK; |
3747 | 3845 | |
... | ... | @@ -3787,10 +3885,10 @@ |
3787 | 3885 | * 0: no locks held by lockowner |
3788 | 3886 | */ |
3789 | 3887 | static int |
3790 | -check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) | |
3888 | +check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) | |
3791 | 3889 | { |
3792 | 3890 | struct file_lock **flpp; |
3793 | - struct inode *inode = filp->f_path.dentry->d_inode; | |
3891 | + struct inode *inode = filp->fi_inode; | |
3794 | 3892 | int status = 0; |
3795 | 3893 | |
3796 | 3894 | lock_kernel(); |
... | ... | @@ -3841,7 +3939,7 @@ |
3841 | 3939 | continue; |
3842 | 3940 | list_for_each_entry(stp, &sop->so_stateids, |
3843 | 3941 | st_perstateowner) { |
3844 | - if (check_for_locks(stp->st_vfs_file, sop)) | |
3942 | + if (check_for_locks(stp->st_file, sop)) | |
3845 | 3943 | goto out; |
3846 | 3944 | /* Note: so_perclient unused for lockowners, |
3847 | 3945 | * so it's OK to fool with here. */ |
3848 | 3946 | |
... | ... | @@ -4066,16 +4164,8 @@ |
4066 | 4164 | int |
4067 | 4165 | nfs4_state_start(void) |
4068 | 4166 | { |
4069 | - int ret; | |
4070 | - | |
4071 | - if (nfs4_init) | |
4072 | - return 0; | |
4073 | 4167 | nfsd4_load_reboot_recovery_data(); |
4074 | - ret = __nfs4_state_start(); | |
4075 | - if (ret) | |
4076 | - return ret; | |
4077 | - nfs4_init = 1; | |
4078 | - return 0; | |
4168 | + return __nfs4_state_start(); | |
4079 | 4169 | } |
4080 | 4170 | |
4081 | 4171 | static void |
... | ... | @@ -4110,7 +4200,6 @@ |
4110 | 4200 | } |
4111 | 4201 | |
4112 | 4202 | nfsd4_shutdown_recdir(); |
4113 | - nfs4_init = 0; | |
4114 | 4203 | } |
4115 | 4204 | |
4116 | 4205 | void |
fs/nfsd/nfs4xdr.c
... | ... | @@ -2630,7 +2630,7 @@ |
2630 | 2630 | } |
2631 | 2631 | read->rd_vlen = v; |
2632 | 2632 | |
2633 | - nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, | |
2633 | + nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp, | |
2634 | 2634 | read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, |
2635 | 2635 | &maxcount); |
2636 | 2636 | |
... | ... | @@ -3325,6 +3325,7 @@ |
3325 | 3325 | } |
3326 | 3326 | /* Renew the clientid on success and on replay */ |
3327 | 3327 | release_session_client(cs->session); |
3328 | + nfsd4_put_session(cs->session); | |
3328 | 3329 | } |
3329 | 3330 | return 1; |
3330 | 3331 | } |
fs/nfsd/nfsctl.c
... | ... | @@ -949,15 +949,12 @@ |
949 | 949 | if (err != 0) |
950 | 950 | return err; |
951 | 951 | |
952 | - err = lockd_up(); | |
953 | - if (err != 0) | |
954 | - goto out; | |
955 | - | |
956 | 952 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
957 | - if (err < 0) | |
958 | - lockd_down(); | |
953 | + if (err < 0) { | |
954 | + svc_destroy(nfsd_serv); | |
955 | + return err; | |
956 | + } | |
959 | 957 | |
960 | -out: | |
961 | 958 | /* Decrease the count, but don't shut down the service */ |
962 | 959 | nfsd_serv->sv_nrthreads--; |
963 | 960 | return err; |
... | ... | @@ -978,9 +975,6 @@ |
978 | 975 | if (nfsd_serv != NULL) |
979 | 976 | len = svc_sock_names(nfsd_serv, buf, |
980 | 977 | SIMPLE_TRANSACTION_LIMIT, toclose); |
981 | - if (len >= 0) | |
982 | - lockd_down(); | |
983 | - | |
984 | 978 | kfree(toclose); |
985 | 979 | return len; |
986 | 980 | } |
... | ... | @@ -1014,6 +1008,9 @@ |
1014 | 1008 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
1015 | 1009 | if (err < 0 && err != -EAFNOSUPPORT) |
1016 | 1010 | goto out_close; |
1011 | + | |
1012 | + /* Decrease the count, but don't shut down the service */ | |
1013 | + nfsd_serv->sv_nrthreads--; | |
1017 | 1014 | return 0; |
1018 | 1015 | out_close: |
1019 | 1016 | xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port); |
... | ... | @@ -1022,8 +1019,7 @@ |
1022 | 1019 | svc_xprt_put(xprt); |
1023 | 1020 | } |
1024 | 1021 | out_err: |
1025 | - /* Decrease the count, but don't shut down the service */ | |
1026 | - nfsd_serv->sv_nrthreads--; | |
1022 | + svc_destroy(nfsd_serv); | |
1027 | 1023 | return err; |
1028 | 1024 | } |
1029 | 1025 | |
... | ... | @@ -1194,7 +1190,7 @@ |
1194 | 1190 | bsize = NFSSVC_MAXBLKSIZE; |
1195 | 1191 | bsize &= ~(1024-1); |
1196 | 1192 | mutex_lock(&nfsd_mutex); |
1197 | - if (nfsd_serv && nfsd_serv->sv_nrthreads) { | |
1193 | + if (nfsd_serv) { | |
1198 | 1194 | mutex_unlock(&nfsd_mutex); |
1199 | 1195 | return -EBUSY; |
1200 | 1196 | } |
... | ... | @@ -1310,6 +1306,8 @@ |
1310 | 1306 | return -EINVAL; |
1311 | 1307 | |
1312 | 1308 | status = nfs4_reset_recoverydir(recdir); |
1309 | + if (status) | |
1310 | + return status; | |
1313 | 1311 | } |
1314 | 1312 | |
1315 | 1313 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
fs/nfsd/nfsd.h
... | ... | @@ -153,6 +153,7 @@ |
153 | 153 | #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) |
154 | 154 | #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) |
155 | 155 | #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) |
156 | +#define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE) | |
156 | 157 | #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) |
157 | 158 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) |
158 | 159 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) |
fs/nfsd/nfsproc.c
... | ... | @@ -144,7 +144,7 @@ |
144 | 144 | svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); |
145 | 145 | |
146 | 146 | resp->count = argp->count; |
147 | - nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, | |
147 | + nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), | |
148 | 148 | argp->offset, |
149 | 149 | rqstp->rq_vec, argp->vlen, |
150 | 150 | &resp->count); |
... | ... | @@ -290,7 +290,6 @@ |
290 | 290 | * gospel of sun micro |
291 | 291 | */ |
292 | 292 | if (type != S_IFREG) { |
293 | - int is_borc = 0; | |
294 | 293 | if (type != S_IFBLK && type != S_IFCHR) { |
295 | 294 | rdev = 0; |
296 | 295 | } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { |
... | ... | @@ -298,7 +297,6 @@ |
298 | 297 | type = S_IFIFO; |
299 | 298 | } else { |
300 | 299 | /* Okay, char or block special */ |
301 | - is_borc = 1; | |
302 | 300 | if (!rdev) |
303 | 301 | rdev = wanted; |
304 | 302 | } |
fs/nfsd/nfssvc.c
... | ... | @@ -180,15 +180,80 @@ |
180 | 180 | return rv; |
181 | 181 | } |
182 | 182 | |
183 | +static int nfsd_init_socks(int port) | |
184 | +{ | |
185 | + int error; | |
186 | + if (!list_empty(&nfsd_serv->sv_permsocks)) | |
187 | + return 0; | |
188 | + | |
189 | + error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port, | |
190 | + SVC_SOCK_DEFAULTS); | |
191 | + if (error < 0) | |
192 | + return error; | |
193 | + | |
194 | + error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port, | |
195 | + SVC_SOCK_DEFAULTS); | |
196 | + if (error < 0) | |
197 | + return error; | |
198 | + | |
199 | + return 0; | |
200 | +} | |
201 | + | |
202 | +static bool nfsd_up = false; | |
203 | + | |
204 | +static int nfsd_startup(unsigned short port, int nrservs) | |
205 | +{ | |
206 | + int ret; | |
207 | + | |
208 | + if (nfsd_up) | |
209 | + return 0; | |
210 | + /* | |
211 | + * Readahead param cache - will no-op if it already exists. | |
212 | + * (Note therefore results will be suboptimal if number of | |
213 | + * threads is modified after nfsd start.) | |
214 | + */ | |
215 | + ret = nfsd_racache_init(2*nrservs); | |
216 | + if (ret) | |
217 | + return ret; | |
218 | + ret = nfsd_init_socks(port); | |
219 | + if (ret) | |
220 | + goto out_racache; | |
221 | + ret = lockd_up(); | |
222 | + if (ret) | |
223 | + goto out_racache; | |
224 | + ret = nfs4_state_start(); | |
225 | + if (ret) | |
226 | + goto out_lockd; | |
227 | + nfsd_up = true; | |
228 | + return 0; | |
229 | +out_lockd: | |
230 | + lockd_down(); | |
231 | +out_racache: | |
232 | + nfsd_racache_shutdown(); | |
233 | + return ret; | |
234 | +} | |
235 | + | |
236 | +static void nfsd_shutdown(void) | |
237 | +{ | |
238 | + /* | |
239 | + * write_ports can create the server without actually starting | |
240 | + * any threads--if we get shut down before any threads are | |
241 | + * started, then nfsd_last_thread will be run before any of this | |
242 | + * other initialization has been done. | |
243 | + */ | |
244 | + if (!nfsd_up) | |
245 | + return; | |
246 | + nfs4_state_shutdown(); | |
247 | + lockd_down(); | |
248 | + nfsd_racache_shutdown(); | |
249 | + nfsd_up = false; | |
250 | +} | |
251 | + | |
183 | 252 | static void nfsd_last_thread(struct svc_serv *serv) |
184 | 253 | { |
185 | 254 | /* When last nfsd thread exits we need to do some clean-up */ |
186 | - struct svc_xprt *xprt; | |
187 | - list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) | |
188 | - lockd_down(); | |
189 | 255 | nfsd_serv = NULL; |
190 | - nfsd_racache_shutdown(); | |
191 | - nfs4_state_shutdown(); | |
256 | + nfsd_shutdown(); | |
192 | 257 | |
193 | 258 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
194 | 259 | "cache\n"); |
195 | 260 | |
196 | 261 | |
197 | 262 | |
... | ... | @@ -263,45 +328,18 @@ |
263 | 328 | nfsd_max_blksize >= 8*1024*2) |
264 | 329 | nfsd_max_blksize /= 2; |
265 | 330 | } |
331 | + nfsd_reset_versions(); | |
266 | 332 | |
267 | 333 | nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
268 | 334 | nfsd_last_thread, nfsd, THIS_MODULE); |
269 | 335 | if (nfsd_serv == NULL) |
270 | - err = -ENOMEM; | |
271 | - else | |
272 | - set_max_drc(); | |
336 | + return -ENOMEM; | |
273 | 337 | |
338 | + set_max_drc(); | |
274 | 339 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
275 | 340 | return err; |
276 | 341 | } |
277 | 342 | |
278 | -static int nfsd_init_socks(int port) | |
279 | -{ | |
280 | - int error; | |
281 | - if (!list_empty(&nfsd_serv->sv_permsocks)) | |
282 | - return 0; | |
283 | - | |
284 | - error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port, | |
285 | - SVC_SOCK_DEFAULTS); | |
286 | - if (error < 0) | |
287 | - return error; | |
288 | - | |
289 | - error = lockd_up(); | |
290 | - if (error < 0) | |
291 | - return error; | |
292 | - | |
293 | - error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port, | |
294 | - SVC_SOCK_DEFAULTS); | |
295 | - if (error < 0) | |
296 | - return error; | |
297 | - | |
298 | - error = lockd_up(); | |
299 | - if (error < 0) | |
300 | - return error; | |
301 | - | |
302 | - return 0; | |
303 | -} | |
304 | - | |
305 | 343 | int nfsd_nrpools(void) |
306 | 344 | { |
307 | 345 | if (nfsd_serv == NULL) |
308 | 346 | |
... | ... | @@ -376,10 +414,16 @@ |
376 | 414 | return err; |
377 | 415 | } |
378 | 416 | |
417 | +/* | |
418 | + * Adjust the number of threads and return the new number of threads. | |
419 | + * This is also the function that starts the server if necessary, if | |
420 | + * this is the first time nrservs is nonzero. | |
421 | + */ | |
379 | 422 | int |
380 | 423 | nfsd_svc(unsigned short port, int nrservs) |
381 | 424 | { |
382 | 425 | int error; |
426 | + bool nfsd_up_before; | |
383 | 427 | |
384 | 428 | mutex_lock(&nfsd_mutex); |
385 | 429 | dprintk("nfsd: creating service\n"); |
386 | 430 | |
387 | 431 | |
388 | 432 | |
389 | 433 | |
390 | 434 | |
... | ... | @@ -391,34 +435,29 @@ |
391 | 435 | if (nrservs == 0 && nfsd_serv == NULL) |
392 | 436 | goto out; |
393 | 437 | |
394 | - /* Readahead param cache - will no-op if it already exists */ | |
395 | - error = nfsd_racache_init(2*nrservs); | |
396 | - if (error<0) | |
397 | - goto out; | |
398 | - error = nfs4_state_start(); | |
438 | + error = nfsd_create_serv(); | |
399 | 439 | if (error) |
400 | 440 | goto out; |
401 | 441 | |
402 | - nfsd_reset_versions(); | |
442 | + nfsd_up_before = nfsd_up; | |
403 | 443 | |
404 | - error = nfsd_create_serv(); | |
405 | - | |
444 | + error = nfsd_startup(port, nrservs); | |
406 | 445 | if (error) |
407 | - goto out; | |
408 | - error = nfsd_init_socks(port); | |
409 | - if (error) | |
410 | - goto failure; | |
411 | - | |
446 | + goto out_destroy; | |
412 | 447 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
413 | - if (error == 0) | |
414 | - /* We are holding a reference to nfsd_serv which | |
415 | - * we don't want to count in the return value, | |
416 | - * so subtract 1 | |
417 | - */ | |
418 | - error = nfsd_serv->sv_nrthreads - 1; | |
419 | - failure: | |
448 | + if (error) | |
449 | + goto out_shutdown; | |
450 | + /* We are holding a reference to nfsd_serv which | |
451 | + * we don't want to count in the return value, | |
452 | + * so subtract 1 | |
453 | + */ | |
454 | + error = nfsd_serv->sv_nrthreads - 1; | |
455 | +out_shutdown: | |
456 | + if (error < 0 && !nfsd_up_before) | |
457 | + nfsd_shutdown(); | |
458 | +out_destroy: | |
420 | 459 | svc_destroy(nfsd_serv); /* Release server */ |
421 | - out: | |
460 | +out: | |
422 | 461 | mutex_unlock(&nfsd_mutex); |
423 | 462 | return error; |
424 | 463 | } |
fs/nfsd/state.h
... | ... | @@ -88,7 +88,6 @@ |
88 | 88 | struct nfs4_client *dl_client; |
89 | 89 | struct nfs4_file *dl_file; |
90 | 90 | struct file_lock *dl_flock; |
91 | - struct file *dl_vfs_file; | |
92 | 91 | u32 dl_type; |
93 | 92 | time_t dl_time; |
94 | 93 | /* For recall: */ |
95 | 94 | |
... | ... | @@ -342,12 +341,50 @@ |
342 | 341 | struct list_head fi_hash; /* hash by "struct inode *" */ |
343 | 342 | struct list_head fi_stateids; |
344 | 343 | struct list_head fi_delegations; |
344 | + /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ | |
345 | + struct file * fi_fds[3]; | |
346 | + /* One each for O_RDONLY, O_WRONLY: */ | |
347 | + atomic_t fi_access[2]; | |
348 | + /* | |
349 | + * Each open stateid contributes 1 to either fi_readers or | |
350 | + * fi_writers, or both, depending on the open mode. A | |
351 | + * delegation also takes an fi_readers reference. Lock | |
352 | + * stateid's take none. | |
353 | + */ | |
354 | + atomic_t fi_readers; | |
355 | + atomic_t fi_writers; | |
345 | 356 | struct inode *fi_inode; |
346 | 357 | u32 fi_id; /* used with stateowner->so_id |
347 | 358 | * for stateid_hashtbl hash */ |
348 | 359 | bool fi_had_conflict; |
349 | 360 | }; |
350 | 361 | |
362 | +/* XXX: for first cut may fall back on returning file that doesn't work | |
363 | + * at all? */ | |
364 | +static inline struct file *find_writeable_file(struct nfs4_file *f) | |
365 | +{ | |
366 | + if (f->fi_fds[O_RDWR]) | |
367 | + return f->fi_fds[O_RDWR]; | |
368 | + return f->fi_fds[O_WRONLY]; | |
369 | +} | |
370 | + | |
371 | +static inline struct file *find_readable_file(struct nfs4_file *f) | |
372 | +{ | |
373 | + if (f->fi_fds[O_RDWR]) | |
374 | + return f->fi_fds[O_RDWR]; | |
375 | + return f->fi_fds[O_RDONLY]; | |
376 | +} | |
377 | + | |
378 | +static inline struct file *find_any_file(struct nfs4_file *f) | |
379 | +{ | |
380 | + if (f->fi_fds[O_RDWR]) | |
381 | + return f->fi_fds[O_RDWR]; | |
382 | + else if (f->fi_fds[O_RDWR]) | |
383 | + return f->fi_fds[O_WRONLY]; | |
384 | + else | |
385 | + return f->fi_fds[O_RDONLY]; | |
386 | +} | |
387 | + | |
351 | 388 | /* |
352 | 389 | * nfs4_stateid can either be an open stateid or (eventually) a lock stateid |
353 | 390 | * |
... | ... | @@ -373,7 +410,6 @@ |
373 | 410 | struct nfs4_stateowner * st_stateowner; |
374 | 411 | struct nfs4_file * st_file; |
375 | 412 | stateid_t st_stateid; |
376 | - struct file * st_vfs_file; | |
377 | 413 | unsigned long st_access_bmap; |
378 | 414 | unsigned long st_deny_bmap; |
379 | 415 | struct nfs4_stateid * st_openstp; |
fs/nfsd/vfs.c
... | ... | @@ -604,7 +604,7 @@ |
604 | 604 | return error; |
605 | 605 | } |
606 | 606 | |
607 | -#endif /* defined(CONFIG_NFS_V4) */ | |
607 | +#endif /* defined(CONFIG_NFSD_V4) */ | |
608 | 608 | |
609 | 609 | #ifdef CONFIG_NFSD_V3 |
610 | 610 | /* |
... | ... | @@ -903,7 +903,6 @@ |
903 | 903 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
904 | 904 | { |
905 | 905 | struct inode *inode; |
906 | - struct raparms *ra; | |
907 | 906 | mm_segment_t oldfs; |
908 | 907 | __be32 err; |
909 | 908 | int host_err; |
... | ... | @@ -914,12 +913,6 @@ |
914 | 913 | if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) |
915 | 914 | goto out; |
916 | 915 | |
917 | - /* Get readahead parameters */ | |
918 | - ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); | |
919 | - | |
920 | - if (ra && ra->p_set) | |
921 | - file->f_ra = ra->p_ra; | |
922 | - | |
923 | 916 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { |
924 | 917 | struct splice_desc sd = { |
925 | 918 | .len = 0, |
... | ... | @@ -937,16 +930,6 @@ |
937 | 930 | set_fs(oldfs); |
938 | 931 | } |
939 | 932 | |
940 | - /* Write back readahead params */ | |
941 | - if (ra) { | |
942 | - struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; | |
943 | - spin_lock(&rab->pb_lock); | |
944 | - ra->p_ra = file->f_ra; | |
945 | - ra->p_set = 1; | |
946 | - ra->p_count--; | |
947 | - spin_unlock(&rab->pb_lock); | |
948 | - } | |
949 | - | |
950 | 933 | if (host_err >= 0) { |
951 | 934 | nfsdstats.io_read += host_err; |
952 | 935 | *count = host_err; |
953 | 936 | |
... | ... | @@ -1086,8 +1069,45 @@ |
1086 | 1069 | * on entry. On return, *count contains the number of bytes actually read. |
1087 | 1070 | * N.B. After this call fhp needs an fh_put |
1088 | 1071 | */ |
1072 | +__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, | |
1073 | + loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | |
1074 | +{ | |
1075 | + struct file *file; | |
1076 | + struct inode *inode; | |
1077 | + struct raparms *ra; | |
1078 | + __be32 err; | |
1079 | + | |
1080 | + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | |
1081 | + if (err) | |
1082 | + return err; | |
1083 | + | |
1084 | + inode = file->f_path.dentry->d_inode; | |
1085 | + | |
1086 | + /* Get readahead parameters */ | |
1087 | + ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); | |
1088 | + | |
1089 | + if (ra && ra->p_set) | |
1090 | + file->f_ra = ra->p_ra; | |
1091 | + | |
1092 | + err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); | |
1093 | + | |
1094 | + /* Write back readahead params */ | |
1095 | + if (ra) { | |
1096 | + struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; | |
1097 | + spin_lock(&rab->pb_lock); | |
1098 | + ra->p_ra = file->f_ra; | |
1099 | + ra->p_set = 1; | |
1100 | + ra->p_count--; | |
1101 | + spin_unlock(&rab->pb_lock); | |
1102 | + } | |
1103 | + | |
1104 | + nfsd_close(file); | |
1105 | + return err; | |
1106 | +} | |
1107 | + | |
1108 | +/* As above, but use the provided file descriptor. */ | |
1089 | 1109 | __be32 |
1090 | -nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |
1110 | +nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |
1091 | 1111 | loff_t offset, struct kvec *vec, int vlen, |
1092 | 1112 | unsigned long *count) |
1093 | 1113 | { |
... | ... | @@ -1099,13 +1119,8 @@ |
1099 | 1119 | if (err) |
1100 | 1120 | goto out; |
1101 | 1121 | err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); |
1102 | - } else { | |
1103 | - err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | |
1104 | - if (err) | |
1105 | - goto out; | |
1106 | - err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); | |
1107 | - nfsd_close(file); | |
1108 | - } | |
1122 | + } else /* Note file may still be NULL in NFSv4 special stateid case: */ | |
1123 | + err = nfsd_read(rqstp, fhp, offset, vec, vlen, count); | |
1109 | 1124 | out: |
1110 | 1125 | return err; |
1111 | 1126 | } |
... | ... | @@ -1631,7 +1646,7 @@ |
1631 | 1646 | char *name, int len, struct svc_fh *tfhp) |
1632 | 1647 | { |
1633 | 1648 | struct dentry *ddir, *dnew, *dold; |
1634 | - struct inode *dirp, *dest; | |
1649 | + struct inode *dirp; | |
1635 | 1650 | __be32 err; |
1636 | 1651 | int host_err; |
1637 | 1652 | |
... | ... | @@ -1659,7 +1674,6 @@ |
1659 | 1674 | goto out_nfserr; |
1660 | 1675 | |
1661 | 1676 | dold = tfhp->fh_dentry; |
1662 | - dest = dold->d_inode; | |
1663 | 1677 | |
1664 | 1678 | host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt); |
1665 | 1679 | if (host_err) { |
... | ... | @@ -2038,7 +2052,6 @@ |
2038 | 2052 | struct dentry *dentry, int acc) |
2039 | 2053 | { |
2040 | 2054 | struct inode *inode = dentry->d_inode; |
2041 | - struct path path; | |
2042 | 2055 | int err; |
2043 | 2056 | |
2044 | 2057 | if (acc == NFSD_MAY_NOP) |
2045 | 2058 | |
... | ... | @@ -2111,15 +2124,7 @@ |
2111 | 2124 | if (err == -EACCES && S_ISREG(inode->i_mode) && |
2112 | 2125 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) |
2113 | 2126 | err = inode_permission(inode, MAY_EXEC); |
2114 | - if (err) | |
2115 | - goto nfsd_out; | |
2116 | 2127 | |
2117 | - /* Do integrity (permission) checking now, but defer incrementing | |
2118 | - * IMA counts to the actual file open. | |
2119 | - */ | |
2120 | - path.mnt = exp->ex_path.mnt; | |
2121 | - path.dentry = dentry; | |
2122 | -nfsd_out: | |
2123 | 2128 | return err? nfserrno(err) : 0; |
2124 | 2129 | } |
2125 | 2130 |
fs/nfsd/vfs.h
... | ... | @@ -64,7 +64,9 @@ |
64 | 64 | __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int, |
65 | 65 | int, struct file **); |
66 | 66 | void nfsd_close(struct file *); |
67 | -__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, | |
67 | +__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, | |
68 | + loff_t, struct kvec *, int, unsigned long *); | |
69 | +__be32 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *, | |
68 | 70 | loff_t, struct kvec *, int, unsigned long *); |
69 | 71 | __be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, |
70 | 72 | loff_t, struct kvec *,int, unsigned long *, int *); |
include/linux/sunrpc/cache.h
... | ... | @@ -192,6 +192,7 @@ |
192 | 192 | extern void cache_flush(void); |
193 | 193 | extern void cache_purge(struct cache_detail *detail); |
194 | 194 | #define NEVER (0x7FFFFFFF) |
195 | +extern void __init cache_initialize(void); | |
195 | 196 | extern int cache_register(struct cache_detail *cd); |
196 | 197 | extern void cache_unregister(struct cache_detail *cd); |
197 | 198 |
net/sunrpc/cache.c
... | ... | @@ -34,7 +34,6 @@ |
34 | 34 | #include <linux/sunrpc/cache.h> |
35 | 35 | #include <linux/sunrpc/stats.h> |
36 | 36 | #include <linux/sunrpc/rpc_pipe_fs.h> |
37 | -#include <linux/smp_lock.h> | |
38 | 37 | |
39 | 38 | #define RPCDBG_FACILITY RPCDBG_CACHE |
40 | 39 | |
... | ... | @@ -320,7 +319,7 @@ |
320 | 319 | static int current_index; |
321 | 320 | |
322 | 321 | static void do_cache_clean(struct work_struct *work); |
323 | -static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); | |
322 | +static struct delayed_work cache_cleaner; | |
324 | 323 | |
325 | 324 | static void sunrpc_init_cache_detail(struct cache_detail *cd) |
326 | 325 | { |
... | ... | @@ -1503,6 +1502,11 @@ |
1503 | 1502 | return 0; |
1504 | 1503 | } |
1505 | 1504 | #endif |
1505 | + | |
1506 | +void __init cache_initialize(void) | |
1507 | +{ | |
1508 | + INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean); | |
1509 | +} | |
1506 | 1510 | |
1507 | 1511 | int cache_register(struct cache_detail *cd) |
1508 | 1512 | { |
net/sunrpc/sunrpc_syms.c