diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 755 |
1 files changed, 430 insertions, 325 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6a8fedaa4f55..2e7357104cfd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -45,13 +45,12 @@ | |||
45 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 45 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
46 | 46 | ||
47 | /* Globals */ | 47 | /* Globals */ |
48 | static time_t lease_time = 90; /* default lease time */ | 48 | time_t nfsd4_lease = 90; /* default lease time */ |
49 | static time_t user_lease_time = 90; | 49 | time_t nfsd4_grace = 90; |
50 | static time_t boot_time; | 50 | static time_t boot_time; |
51 | static u32 current_ownerid = 1; | 51 | static u32 current_ownerid = 1; |
52 | static u32 current_fileid = 1; | 52 | static u32 current_fileid = 1; |
53 | static u32 current_delegid = 1; | 53 | static u32 current_delegid = 1; |
54 | static u32 nfs4_init; | ||
55 | static stateid_t zerostateid; /* bits all 0 */ | 54 | static stateid_t zerostateid; /* bits all 0 */ |
56 | static stateid_t onestateid; /* bits all 1 */ | 55 | static stateid_t onestateid; /* bits all 1 */ |
57 | static u64 current_sessionid = 1; | 56 | static u64 current_sessionid = 1; |
@@ -163,6 +162,46 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | |||
163 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | 162 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; |
164 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | 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 | static struct nfs4_delegation * | 205 | static struct nfs4_delegation * |
167 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 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 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
171 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; | 210 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
172 | 211 | ||
173 | dprintk("NFSD alloc_init_deleg\n"); | 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 | if (fp->fi_had_conflict) | 220 | if (fp->fi_had_conflict) |
175 | return NULL; | 221 | return NULL; |
176 | if (num_delegations > max_delegations) | 222 | if (num_delegations > max_delegations) |
@@ -185,12 +231,11 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
185 | dp->dl_client = clp; | 231 | dp->dl_client = clp; |
186 | get_nfs4_file(fp); | 232 | get_nfs4_file(fp); |
187 | dp->dl_file = fp; | 233 | dp->dl_file = fp; |
234 | nfs4_file_get_access(fp, O_RDONLY); | ||
188 | dp->dl_flock = NULL; | 235 | dp->dl_flock = NULL; |
189 | get_file(stp->st_vfs_file); | ||
190 | dp->dl_vfs_file = stp->st_vfs_file; | ||
191 | dp->dl_type = type; | 236 | dp->dl_type = type; |
192 | dp->dl_ident = cb->cb_ident; | 237 | dp->dl_ident = cb->cb_ident; |
193 | dp->dl_stateid.si_boot = get_seconds(); | 238 | dp->dl_stateid.si_boot = boot_time; |
194 | dp->dl_stateid.si_stateownerid = current_delegid++; | 239 | dp->dl_stateid.si_stateownerid = current_delegid++; |
195 | dp->dl_stateid.si_fileid = 0; | 240 | dp->dl_stateid.si_fileid = 0; |
196 | dp->dl_stateid.si_generation = 0; | 241 | dp->dl_stateid.si_generation = 0; |
@@ -199,6 +244,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
199 | atomic_set(&dp->dl_count, 1); | 244 | atomic_set(&dp->dl_count, 1); |
200 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 245 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
201 | list_add(&dp->dl_perclnt, &clp->cl_delegations); | 246 | list_add(&dp->dl_perclnt, &clp->cl_delegations); |
247 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); | ||
202 | return dp; | 248 | return dp; |
203 | } | 249 | } |
204 | 250 | ||
@@ -221,15 +267,12 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
221 | static void | 267 | static void |
222 | nfs4_close_delegation(struct nfs4_delegation *dp) | 268 | nfs4_close_delegation(struct nfs4_delegation *dp) |
223 | { | 269 | { |
224 | struct file *filp = dp->dl_vfs_file; | 270 | struct file *filp = find_readable_file(dp->dl_file); |
225 | 271 | ||
226 | dprintk("NFSD: close_delegation dp %p\n",dp); | 272 | dprintk("NFSD: close_delegation dp %p\n",dp); |
227 | dp->dl_vfs_file = NULL; | ||
228 | /* The following nfsd_close may not actually close the file, | ||
229 | * but we want to remove the lease in any case. */ | ||
230 | if (dp->dl_flock) | 273 | if (dp->dl_flock) |
231 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); | 274 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); |
232 | nfsd_close(filp); | 275 | nfs4_file_put_access(dp->dl_file, O_RDONLY); |
233 | } | 276 | } |
234 | 277 | ||
235 | /* Called under the state lock. */ | 278 | /* Called under the state lock. */ |
@@ -249,6 +292,9 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
249 | * SETCLIENTID state | 292 | * SETCLIENTID state |
250 | */ | 293 | */ |
251 | 294 | ||
295 | /* client_lock protects the client lru list and session hash table */ | ||
296 | static DEFINE_SPINLOCK(client_lock); | ||
297 | |||
252 | /* Hash tables for nfs4_clientid state */ | 298 | /* Hash tables for nfs4_clientid state */ |
253 | #define CLIENT_HASH_BITS 4 | 299 | #define CLIENT_HASH_BITS 4 |
254 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) | 300 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) |
@@ -298,8 +344,12 @@ static void free_generic_stateid(struct nfs4_stateid *stp) | |||
298 | 344 | ||
299 | static void release_lock_stateid(struct nfs4_stateid *stp) | 345 | static void release_lock_stateid(struct nfs4_stateid *stp) |
300 | { | 346 | { |
347 | struct file *file; | ||
348 | |||
301 | unhash_generic_stateid(stp); | 349 | unhash_generic_stateid(stp); |
302 | 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); | ||
303 | free_generic_stateid(stp); | 353 | free_generic_stateid(stp); |
304 | } | 354 | } |
305 | 355 | ||
@@ -337,11 +387,85 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp) | |||
337 | } | 387 | } |
338 | } | 388 | } |
339 | 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 | |||
340 | static void release_open_stateid(struct nfs4_stateid *stp) | 462 | static void release_open_stateid(struct nfs4_stateid *stp) |
341 | { | 463 | { |
464 | int oflag = nfs4_access_bmap_to_omode(stp); | ||
465 | |||
342 | unhash_generic_stateid(stp); | 466 | unhash_generic_stateid(stp); |
343 | release_stateid_lockowners(stp); | 467 | release_stateid_lockowners(stp); |
344 | nfsd_close(stp->st_vfs_file); | 468 | nfs4_file_put_access(stp->st_file, oflag); |
345 | free_generic_stateid(stp); | 469 | free_generic_stateid(stp); |
346 | } | 470 | } |
347 | 471 | ||
@@ -367,7 +491,6 @@ static void release_openowner(struct nfs4_stateowner *sop) | |||
367 | nfs4_put_stateowner(sop); | 491 | nfs4_put_stateowner(sop); |
368 | } | 492 | } |
369 | 493 | ||
370 | static DEFINE_SPINLOCK(sessionid_lock); | ||
371 | #define SESSION_HASH_SIZE 512 | 494 | #define SESSION_HASH_SIZE 512 |
372 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; | 495 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; |
373 | 496 | ||
@@ -454,7 +577,7 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) | |||
454 | spin_unlock(&nfsd_drc_lock); | 577 | spin_unlock(&nfsd_drc_lock); |
455 | 578 | ||
456 | if (fchan->maxreqs == 0) | 579 | if (fchan->maxreqs == 0) |
457 | return nfserr_serverfault; | 580 | return nfserr_jukebox; |
458 | 581 | ||
459 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; | 582 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; |
460 | return 0; | 583 | return 0; |
@@ -539,7 +662,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
539 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) | 662 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) |
540 | + sizeof(struct nfsd4_session) > PAGE_SIZE); | 663 | + sizeof(struct nfsd4_session) > PAGE_SIZE); |
541 | 664 | ||
542 | status = nfserr_serverfault; | 665 | status = nfserr_jukebox; |
543 | /* allocate struct nfsd4_session and slot table pointers in one piece */ | 666 | /* allocate struct nfsd4_session and slot table pointers in one piece */ |
544 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); | 667 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); |
545 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 668 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
@@ -565,10 +688,10 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
565 | 688 | ||
566 | new->se_flags = cses->flags; | 689 | new->se_flags = cses->flags; |
567 | kref_init(&new->se_ref); | 690 | kref_init(&new->se_ref); |
568 | spin_lock(&sessionid_lock); | 691 | spin_lock(&client_lock); |
569 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | 692 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); |
570 | list_add(&new->se_perclnt, &clp->cl_sessions); | 693 | list_add(&new->se_perclnt, &clp->cl_sessions); |
571 | spin_unlock(&sessionid_lock); | 694 | spin_unlock(&client_lock); |
572 | 695 | ||
573 | status = nfs_ok; | 696 | status = nfs_ok; |
574 | out: | 697 | out: |
@@ -579,7 +702,7 @@ out_free: | |||
579 | goto out; | 702 | goto out; |
580 | } | 703 | } |
581 | 704 | ||
582 | /* caller must hold sessionid_lock */ | 705 | /* caller must hold client_lock */ |
583 | static struct nfsd4_session * | 706 | static struct nfsd4_session * |
584 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | 707 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) |
585 | { | 708 | { |
@@ -588,10 +711,8 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | |||
588 | 711 | ||
589 | dump_sessionid(__func__, sessionid); | 712 | dump_sessionid(__func__, sessionid); |
590 | idx = hash_sessionid(sessionid); | 713 | idx = hash_sessionid(sessionid); |
591 | dprintk("%s: idx is %d\n", __func__, idx); | ||
592 | /* Search in the appropriate list */ | 714 | /* Search in the appropriate list */ |
593 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { | 715 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { |
594 | dump_sessionid("list traversal", &elem->se_sessionid); | ||
595 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | 716 | if (!memcmp(elem->se_sessionid.data, sessionid->data, |
596 | NFS4_MAX_SESSIONID_LEN)) { | 717 | NFS4_MAX_SESSIONID_LEN)) { |
597 | return elem; | 718 | return elem; |
@@ -602,7 +723,7 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | |||
602 | return NULL; | 723 | return NULL; |
603 | } | 724 | } |
604 | 725 | ||
605 | /* caller must hold sessionid_lock */ | 726 | /* caller must hold client_lock */ |
606 | static void | 727 | static void |
607 | unhash_session(struct nfsd4_session *ses) | 728 | unhash_session(struct nfsd4_session *ses) |
608 | { | 729 | { |
@@ -610,15 +731,6 @@ unhash_session(struct nfsd4_session *ses) | |||
610 | list_del(&ses->se_perclnt); | 731 | list_del(&ses->se_perclnt); |
611 | } | 732 | } |
612 | 733 | ||
613 | static void | ||
614 | release_session(struct nfsd4_session *ses) | ||
615 | { | ||
616 | spin_lock(&sessionid_lock); | ||
617 | unhash_session(ses); | ||
618 | spin_unlock(&sessionid_lock); | ||
619 | nfsd4_put_session(ses); | ||
620 | } | ||
621 | |||
622 | void | 734 | void |
623 | free_session(struct kref *kref) | 735 | free_session(struct kref *kref) |
624 | { | 736 | { |
@@ -634,9 +746,18 @@ free_session(struct kref *kref) | |||
634 | kfree(ses); | 746 | kfree(ses); |
635 | } | 747 | } |
636 | 748 | ||
749 | /* must be called under the client_lock */ | ||
637 | static inline void | 750 | static inline void |
638 | renew_client(struct nfs4_client *clp) | 751 | renew_client_locked(struct nfs4_client *clp) |
639 | { | 752 | { |
753 | if (is_client_expired(clp)) { | ||
754 | dprintk("%s: client (clientid %08x/%08x) already expired\n", | ||
755 | __func__, | ||
756 | clp->cl_clientid.cl_boot, | ||
757 | clp->cl_clientid.cl_id); | ||
758 | return; | ||
759 | } | ||
760 | |||
640 | /* | 761 | /* |
641 | * Move client to the end to the LRU list. | 762 | * Move client to the end to the LRU list. |
642 | */ | 763 | */ |
@@ -647,6 +768,14 @@ renew_client(struct nfs4_client *clp) | |||
647 | clp->cl_time = get_seconds(); | 768 | clp->cl_time = get_seconds(); |
648 | } | 769 | } |
649 | 770 | ||
771 | static inline void | ||
772 | renew_client(struct nfs4_client *clp) | ||
773 | { | ||
774 | spin_lock(&client_lock); | ||
775 | renew_client_locked(clp); | ||
776 | spin_unlock(&client_lock); | ||
777 | } | ||
778 | |||
650 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ | 779 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ |
651 | static int | 780 | static int |
652 | STALE_CLIENTID(clientid_t *clid) | 781 | STALE_CLIENTID(clientid_t *clid) |
@@ -680,27 +809,9 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
680 | return clp; | 809 | return clp; |
681 | } | 810 | } |
682 | 811 | ||
683 | static void | ||
684 | shutdown_callback_client(struct nfs4_client *clp) | ||
685 | { | ||
686 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; | ||
687 | |||
688 | if (clnt) { | ||
689 | /* | ||
690 | * Callback threads take a reference on the client, so there | ||
691 | * should be no outstanding callbacks at this point. | ||
692 | */ | ||
693 | clp->cl_cb_conn.cb_client = NULL; | ||
694 | rpc_shutdown_client(clnt); | ||
695 | } | ||
696 | } | ||
697 | |||
698 | static inline void | 812 | static inline void |
699 | free_client(struct nfs4_client *clp) | 813 | free_client(struct nfs4_client *clp) |
700 | { | 814 | { |
701 | shutdown_callback_client(clp); | ||
702 | if (clp->cl_cb_xprt) | ||
703 | svc_xprt_put(clp->cl_cb_xprt); | ||
704 | if (clp->cl_cred.cr_group_info) | 815 | if (clp->cl_cred.cr_group_info) |
705 | put_group_info(clp->cl_cred.cr_group_info); | 816 | put_group_info(clp->cl_cred.cr_group_info); |
706 | kfree(clp->cl_principal); | 817 | kfree(clp->cl_principal); |
@@ -709,10 +820,33 @@ free_client(struct nfs4_client *clp) | |||
709 | } | 820 | } |
710 | 821 | ||
711 | void | 822 | void |
712 | put_nfs4_client(struct nfs4_client *clp) | 823 | release_session_client(struct nfsd4_session *session) |
713 | { | 824 | { |
714 | if (atomic_dec_and_test(&clp->cl_count)) | 825 | struct nfs4_client *clp = session->se_client; |
826 | |||
827 | if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) | ||
828 | return; | ||
829 | if (is_client_expired(clp)) { | ||
715 | free_client(clp); | 830 | free_client(clp); |
831 | session->se_client = NULL; | ||
832 | } else | ||
833 | renew_client_locked(clp); | ||
834 | spin_unlock(&client_lock); | ||
835 | } | ||
836 | |||
837 | /* must be called under the client_lock */ | ||
838 | static inline void | ||
839 | unhash_client_locked(struct nfs4_client *clp) | ||
840 | { | ||
841 | mark_client_expired(clp); | ||
842 | list_del(&clp->cl_lru); | ||
843 | while (!list_empty(&clp->cl_sessions)) { | ||
844 | struct nfsd4_session *ses; | ||
845 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | ||
846 | se_perclnt); | ||
847 | unhash_session(ses); | ||
848 | nfsd4_put_session(ses); | ||
849 | } | ||
716 | } | 850 | } |
717 | 851 | ||
718 | static void | 852 | static void |
@@ -722,9 +856,6 @@ expire_client(struct nfs4_client *clp) | |||
722 | struct nfs4_delegation *dp; | 856 | struct nfs4_delegation *dp; |
723 | struct list_head reaplist; | 857 | struct list_head reaplist; |
724 | 858 | ||
725 | dprintk("NFSD: expire_client cl_count %d\n", | ||
726 | atomic_read(&clp->cl_count)); | ||
727 | |||
728 | INIT_LIST_HEAD(&reaplist); | 859 | INIT_LIST_HEAD(&reaplist); |
729 | spin_lock(&recall_lock); | 860 | spin_lock(&recall_lock); |
730 | while (!list_empty(&clp->cl_delegations)) { | 861 | while (!list_empty(&clp->cl_delegations)) { |
@@ -740,20 +871,20 @@ expire_client(struct nfs4_client *clp) | |||
740 | list_del_init(&dp->dl_recall_lru); | 871 | list_del_init(&dp->dl_recall_lru); |
741 | unhash_delegation(dp); | 872 | unhash_delegation(dp); |
742 | } | 873 | } |
743 | list_del(&clp->cl_idhash); | ||
744 | list_del(&clp->cl_strhash); | ||
745 | list_del(&clp->cl_lru); | ||
746 | while (!list_empty(&clp->cl_openowners)) { | 874 | while (!list_empty(&clp->cl_openowners)) { |
747 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); | 875 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); |
748 | release_openowner(sop); | 876 | release_openowner(sop); |
749 | } | 877 | } |
750 | while (!list_empty(&clp->cl_sessions)) { | 878 | nfsd4_set_callback_client(clp, NULL); |
751 | struct nfsd4_session *ses; | 879 | if (clp->cl_cb_conn.cb_xprt) |
752 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 880 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); |
753 | se_perclnt); | 881 | list_del(&clp->cl_idhash); |
754 | release_session(ses); | 882 | list_del(&clp->cl_strhash); |
755 | } | 883 | spin_lock(&client_lock); |
756 | put_nfs4_client(clp); | 884 | unhash_client_locked(clp); |
885 | if (atomic_read(&clp->cl_refcount) == 0) | ||
886 | free_client(clp); | ||
887 | spin_unlock(&client_lock); | ||
757 | } | 888 | } |
758 | 889 | ||
759 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) | 890 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) |
@@ -839,14 +970,15 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
839 | } | 970 | } |
840 | 971 | ||
841 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 972 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
842 | atomic_set(&clp->cl_count, 1); | 973 | atomic_set(&clp->cl_refcount, 0); |
843 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | 974 | atomic_set(&clp->cl_cb_set, 0); |
844 | INIT_LIST_HEAD(&clp->cl_idhash); | 975 | INIT_LIST_HEAD(&clp->cl_idhash); |
845 | INIT_LIST_HEAD(&clp->cl_strhash); | 976 | INIT_LIST_HEAD(&clp->cl_strhash); |
846 | INIT_LIST_HEAD(&clp->cl_openowners); | 977 | INIT_LIST_HEAD(&clp->cl_openowners); |
847 | INIT_LIST_HEAD(&clp->cl_delegations); | 978 | INIT_LIST_HEAD(&clp->cl_delegations); |
848 | INIT_LIST_HEAD(&clp->cl_sessions); | 979 | INIT_LIST_HEAD(&clp->cl_sessions); |
849 | INIT_LIST_HEAD(&clp->cl_lru); | 980 | INIT_LIST_HEAD(&clp->cl_lru); |
981 | clp->cl_time = get_seconds(); | ||
850 | clear_bit(0, &clp->cl_cb_slot_busy); | 982 | clear_bit(0, &clp->cl_cb_slot_busy); |
851 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 983 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
852 | copy_verf(clp, verf); | 984 | copy_verf(clp, verf); |
@@ -877,8 +1009,7 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | |||
877 | list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); | 1009 | list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); |
878 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1010 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
879 | list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); | 1011 | list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); |
880 | list_add_tail(&clp->cl_lru, &client_lru); | 1012 | renew_client(clp); |
881 | clp->cl_time = get_seconds(); | ||
882 | } | 1013 | } |
883 | 1014 | ||
884 | static void | 1015 | static void |
@@ -888,10 +1019,9 @@ move_to_confirmed(struct nfs4_client *clp) | |||
888 | unsigned int strhashval; | 1019 | unsigned int strhashval; |
889 | 1020 | ||
890 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); | 1021 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); |
891 | list_del_init(&clp->cl_strhash); | ||
892 | list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); | 1022 | list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); |
893 | strhashval = clientstr_hashval(clp->cl_recdir); | 1023 | strhashval = clientstr_hashval(clp->cl_recdir); |
894 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); | 1024 | list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); |
895 | renew_client(clp); | 1025 | renew_client(clp); |
896 | } | 1026 | } |
897 | 1027 | ||
@@ -1207,7 +1337,7 @@ out_new: | |||
1207 | /* Normal case */ | 1337 | /* Normal case */ |
1208 | new = create_client(exid->clname, dname, rqstp, &verf); | 1338 | new = create_client(exid->clname, dname, rqstp, &verf); |
1209 | if (new == NULL) { | 1339 | if (new == NULL) { |
1210 | status = nfserr_serverfault; | 1340 | status = nfserr_jukebox; |
1211 | goto out; | 1341 | goto out; |
1212 | } | 1342 | } |
1213 | 1343 | ||
@@ -1327,15 +1457,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1327 | cs_slot->sl_seqid++; /* from 0 to 1 */ | 1457 | cs_slot->sl_seqid++; /* from 0 to 1 */ |
1328 | move_to_confirmed(unconf); | 1458 | move_to_confirmed(unconf); |
1329 | 1459 | ||
1330 | /* | ||
1331 | * We do not support RDMA or persistent sessions | ||
1332 | */ | ||
1333 | cr_ses->flags &= ~SESSION4_PERSIST; | ||
1334 | cr_ses->flags &= ~SESSION4_RDMA; | ||
1335 | |||
1336 | if (cr_ses->flags & SESSION4_BACK_CHAN) { | 1460 | if (cr_ses->flags & SESSION4_BACK_CHAN) { |
1337 | unconf->cl_cb_xprt = rqstp->rq_xprt; | 1461 | unconf->cl_cb_conn.cb_xprt = rqstp->rq_xprt; |
1338 | svc_xprt_get(unconf->cl_cb_xprt); | 1462 | svc_xprt_get(rqstp->rq_xprt); |
1339 | rpc_copy_addr( | 1463 | rpc_copy_addr( |
1340 | (struct sockaddr *)&unconf->cl_cb_conn.cb_addr, | 1464 | (struct sockaddr *)&unconf->cl_cb_conn.cb_addr, |
1341 | sa); | 1465 | sa); |
@@ -1344,7 +1468,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1344 | cstate->minorversion; | 1468 | cstate->minorversion; |
1345 | unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; | 1469 | unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; |
1346 | unconf->cl_cb_seq_nr = 1; | 1470 | unconf->cl_cb_seq_nr = 1; |
1347 | nfsd4_probe_callback(unconf); | 1471 | nfsd4_probe_callback(unconf, &unconf->cl_cb_conn); |
1348 | } | 1472 | } |
1349 | conf = unconf; | 1473 | conf = unconf; |
1350 | } else { | 1474 | } else { |
@@ -1352,6 +1476,12 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1352 | goto out; | 1476 | goto out; |
1353 | } | 1477 | } |
1354 | 1478 | ||
1479 | /* | ||
1480 | * We do not support RDMA or persistent sessions | ||
1481 | */ | ||
1482 | cr_ses->flags &= ~SESSION4_PERSIST; | ||
1483 | cr_ses->flags &= ~SESSION4_RDMA; | ||
1484 | |||
1355 | status = alloc_init_session(rqstp, conf, cr_ses); | 1485 | status = alloc_init_session(rqstp, conf, cr_ses); |
1356 | if (status) | 1486 | if (status) |
1357 | goto out; | 1487 | goto out; |
@@ -1369,6 +1499,21 @@ out: | |||
1369 | return status; | 1499 | return status; |
1370 | } | 1500 | } |
1371 | 1501 | ||
1502 | static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | ||
1503 | { | ||
1504 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1505 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
1506 | |||
1507 | return argp->opcnt == resp->opcnt; | ||
1508 | } | ||
1509 | |||
1510 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) | ||
1511 | { | ||
1512 | if (!session) | ||
1513 | return 0; | ||
1514 | return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); | ||
1515 | } | ||
1516 | |||
1372 | __be32 | 1517 | __be32 |
1373 | nfsd4_destroy_session(struct svc_rqst *r, | 1518 | nfsd4_destroy_session(struct svc_rqst *r, |
1374 | struct nfsd4_compound_state *cstate, | 1519 | struct nfsd4_compound_state *cstate, |
@@ -1384,19 +1529,25 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1384 | * - Do we need to clear any callback info from previous session? | 1529 | * - Do we need to clear any callback info from previous session? |
1385 | */ | 1530 | */ |
1386 | 1531 | ||
1532 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { | ||
1533 | if (!nfsd4_last_compound_op(r)) | ||
1534 | return nfserr_not_only_op; | ||
1535 | } | ||
1387 | dump_sessionid(__func__, &sessionid->sessionid); | 1536 | dump_sessionid(__func__, &sessionid->sessionid); |
1388 | spin_lock(&sessionid_lock); | 1537 | spin_lock(&client_lock); |
1389 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); | 1538 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); |
1390 | if (!ses) { | 1539 | if (!ses) { |
1391 | spin_unlock(&sessionid_lock); | 1540 | spin_unlock(&client_lock); |
1392 | goto out; | 1541 | goto out; |
1393 | } | 1542 | } |
1394 | 1543 | ||
1395 | unhash_session(ses); | 1544 | unhash_session(ses); |
1396 | spin_unlock(&sessionid_lock); | 1545 | spin_unlock(&client_lock); |
1397 | 1546 | ||
1547 | nfs4_lock_state(); | ||
1398 | /* wait for callbacks */ | 1548 | /* wait for callbacks */ |
1399 | shutdown_callback_client(ses->se_client); | 1549 | nfsd4_set_callback_client(ses->se_client, NULL); |
1550 | nfs4_unlock_state(); | ||
1400 | nfsd4_put_session(ses); | 1551 | nfsd4_put_session(ses); |
1401 | status = nfs_ok; | 1552 | status = nfs_ok; |
1402 | out: | 1553 | out: |
@@ -1417,7 +1568,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1417 | if (resp->opcnt != 1) | 1568 | if (resp->opcnt != 1) |
1418 | return nfserr_sequence_pos; | 1569 | return nfserr_sequence_pos; |
1419 | 1570 | ||
1420 | spin_lock(&sessionid_lock); | 1571 | spin_lock(&client_lock); |
1421 | status = nfserr_badsession; | 1572 | status = nfserr_badsession; |
1422 | session = find_in_sessionid_hashtbl(&seq->sessionid); | 1573 | session = find_in_sessionid_hashtbl(&seq->sessionid); |
1423 | if (!session) | 1574 | if (!session) |
@@ -1456,23 +1607,47 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1456 | cstate->slot = slot; | 1607 | cstate->slot = slot; |
1457 | cstate->session = session; | 1608 | cstate->session = session; |
1458 | 1609 | ||
1459 | /* Hold a session reference until done processing the compound: | ||
1460 | * nfsd4_put_session called only if the cstate slot is set. | ||
1461 | */ | ||
1462 | nfsd4_get_session(session); | ||
1463 | out: | 1610 | out: |
1464 | spin_unlock(&sessionid_lock); | 1611 | /* Hold a session reference until done processing the compound. */ |
1465 | /* Renew the clientid on success and on replay */ | ||
1466 | if (cstate->session) { | 1612 | if (cstate->session) { |
1467 | nfs4_lock_state(); | 1613 | nfsd4_get_session(cstate->session); |
1468 | renew_client(session->se_client); | 1614 | atomic_inc(&session->se_client->cl_refcount); |
1469 | nfs4_unlock_state(); | ||
1470 | } | 1615 | } |
1616 | spin_unlock(&client_lock); | ||
1471 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 1617 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
1472 | return status; | 1618 | return status; |
1473 | } | 1619 | } |
1474 | 1620 | ||
1475 | __be32 | 1621 | __be32 |
1622 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | ||
1623 | { | ||
1624 | if (rc->rca_one_fs) { | ||
1625 | if (!cstate->current_fh.fh_dentry) | ||
1626 | return nfserr_nofilehandle; | ||
1627 | /* | ||
1628 | * We don't take advantage of the rca_one_fs case. | ||
1629 | * That's OK, it's optional, we can safely ignore it. | ||
1630 | */ | ||
1631 | return nfs_ok; | ||
1632 | } | ||
1633 | nfs4_lock_state(); | ||
1634 | if (is_client_expired(cstate->session->se_client)) { | ||
1635 | nfs4_unlock_state(); | ||
1636 | /* | ||
1637 | * The following error isn't really legal. | ||
1638 | * But we only get here if the client just explicitly | ||
1639 | * destroyed the client. Surely it no longer cares what | ||
1640 | * error it gets back on an operation for the dead | ||
1641 | * client. | ||
1642 | */ | ||
1643 | return nfserr_stale_clientid; | ||
1644 | } | ||
1645 | nfsd4_create_clid_dir(cstate->session->se_client); | ||
1646 | nfs4_unlock_state(); | ||
1647 | return nfs_ok; | ||
1648 | } | ||
1649 | |||
1650 | __be32 | ||
1476 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1651 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1477 | struct nfsd4_setclientid *setclid) | 1652 | struct nfsd4_setclientid *setclid) |
1478 | { | 1653 | { |
@@ -1631,9 +1806,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1631 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 1806 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) |
1632 | status = nfserr_clid_inuse; | 1807 | status = nfserr_clid_inuse; |
1633 | else { | 1808 | else { |
1634 | /* XXX: We just turn off callbacks until we can handle | 1809 | atomic_set(&conf->cl_cb_set, 0); |
1635 | * change request correctly. */ | 1810 | nfsd4_probe_callback(conf, &unconf->cl_cb_conn); |
1636 | atomic_set(&conf->cl_cb_conn.cb_set, 0); | ||
1637 | expire_client(unconf); | 1811 | expire_client(unconf); |
1638 | status = nfs_ok; | 1812 | status = nfs_ok; |
1639 | 1813 | ||
@@ -1667,7 +1841,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1667 | } | 1841 | } |
1668 | move_to_confirmed(unconf); | 1842 | move_to_confirmed(unconf); |
1669 | conf = unconf; | 1843 | conf = unconf; |
1670 | nfsd4_probe_callback(conf); | 1844 | nfsd4_probe_callback(conf, &conf->cl_cb_conn); |
1671 | status = nfs_ok; | 1845 | status = nfs_ok; |
1672 | } | 1846 | } |
1673 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | 1847 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) |
@@ -1700,12 +1874,14 @@ alloc_init_file(struct inode *ino) | |||
1700 | INIT_LIST_HEAD(&fp->fi_hash); | 1874 | INIT_LIST_HEAD(&fp->fi_hash); |
1701 | INIT_LIST_HEAD(&fp->fi_stateids); | 1875 | INIT_LIST_HEAD(&fp->fi_stateids); |
1702 | INIT_LIST_HEAD(&fp->fi_delegations); | 1876 | INIT_LIST_HEAD(&fp->fi_delegations); |
1703 | spin_lock(&recall_lock); | ||
1704 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | ||
1705 | spin_unlock(&recall_lock); | ||
1706 | fp->fi_inode = igrab(ino); | 1877 | fp->fi_inode = igrab(ino); |
1707 | fp->fi_id = current_fileid++; | 1878 | fp->fi_id = current_fileid++; |
1708 | fp->fi_had_conflict = false; | 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)); | ||
1882 | spin_lock(&recall_lock); | ||
1883 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | ||
1884 | spin_unlock(&recall_lock); | ||
1709 | return fp; | 1885 | return fp; |
1710 | } | 1886 | } |
1711 | return NULL; | 1887 | return NULL; |
@@ -1827,7 +2003,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1827 | stp->st_stateowner = sop; | 2003 | stp->st_stateowner = sop; |
1828 | get_nfs4_file(fp); | 2004 | get_nfs4_file(fp); |
1829 | stp->st_file = fp; | 2005 | stp->st_file = fp; |
1830 | stp->st_stateid.si_boot = get_seconds(); | 2006 | stp->st_stateid.si_boot = boot_time; |
1831 | stp->st_stateid.si_stateownerid = sop->so_id; | 2007 | stp->st_stateid.si_stateownerid = sop->so_id; |
1832 | stp->st_stateid.si_fileid = fp->fi_id; | 2008 | stp->st_stateid.si_fileid = fp->fi_id; |
1833 | stp->st_stateid.si_generation = 0; | 2009 | stp->st_stateid.si_generation = 0; |
@@ -1914,57 +2090,6 @@ static inline int deny_valid(u32 x) | |||
1914 | } | 2090 | } |
1915 | 2091 | ||
1916 | /* | 2092 | /* |
1917 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | ||
1918 | * st_{access,deny}_bmap field of the stateid, in order to track not | ||
1919 | * only what share bits are currently in force, but also what | ||
1920 | * combinations of share bits previous opens have used. This allows us | ||
1921 | * to enforce the recommendation of rfc 3530 14.2.19 that the server | ||
1922 | * return an error if the client attempt to downgrade to a combination | ||
1923 | * of share bits not explicable by closing some of its previous opens. | ||
1924 | * | ||
1925 | * XXX: This enforcement is actually incomplete, since we don't keep | ||
1926 | * track of access/deny bit combinations; so, e.g., we allow: | ||
1927 | * | ||
1928 | * OPEN allow read, deny write | ||
1929 | * OPEN allow both, deny none | ||
1930 | * DOWNGRADE allow read, deny none | ||
1931 | * | ||
1932 | * which we should reject. | ||
1933 | */ | ||
1934 | static void | ||
1935 | set_access(unsigned int *access, unsigned long bmap) { | ||
1936 | int i; | ||
1937 | |||
1938 | *access = 0; | ||
1939 | for (i = 1; i < 4; i++) { | ||
1940 | if (test_bit(i, &bmap)) | ||
1941 | *access |= i; | ||
1942 | } | ||
1943 | } | ||
1944 | |||
1945 | static void | ||
1946 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
1947 | int i; | ||
1948 | |||
1949 | *deny = 0; | ||
1950 | for (i = 0; i < 4; i++) { | ||
1951 | if (test_bit(i, &bmap)) | ||
1952 | *deny |= i ; | ||
1953 | } | ||
1954 | } | ||
1955 | |||
1956 | static int | ||
1957 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | ||
1958 | unsigned int access, deny; | ||
1959 | |||
1960 | set_access(&access, stp->st_access_bmap); | ||
1961 | set_deny(&deny, stp->st_deny_bmap); | ||
1962 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
1963 | return 0; | ||
1964 | return 1; | ||
1965 | } | ||
1966 | |||
1967 | /* | ||
1968 | * Called to check deny when READ with all zero stateid or | 2093 | * Called to check deny when READ with all zero stateid or |
1969 | * WRITE with all zero or all one stateid | 2094 | * WRITE with all zero or all one stateid |
1970 | */ | 2095 | */ |
@@ -1995,14 +2120,12 @@ out: | |||
1995 | } | 2120 | } |
1996 | 2121 | ||
1997 | static inline void | 2122 | static inline void |
1998 | nfs4_file_downgrade(struct file *filp, unsigned int share_access) | 2123 | nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) |
1999 | { | 2124 | { |
2000 | if (share_access & NFS4_SHARE_ACCESS_WRITE) { | 2125 | if (share_access & NFS4_SHARE_ACCESS_WRITE) |
2001 | drop_file_write_access(filp); | 2126 | nfs4_file_put_access(fp, O_WRONLY); |
2002 | spin_lock(&filp->f_lock); | 2127 | if (share_access & NFS4_SHARE_ACCESS_READ) |
2003 | filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; | 2128 | nfs4_file_put_access(fp, O_RDONLY); |
2004 | spin_unlock(&filp->f_lock); | ||
2005 | } | ||
2006 | } | 2129 | } |
2007 | 2130 | ||
2008 | /* | 2131 | /* |
@@ -2028,7 +2151,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2028 | * lock) we know the server hasn't removed the lease yet, we know | 2151 | * lock) we know the server hasn't removed the lease yet, we know |
2029 | * it's safe to take a reference: */ | 2152 | * it's safe to take a reference: */ |
2030 | atomic_inc(&dp->dl_count); | 2153 | atomic_inc(&dp->dl_count); |
2031 | atomic_inc(&dp->dl_client->cl_count); | ||
2032 | 2154 | ||
2033 | spin_lock(&recall_lock); | 2155 | spin_lock(&recall_lock); |
2034 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); | 2156 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); |
@@ -2199,6 +2321,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | |||
2199 | return NULL; | 2321 | return NULL; |
2200 | } | 2322 | } |
2201 | 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 | |||
2202 | static __be32 | 2331 | static __be32 |
2203 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | 2332 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, |
2204 | struct nfs4_delegation **dp) | 2333 | struct nfs4_delegation **dp) |
@@ -2209,8 +2338,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | |||
2209 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); | 2338 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); |
2210 | if (*dp == NULL) | 2339 | if (*dp == NULL) |
2211 | goto out; | 2340 | goto out; |
2212 | flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ? | 2341 | flags = share_access_to_flags(open->op_share_access); |
2213 | RD_STATE : WR_STATE; | ||
2214 | status = nfs4_check_delegmode(*dp, flags); | 2342 | status = nfs4_check_delegmode(*dp, flags); |
2215 | if (status) | 2343 | if (status) |
2216 | *dp = NULL; | 2344 | *dp = NULL; |
@@ -2252,30 +2380,53 @@ nfs4_alloc_stateid(void) | |||
2252 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); | 2380 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); |
2253 | } | 2381 | } |
2254 | 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 | |||
2255 | static __be32 | 2414 | static __be32 |
2256 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | 2415 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, |
2257 | struct nfs4_delegation *dp, | 2416 | struct nfs4_file *fp, struct svc_fh *cur_fh, |
2258 | struct svc_fh *cur_fh, int flags) | 2417 | struct nfsd4_open *open) |
2259 | { | 2418 | { |
2260 | struct nfs4_stateid *stp; | 2419 | struct nfs4_stateid *stp; |
2420 | __be32 status; | ||
2261 | 2421 | ||
2262 | stp = nfs4_alloc_stateid(); | 2422 | stp = nfs4_alloc_stateid(); |
2263 | if (stp == NULL) | 2423 | if (stp == NULL) |
2264 | return nfserr_resource; | 2424 | return nfserr_resource; |
2265 | 2425 | ||
2266 | if (dp) { | 2426 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); |
2267 | get_file(dp->dl_vfs_file); | 2427 | if (status) { |
2268 | stp->st_vfs_file = dp->dl_vfs_file; | 2428 | kmem_cache_free(stateid_slab, stp); |
2269 | } else { | 2429 | return status; |
2270 | __be32 status; | ||
2271 | status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, | ||
2272 | &stp->st_vfs_file); | ||
2273 | if (status) { | ||
2274 | if (status == nfserr_dropit) | ||
2275 | status = nfserr_jukebox; | ||
2276 | kmem_cache_free(stateid_slab, stp); | ||
2277 | return status; | ||
2278 | } | ||
2279 | } | 2430 | } |
2280 | *stpp = stp; | 2431 | *stpp = stp; |
2281 | return 0; | 2432 | return 0; |
@@ -2297,35 +2448,30 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
2297 | } | 2448 | } |
2298 | 2449 | ||
2299 | static __be32 | 2450 | static __be32 |
2300 | 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) |
2301 | { | 2452 | { |
2302 | struct file *filp = stp->st_vfs_file; | 2453 | u32 op_share_access, new_access; |
2303 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
2304 | unsigned int share_access, new_writer; | ||
2305 | __be32 status; | 2454 | __be32 status; |
2306 | 2455 | ||
2307 | set_access(&share_access, stp->st_access_bmap); | 2456 | set_access(&new_access, stp->st_access_bmap); |
2308 | new_writer = (~share_access) & open->op_share_access | 2457 | new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2309 | & NFS4_SHARE_ACCESS_WRITE; | 2458 | |
2310 | 2459 | if (new_access) { | |
2311 | if (new_writer) { | 2460 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access); |
2312 | int err = get_write_access(inode); | 2461 | if (status) |
2313 | if (err) | 2462 | return status; |
2314 | return nfserrno(err); | ||
2315 | err = mnt_want_write(cur_fh->fh_export->ex_path.mnt); | ||
2316 | if (err) | ||
2317 | return nfserrno(err); | ||
2318 | file_take_write(filp); | ||
2319 | } | 2463 | } |
2320 | status = nfsd4_truncate(rqstp, cur_fh, open); | 2464 | status = nfsd4_truncate(rqstp, cur_fh, open); |
2321 | if (status) { | 2465 | if (status) { |
2322 | if (new_writer) | 2466 | if (new_access) { |
2323 | put_write_access(inode); | 2467 | int oflag = nfs4_access_to_omode(new_access); |
2468 | nfs4_file_put_access(fp, oflag); | ||
2469 | } | ||
2324 | return status; | 2470 | return status; |
2325 | } | 2471 | } |
2326 | /* remember the open */ | 2472 | /* remember the open */ |
2327 | filp->f_mode |= open->op_share_access; | 2473 | op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2328 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 2474 | __set_bit(op_share_access, &stp->st_access_bmap); |
2329 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2475 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2330 | 2476 | ||
2331 | return nfs_ok; | 2477 | return nfs_ok; |
@@ -2347,7 +2493,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2347 | { | 2493 | { |
2348 | struct nfs4_delegation *dp; | 2494 | struct nfs4_delegation *dp; |
2349 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2495 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2350 | struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn; | 2496 | int cb_up = atomic_read(&sop->so_client->cl_cb_set); |
2351 | struct file_lock fl, *flp = &fl; | 2497 | struct file_lock fl, *flp = &fl; |
2352 | int status, flag = 0; | 2498 | int status, flag = 0; |
2353 | 2499 | ||
@@ -2355,7 +2501,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2355 | open->op_recall = 0; | 2501 | open->op_recall = 0; |
2356 | switch (open->op_claim_type) { | 2502 | switch (open->op_claim_type) { |
2357 | case NFS4_OPEN_CLAIM_PREVIOUS: | 2503 | case NFS4_OPEN_CLAIM_PREVIOUS: |
2358 | if (!atomic_read(&cb->cb_set)) | 2504 | if (!cb_up) |
2359 | open->op_recall = 1; | 2505 | open->op_recall = 1; |
2360 | flag = open->op_delegate_type; | 2506 | flag = open->op_delegate_type; |
2361 | if (flag == NFS4_OPEN_DELEGATE_NONE) | 2507 | if (flag == NFS4_OPEN_DELEGATE_NONE) |
@@ -2366,7 +2512,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2366 | * had the chance to reclaim theirs.... */ | 2512 | * had the chance to reclaim theirs.... */ |
2367 | if (locks_in_grace()) | 2513 | if (locks_in_grace()) |
2368 | goto out; | 2514 | goto out; |
2369 | if (!atomic_read(&cb->cb_set) || !sop->so_confirmed) | 2515 | if (!cb_up || !sop->so_confirmed) |
2370 | goto out; | 2516 | goto out; |
2371 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 2517 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
2372 | flag = NFS4_OPEN_DELEGATE_WRITE; | 2518 | flag = NFS4_OPEN_DELEGATE_WRITE; |
@@ -2388,13 +2534,14 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2388 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | 2534 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; |
2389 | fl.fl_end = OFFSET_MAX; | 2535 | fl.fl_end = OFFSET_MAX; |
2390 | fl.fl_owner = (fl_owner_t)dp; | 2536 | fl.fl_owner = (fl_owner_t)dp; |
2391 | fl.fl_file = stp->st_vfs_file; | 2537 | fl.fl_file = find_readable_file(stp->st_file); |
2538 | BUG_ON(!fl.fl_file); | ||
2392 | fl.fl_pid = current->tgid; | 2539 | fl.fl_pid = current->tgid; |
2393 | 2540 | ||
2394 | /* vfs_setlease checks to see if delegation should be handed out. | 2541 | /* vfs_setlease checks to see if delegation should be handed out. |
2395 | * the lock_manager callbacks fl_mylease and fl_change are used | 2542 | * the lock_manager callbacks fl_mylease and fl_change are used |
2396 | */ | 2543 | */ |
2397 | if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) { | 2544 | if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) { |
2398 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 2545 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
2399 | unhash_delegation(dp); | 2546 | unhash_delegation(dp); |
2400 | flag = NFS4_OPEN_DELEGATE_NONE; | 2547 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -2458,18 +2605,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2458 | */ | 2605 | */ |
2459 | if (stp) { | 2606 | if (stp) { |
2460 | /* Stateid was found, this is an OPEN upgrade */ | 2607 | /* Stateid was found, this is an OPEN upgrade */ |
2461 | status = nfs4_upgrade_open(rqstp, current_fh, stp, open); | 2608 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
2462 | if (status) | 2609 | if (status) |
2463 | goto out; | 2610 | goto out; |
2464 | update_stateid(&stp->st_stateid); | 2611 | update_stateid(&stp->st_stateid); |
2465 | } else { | 2612 | } else { |
2466 | /* Stateid was not found, this is a new OPEN */ | 2613 | status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); |
2467 | int flags = 0; | ||
2468 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) | ||
2469 | flags |= NFSD_MAY_READ; | ||
2470 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | ||
2471 | flags |= NFSD_MAY_WRITE; | ||
2472 | status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); | ||
2473 | if (status) | 2614 | if (status) |
2474 | goto out; | 2615 | goto out; |
2475 | init_stateid(stp, fp, open); | 2616 | init_stateid(stp, fp, open); |
@@ -2483,10 +2624,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2483 | } | 2624 | } |
2484 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2625 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); |
2485 | 2626 | ||
2486 | if (nfsd4_has_session(&resp->cstate)) { | 2627 | if (nfsd4_has_session(&resp->cstate)) |
2487 | open->op_stateowner->so_confirmed = 1; | 2628 | open->op_stateowner->so_confirmed = 1; |
2488 | nfsd4_create_clid_dir(open->op_stateowner->so_client); | ||
2489 | } | ||
2490 | 2629 | ||
2491 | /* | 2630 | /* |
2492 | * Attempt to hand out a delegation. No error return, because the | 2631 | * Attempt to hand out a delegation. No error return, because the |
@@ -2537,7 +2676,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2537 | renew_client(clp); | 2676 | renew_client(clp); |
2538 | status = nfserr_cb_path_down; | 2677 | status = nfserr_cb_path_down; |
2539 | if (!list_empty(&clp->cl_delegations) | 2678 | if (!list_empty(&clp->cl_delegations) |
2540 | && !atomic_read(&clp->cl_cb_conn.cb_set)) | 2679 | && !atomic_read(&clp->cl_cb_set)) |
2541 | goto out; | 2680 | goto out; |
2542 | status = nfs_ok; | 2681 | status = nfs_ok; |
2543 | out: | 2682 | out: |
@@ -2554,6 +2693,12 @@ nfsd4_end_grace(void) | |||
2554 | dprintk("NFSD: end of grace period\n"); | 2693 | dprintk("NFSD: end of grace period\n"); |
2555 | nfsd4_recdir_purge_old(); | 2694 | nfsd4_recdir_purge_old(); |
2556 | locks_end_grace(&nfsd4_manager); | 2695 | locks_end_grace(&nfsd4_manager); |
2696 | /* | ||
2697 | * Now that every NFSv4 client has had the chance to recover and | ||
2698 | * to see the (possibly new, possibly shorter) lease time, we | ||
2699 | * can safely set the next grace time to the current lease time: | ||
2700 | */ | ||
2701 | nfsd4_grace = nfsd4_lease; | ||
2557 | } | 2702 | } |
2558 | 2703 | ||
2559 | static time_t | 2704 | static time_t |
@@ -2563,15 +2708,17 @@ nfs4_laundromat(void) | |||
2563 | struct nfs4_stateowner *sop; | 2708 | struct nfs4_stateowner *sop; |
2564 | struct nfs4_delegation *dp; | 2709 | struct nfs4_delegation *dp; |
2565 | struct list_head *pos, *next, reaplist; | 2710 | struct list_head *pos, *next, reaplist; |
2566 | time_t cutoff = get_seconds() - NFSD_LEASE_TIME; | 2711 | time_t cutoff = get_seconds() - nfsd4_lease; |
2567 | time_t t, clientid_val = NFSD_LEASE_TIME; | 2712 | time_t t, clientid_val = nfsd4_lease; |
2568 | time_t u, test_val = NFSD_LEASE_TIME; | 2713 | time_t u, test_val = nfsd4_lease; |
2569 | 2714 | ||
2570 | nfs4_lock_state(); | 2715 | nfs4_lock_state(); |
2571 | 2716 | ||
2572 | dprintk("NFSD: laundromat service - starting\n"); | 2717 | dprintk("NFSD: laundromat service - starting\n"); |
2573 | if (locks_in_grace()) | 2718 | if (locks_in_grace()) |
2574 | nfsd4_end_grace(); | 2719 | nfsd4_end_grace(); |
2720 | INIT_LIST_HEAD(&reaplist); | ||
2721 | spin_lock(&client_lock); | ||
2575 | list_for_each_safe(pos, next, &client_lru) { | 2722 | list_for_each_safe(pos, next, &client_lru) { |
2576 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 2723 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
2577 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { | 2724 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { |
@@ -2580,12 +2727,22 @@ nfs4_laundromat(void) | |||
2580 | clientid_val = t; | 2727 | clientid_val = t; |
2581 | break; | 2728 | break; |
2582 | } | 2729 | } |
2730 | if (atomic_read(&clp->cl_refcount)) { | ||
2731 | dprintk("NFSD: client in use (clientid %08x)\n", | ||
2732 | clp->cl_clientid.cl_id); | ||
2733 | continue; | ||
2734 | } | ||
2735 | unhash_client_locked(clp); | ||
2736 | list_add(&clp->cl_lru, &reaplist); | ||
2737 | } | ||
2738 | spin_unlock(&client_lock); | ||
2739 | list_for_each_safe(pos, next, &reaplist) { | ||
2740 | clp = list_entry(pos, struct nfs4_client, cl_lru); | ||
2583 | dprintk("NFSD: purging unused client (clientid %08x)\n", | 2741 | dprintk("NFSD: purging unused client (clientid %08x)\n", |
2584 | clp->cl_clientid.cl_id); | 2742 | clp->cl_clientid.cl_id); |
2585 | nfsd4_remove_clid_dir(clp); | 2743 | nfsd4_remove_clid_dir(clp); |
2586 | expire_client(clp); | 2744 | expire_client(clp); |
2587 | } | 2745 | } |
2588 | INIT_LIST_HEAD(&reaplist); | ||
2589 | spin_lock(&recall_lock); | 2746 | spin_lock(&recall_lock); |
2590 | list_for_each_safe(pos, next, &del_recall_lru) { | 2747 | list_for_each_safe(pos, next, &del_recall_lru) { |
2591 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 2748 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
@@ -2605,7 +2762,7 @@ nfs4_laundromat(void) | |||
2605 | list_del_init(&dp->dl_recall_lru); | 2762 | list_del_init(&dp->dl_recall_lru); |
2606 | unhash_delegation(dp); | 2763 | unhash_delegation(dp); |
2607 | } | 2764 | } |
2608 | test_val = NFSD_LEASE_TIME; | 2765 | test_val = nfsd4_lease; |
2609 | list_for_each_safe(pos, next, &close_lru) { | 2766 | list_for_each_safe(pos, next, &close_lru) { |
2610 | sop = list_entry(pos, struct nfs4_stateowner, so_close_lru); | 2767 | sop = list_entry(pos, struct nfs4_stateowner, so_close_lru); |
2611 | if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) { | 2768 | if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) { |
@@ -2655,45 +2812,17 @@ search_close_lru(u32 st_id, int flags) | |||
2655 | static inline int | 2812 | static inline int |
2656 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | 2813 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) |
2657 | { | 2814 | { |
2658 | 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; |
2659 | } | 2816 | } |
2660 | 2817 | ||
2661 | static int | 2818 | static int |
2662 | STALE_STATEID(stateid_t *stateid) | 2819 | STALE_STATEID(stateid_t *stateid) |
2663 | { | 2820 | { |
2664 | if (time_after((unsigned long)boot_time, | 2821 | if (stateid->si_boot == boot_time) |
2665 | (unsigned long)stateid->si_boot)) { | 2822 | return 0; |
2666 | dprintk("NFSD: stale stateid " STATEID_FMT "!\n", | 2823 | dprintk("NFSD: stale stateid " STATEID_FMT "!\n", |
2667 | STATEID_VAL(stateid)); | ||
2668 | return 1; | ||
2669 | } | ||
2670 | return 0; | ||
2671 | } | ||
2672 | |||
2673 | static int | ||
2674 | EXPIRED_STATEID(stateid_t *stateid) | ||
2675 | { | ||
2676 | if (time_before((unsigned long)boot_time, | ||
2677 | ((unsigned long)stateid->si_boot)) && | ||
2678 | time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) { | ||
2679 | dprintk("NFSD: expired stateid " STATEID_FMT "!\n", | ||
2680 | STATEID_VAL(stateid)); | ||
2681 | return 1; | ||
2682 | } | ||
2683 | return 0; | ||
2684 | } | ||
2685 | |||
2686 | static __be32 | ||
2687 | stateid_error_map(stateid_t *stateid) | ||
2688 | { | ||
2689 | if (STALE_STATEID(stateid)) | ||
2690 | return nfserr_stale_stateid; | ||
2691 | if (EXPIRED_STATEID(stateid)) | ||
2692 | return nfserr_expired; | ||
2693 | |||
2694 | dprintk("NFSD: bad stateid " STATEID_FMT "!\n", | ||
2695 | STATEID_VAL(stateid)); | 2824 | STATEID_VAL(stateid)); |
2696 | return nfserr_bad_stateid; | 2825 | return 1; |
2697 | } | 2826 | } |
2698 | 2827 | ||
2699 | static inline int | 2828 | static inline int |
@@ -2716,6 +2845,9 @@ __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) | |||
2716 | { | 2845 | { |
2717 | __be32 status = nfserr_openmode; | 2846 | __be32 status = nfserr_openmode; |
2718 | 2847 | ||
2848 | /* For lock stateid's, we test the parent open, not the lock: */ | ||
2849 | if (stp->st_openstp) | ||
2850 | stp = stp->st_openstp; | ||
2719 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) | 2851 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) |
2720 | goto out; | 2852 | goto out; |
2721 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) | 2853 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) |
@@ -2817,10 +2949,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2817 | status = nfserr_bad_stateid; | 2949 | status = nfserr_bad_stateid; |
2818 | if (is_delegation_stateid(stateid)) { | 2950 | if (is_delegation_stateid(stateid)) { |
2819 | dp = find_delegation_stateid(ino, stateid); | 2951 | dp = find_delegation_stateid(ino, stateid); |
2820 | if (!dp) { | 2952 | if (!dp) |
2821 | status = stateid_error_map(stateid); | ||
2822 | goto out; | 2953 | goto out; |
2823 | } | ||
2824 | status = check_stateid_generation(stateid, &dp->dl_stateid, | 2954 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2825 | flags); | 2955 | flags); |
2826 | if (status) | 2956 | if (status) |
@@ -2830,13 +2960,12 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2830 | goto out; | 2960 | goto out; |
2831 | renew_client(dp->dl_client); | 2961 | renew_client(dp->dl_client); |
2832 | if (filpp) | 2962 | if (filpp) |
2833 | *filpp = dp->dl_vfs_file; | 2963 | *filpp = find_readable_file(dp->dl_file); |
2964 | BUG_ON(!*filpp); | ||
2834 | } else { /* open or lock stateid */ | 2965 | } else { /* open or lock stateid */ |
2835 | stp = find_stateid(stateid, flags); | 2966 | stp = find_stateid(stateid, flags); |
2836 | if (!stp) { | 2967 | if (!stp) |
2837 | status = stateid_error_map(stateid); | ||
2838 | goto out; | 2968 | goto out; |
2839 | } | ||
2840 | if (nfs4_check_fh(current_fh, stp)) | 2969 | if (nfs4_check_fh(current_fh, stp)) |
2841 | goto out; | 2970 | goto out; |
2842 | if (!stp->st_stateowner->so_confirmed) | 2971 | if (!stp->st_stateowner->so_confirmed) |
@@ -2849,8 +2978,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2849 | if (status) | 2978 | if (status) |
2850 | goto out; | 2979 | goto out; |
2851 | renew_client(stp->st_stateowner->so_client); | 2980 | renew_client(stp->st_stateowner->so_client); |
2852 | if (filpp) | 2981 | if (filpp) { |
2853 | *filpp = stp->st_vfs_file; | 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 | } | ||
2854 | } | 2988 | } |
2855 | status = nfs_ok; | 2989 | status = nfs_ok; |
2856 | out: | 2990 | out: |
@@ -2908,7 +3042,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2908 | */ | 3042 | */ |
2909 | sop = search_close_lru(stateid->si_stateownerid, flags); | 3043 | sop = search_close_lru(stateid->si_stateownerid, flags); |
2910 | if (sop == NULL) | 3044 | if (sop == NULL) |
2911 | return stateid_error_map(stateid); | 3045 | return nfserr_bad_stateid; |
2912 | *sopp = sop; | 3046 | *sopp = sop; |
2913 | goto check_replay; | 3047 | goto check_replay; |
2914 | } | 3048 | } |
@@ -3086,8 +3220,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3086 | goto out; | 3220 | goto out; |
3087 | } | 3221 | } |
3088 | set_access(&share_access, stp->st_access_bmap); | 3222 | set_access(&share_access, stp->st_access_bmap); |
3089 | nfs4_file_downgrade(stp->st_vfs_file, | 3223 | nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); |
3090 | share_access & ~od->od_share_access); | ||
3091 | 3224 | ||
3092 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); | 3225 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); |
3093 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3226 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
@@ -3175,10 +3308,8 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3175 | if (!is_delegation_stateid(stateid)) | 3308 | if (!is_delegation_stateid(stateid)) |
3176 | goto out; | 3309 | goto out; |
3177 | dp = find_delegation_stateid(inode, stateid); | 3310 | dp = find_delegation_stateid(inode, stateid); |
3178 | if (!dp) { | 3311 | if (!dp) |
3179 | status = stateid_error_map(stateid); | ||
3180 | goto out; | 3312 | goto out; |
3181 | } | ||
3182 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3313 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3183 | if (status) | 3314 | if (status) |
3184 | goto out; | 3315 | goto out; |
@@ -3308,11 +3439,9 @@ static inline void | |||
3308 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | 3439 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) |
3309 | { | 3440 | { |
3310 | struct nfs4_stateowner *sop; | 3441 | struct nfs4_stateowner *sop; |
3311 | unsigned int hval; | ||
3312 | 3442 | ||
3313 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { | 3443 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { |
3314 | sop = (struct nfs4_stateowner *) fl->fl_owner; | 3444 | sop = (struct nfs4_stateowner *) fl->fl_owner; |
3315 | hval = lockownerid_hashval(sop->so_id); | ||
3316 | kref_get(&sop->so_ref); | 3445 | kref_get(&sop->so_ref); |
3317 | deny->ld_sop = sop; | 3446 | deny->ld_sop = sop; |
3318 | deny->ld_clientid = sop->so_client->cl_clientid; | 3447 | deny->ld_clientid = sop->so_client->cl_clientid; |
@@ -3404,12 +3533,10 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3404 | stp->st_stateowner = sop; | 3533 | stp->st_stateowner = sop; |
3405 | get_nfs4_file(fp); | 3534 | get_nfs4_file(fp); |
3406 | stp->st_file = fp; | 3535 | stp->st_file = fp; |
3407 | stp->st_stateid.si_boot = get_seconds(); | 3536 | stp->st_stateid.si_boot = boot_time; |
3408 | stp->st_stateid.si_stateownerid = sop->so_id; | 3537 | stp->st_stateid.si_stateownerid = sop->so_id; |
3409 | stp->st_stateid.si_fileid = fp->fi_id; | 3538 | stp->st_stateid.si_fileid = fp->fi_id; |
3410 | stp->st_stateid.si_generation = 0; | 3539 | stp->st_stateid.si_generation = 0; |
3411 | stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ | ||
3412 | stp->st_access_bmap = open_stp->st_access_bmap; | ||
3413 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3540 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3414 | stp->st_openstp = open_stp; | 3541 | stp->st_openstp = open_stp; |
3415 | 3542 | ||
@@ -3509,7 +3636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3509 | lock_sop = lock->lk_replay_owner; | 3636 | lock_sop = lock->lk_replay_owner; |
3510 | } | 3637 | } |
3511 | /* lock->lk_replay_owner and lock_stp have been created or found */ | 3638 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
3512 | filp = lock_stp->st_vfs_file; | ||
3513 | 3639 | ||
3514 | status = nfserr_grace; | 3640 | status = nfserr_grace; |
3515 | if (locks_in_grace() && !lock->lk_reclaim) | 3641 | if (locks_in_grace() && !lock->lk_reclaim) |
@@ -3522,11 +3648,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3522 | switch (lock->lk_type) { | 3648 | switch (lock->lk_type) { |
3523 | case NFS4_READ_LT: | 3649 | case NFS4_READ_LT: |
3524 | case NFS4_READW_LT: | 3650 | case NFS4_READW_LT: |
3651 | filp = find_readable_file(lock_stp->st_file); | ||
3525 | file_lock.fl_type = F_RDLCK; | 3652 | file_lock.fl_type = F_RDLCK; |
3526 | cmd = F_SETLK; | 3653 | cmd = F_SETLK; |
3527 | break; | 3654 | break; |
3528 | case NFS4_WRITE_LT: | 3655 | case NFS4_WRITE_LT: |
3529 | case NFS4_WRITEW_LT: | 3656 | case NFS4_WRITEW_LT: |
3657 | filp = find_writeable_file(lock_stp->st_file); | ||
3530 | file_lock.fl_type = F_WRLCK; | 3658 | file_lock.fl_type = F_WRLCK; |
3531 | cmd = F_SETLK; | 3659 | cmd = F_SETLK; |
3532 | break; | 3660 | break; |
@@ -3534,6 +3662,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3534 | status = nfserr_inval; | 3662 | status = nfserr_inval; |
3535 | goto out; | 3663 | goto out; |
3536 | } | 3664 | } |
3665 | if (!filp) { | ||
3666 | status = nfserr_openmode; | ||
3667 | goto out; | ||
3668 | } | ||
3537 | file_lock.fl_owner = (fl_owner_t)lock_sop; | 3669 | file_lock.fl_owner = (fl_owner_t)lock_sop; |
3538 | file_lock.fl_pid = current->tgid; | 3670 | file_lock.fl_pid = current->tgid; |
3539 | file_lock.fl_file = filp; | 3671 | file_lock.fl_file = filp; |
@@ -3702,7 +3834,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3702 | &locku->lu_stateowner, &stp, NULL))) | 3834 | &locku->lu_stateowner, &stp, NULL))) |
3703 | goto out; | 3835 | goto out; |
3704 | 3836 | ||
3705 | 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 | } | ||
3706 | BUG_ON(!filp); | 3842 | BUG_ON(!filp); |
3707 | locks_init_lock(&file_lock); | 3843 | locks_init_lock(&file_lock); |
3708 | file_lock.fl_type = F_UNLCK; | 3844 | file_lock.fl_type = F_UNLCK; |
@@ -3749,10 +3885,10 @@ out_nfserr: | |||
3749 | * 0: no locks held by lockowner | 3885 | * 0: no locks held by lockowner |
3750 | */ | 3886 | */ |
3751 | static int | 3887 | static int |
3752 | check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) | 3888 | check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) |
3753 | { | 3889 | { |
3754 | struct file_lock **flpp; | 3890 | struct file_lock **flpp; |
3755 | struct inode *inode = filp->f_path.dentry->d_inode; | 3891 | struct inode *inode = filp->fi_inode; |
3756 | int status = 0; | 3892 | int status = 0; |
3757 | 3893 | ||
3758 | lock_kernel(); | 3894 | lock_kernel(); |
@@ -3803,7 +3939,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
3803 | continue; | 3939 | continue; |
3804 | list_for_each_entry(stp, &sop->so_stateids, | 3940 | list_for_each_entry(stp, &sop->so_stateids, |
3805 | st_perstateowner) { | 3941 | st_perstateowner) { |
3806 | if (check_for_locks(stp->st_vfs_file, sop)) | 3942 | if (check_for_locks(stp->st_file, sop)) |
3807 | goto out; | 3943 | goto out; |
3808 | /* Note: so_perclient unused for lockowners, | 3944 | /* Note: so_perclient unused for lockowners, |
3809 | * so it's OK to fool with here. */ | 3945 | * so it's OK to fool with here. */ |
@@ -3976,12 +4112,6 @@ nfsd4_load_reboot_recovery_data(void) | |||
3976 | printk("NFSD: Failure reading reboot recovery data\n"); | 4112 | printk("NFSD: Failure reading reboot recovery data\n"); |
3977 | } | 4113 | } |
3978 | 4114 | ||
3979 | unsigned long | ||
3980 | get_nfs4_grace_period(void) | ||
3981 | { | ||
3982 | return max(user_lease_time, lease_time) * HZ; | ||
3983 | } | ||
3984 | |||
3985 | /* | 4115 | /* |
3986 | * Since the lifetime of a delegation isn't limited to that of an open, a | 4116 | * Since the lifetime of a delegation isn't limited to that of an open, a |
3987 | * client may quite reasonably hang on to a delegation as long as it has | 4117 | * client may quite reasonably hang on to a delegation as long as it has |
@@ -4008,41 +4138,34 @@ set_max_delegations(void) | |||
4008 | static int | 4138 | static int |
4009 | __nfs4_state_start(void) | 4139 | __nfs4_state_start(void) |
4010 | { | 4140 | { |
4011 | unsigned long grace_time; | 4141 | int ret; |
4012 | 4142 | ||
4013 | boot_time = get_seconds(); | 4143 | boot_time = get_seconds(); |
4014 | grace_time = get_nfs4_grace_period(); | ||
4015 | lease_time = user_lease_time; | ||
4016 | locks_start_grace(&nfsd4_manager); | 4144 | locks_start_grace(&nfsd4_manager); |
4017 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4145 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
4018 | grace_time/HZ); | 4146 | nfsd4_grace); |
4147 | ret = set_callback_cred(); | ||
4148 | if (ret) | ||
4149 | return -ENOMEM; | ||
4019 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4150 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4020 | if (laundry_wq == NULL) | 4151 | if (laundry_wq == NULL) |
4021 | return -ENOMEM; | 4152 | return -ENOMEM; |
4022 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); | 4153 | ret = nfsd4_create_callback_queue(); |
4154 | if (ret) | ||
4155 | goto out_free_laundry; | ||
4156 | queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); | ||
4023 | set_max_delegations(); | 4157 | set_max_delegations(); |
4024 | return set_callback_cred(); | 4158 | return 0; |
4159 | out_free_laundry: | ||
4160 | destroy_workqueue(laundry_wq); | ||
4161 | return ret; | ||
4025 | } | 4162 | } |
4026 | 4163 | ||
4027 | int | 4164 | int |
4028 | nfs4_state_start(void) | 4165 | nfs4_state_start(void) |
4029 | { | 4166 | { |
4030 | int ret; | ||
4031 | |||
4032 | if (nfs4_init) | ||
4033 | return 0; | ||
4034 | nfsd4_load_reboot_recovery_data(); | 4167 | nfsd4_load_reboot_recovery_data(); |
4035 | ret = __nfs4_state_start(); | 4168 | return __nfs4_state_start(); |
4036 | if (ret) | ||
4037 | return ret; | ||
4038 | nfs4_init = 1; | ||
4039 | return 0; | ||
4040 | } | ||
4041 | |||
4042 | time_t | ||
4043 | nfs4_lease_time(void) | ||
4044 | { | ||
4045 | return lease_time; | ||
4046 | } | 4169 | } |
4047 | 4170 | ||
4048 | static void | 4171 | static void |
@@ -4077,7 +4200,6 @@ __nfs4_state_shutdown(void) | |||
4077 | } | 4200 | } |
4078 | 4201 | ||
4079 | nfsd4_shutdown_recdir(); | 4202 | nfsd4_shutdown_recdir(); |
4080 | nfs4_init = 0; | ||
4081 | } | 4203 | } |
4082 | 4204 | ||
4083 | void | 4205 | void |
@@ -4090,6 +4212,7 @@ nfs4_state_shutdown(void) | |||
4090 | nfs4_release_reclaim(); | 4212 | nfs4_release_reclaim(); |
4091 | __nfs4_state_shutdown(); | 4213 | __nfs4_state_shutdown(); |
4092 | nfs4_unlock_state(); | 4214 | nfs4_unlock_state(); |
4215 | nfsd4_destroy_callback_queue(); | ||
4093 | } | 4216 | } |
4094 | 4217 | ||
4095 | /* | 4218 | /* |
@@ -4128,21 +4251,3 @@ nfs4_recoverydir(void) | |||
4128 | { | 4251 | { |
4129 | return user_recovery_dirname; | 4252 | return user_recovery_dirname; |
4130 | } | 4253 | } |
4131 | |||
4132 | /* | ||
4133 | * Called when leasetime is changed. | ||
4134 | * | ||
4135 | * The only way the protocol gives us to handle on-the-fly lease changes is to | ||
4136 | * simulate a reboot. Instead of doing that, we just wait till the next time | ||
4137 | * we start to register any changes in lease time. If the administrator | ||
4138 | * really wants to change the lease time *now*, they can go ahead and bring | ||
4139 | * nfsd down and then back up again after changing the lease time. | ||
4140 | * | ||
4141 | * user_lease_time is protected by nfsd_mutex since it's only really accessed | ||
4142 | * when nfsd is starting | ||
4143 | */ | ||
4144 | void | ||
4145 | nfs4_reset_lease(time_t leasetime) | ||
4146 | { | ||
4147 | user_lease_time = leasetime; | ||
4148 | } | ||