diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 376 |
1 files changed, 196 insertions, 180 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6a8fedaa4f55..12f7109720c2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -45,8 +45,8 @@ | |||
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; |
@@ -190,7 +190,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
190 | dp->dl_vfs_file = stp->st_vfs_file; | 190 | dp->dl_vfs_file = stp->st_vfs_file; |
191 | dp->dl_type = type; | 191 | dp->dl_type = type; |
192 | dp->dl_ident = cb->cb_ident; | 192 | dp->dl_ident = cb->cb_ident; |
193 | dp->dl_stateid.si_boot = get_seconds(); | 193 | dp->dl_stateid.si_boot = boot_time; |
194 | dp->dl_stateid.si_stateownerid = current_delegid++; | 194 | dp->dl_stateid.si_stateownerid = current_delegid++; |
195 | dp->dl_stateid.si_fileid = 0; | 195 | dp->dl_stateid.si_fileid = 0; |
196 | dp->dl_stateid.si_generation = 0; | 196 | dp->dl_stateid.si_generation = 0; |
@@ -199,6 +199,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
199 | atomic_set(&dp->dl_count, 1); | 199 | atomic_set(&dp->dl_count, 1); |
200 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 200 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
201 | list_add(&dp->dl_perclnt, &clp->cl_delegations); | 201 | list_add(&dp->dl_perclnt, &clp->cl_delegations); |
202 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); | ||
202 | return dp; | 203 | return dp; |
203 | } | 204 | } |
204 | 205 | ||
@@ -249,6 +250,9 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
249 | * SETCLIENTID state | 250 | * SETCLIENTID state |
250 | */ | 251 | */ |
251 | 252 | ||
253 | /* client_lock protects the client lru list and session hash table */ | ||
254 | static DEFINE_SPINLOCK(client_lock); | ||
255 | |||
252 | /* Hash tables for nfs4_clientid state */ | 256 | /* Hash tables for nfs4_clientid state */ |
253 | #define CLIENT_HASH_BITS 4 | 257 | #define CLIENT_HASH_BITS 4 |
254 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) | 258 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) |
@@ -367,7 +371,6 @@ static void release_openowner(struct nfs4_stateowner *sop) | |||
367 | nfs4_put_stateowner(sop); | 371 | nfs4_put_stateowner(sop); |
368 | } | 372 | } |
369 | 373 | ||
370 | static DEFINE_SPINLOCK(sessionid_lock); | ||
371 | #define SESSION_HASH_SIZE 512 | 374 | #define SESSION_HASH_SIZE 512 |
372 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; | 375 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; |
373 | 376 | ||
@@ -565,10 +568,10 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
565 | 568 | ||
566 | new->se_flags = cses->flags; | 569 | new->se_flags = cses->flags; |
567 | kref_init(&new->se_ref); | 570 | kref_init(&new->se_ref); |
568 | spin_lock(&sessionid_lock); | 571 | spin_lock(&client_lock); |
569 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | 572 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); |
570 | list_add(&new->se_perclnt, &clp->cl_sessions); | 573 | list_add(&new->se_perclnt, &clp->cl_sessions); |
571 | spin_unlock(&sessionid_lock); | 574 | spin_unlock(&client_lock); |
572 | 575 | ||
573 | status = nfs_ok; | 576 | status = nfs_ok; |
574 | out: | 577 | out: |
@@ -579,7 +582,7 @@ out_free: | |||
579 | goto out; | 582 | goto out; |
580 | } | 583 | } |
581 | 584 | ||
582 | /* caller must hold sessionid_lock */ | 585 | /* caller must hold client_lock */ |
583 | static struct nfsd4_session * | 586 | static struct nfsd4_session * |
584 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | 587 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) |
585 | { | 588 | { |
@@ -602,7 +605,7 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | |||
602 | return NULL; | 605 | return NULL; |
603 | } | 606 | } |
604 | 607 | ||
605 | /* caller must hold sessionid_lock */ | 608 | /* caller must hold client_lock */ |
606 | static void | 609 | static void |
607 | unhash_session(struct nfsd4_session *ses) | 610 | unhash_session(struct nfsd4_session *ses) |
608 | { | 611 | { |
@@ -610,15 +613,6 @@ unhash_session(struct nfsd4_session *ses) | |||
610 | list_del(&ses->se_perclnt); | 613 | list_del(&ses->se_perclnt); |
611 | } | 614 | } |
612 | 615 | ||
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 | 616 | void |
623 | free_session(struct kref *kref) | 617 | free_session(struct kref *kref) |
624 | { | 618 | { |
@@ -634,9 +628,18 @@ free_session(struct kref *kref) | |||
634 | kfree(ses); | 628 | kfree(ses); |
635 | } | 629 | } |
636 | 630 | ||
631 | /* must be called under the client_lock */ | ||
637 | static inline void | 632 | static inline void |
638 | renew_client(struct nfs4_client *clp) | 633 | renew_client_locked(struct nfs4_client *clp) |
639 | { | 634 | { |
635 | if (is_client_expired(clp)) { | ||
636 | dprintk("%s: client (clientid %08x/%08x) already expired\n", | ||
637 | __func__, | ||
638 | clp->cl_clientid.cl_boot, | ||
639 | clp->cl_clientid.cl_id); | ||
640 | return; | ||
641 | } | ||
642 | |||
640 | /* | 643 | /* |
641 | * Move client to the end to the LRU list. | 644 | * Move client to the end to the LRU list. |
642 | */ | 645 | */ |
@@ -647,6 +650,14 @@ renew_client(struct nfs4_client *clp) | |||
647 | clp->cl_time = get_seconds(); | 650 | clp->cl_time = get_seconds(); |
648 | } | 651 | } |
649 | 652 | ||
653 | static inline void | ||
654 | renew_client(struct nfs4_client *clp) | ||
655 | { | ||
656 | spin_lock(&client_lock); | ||
657 | renew_client_locked(clp); | ||
658 | spin_unlock(&client_lock); | ||
659 | } | ||
660 | |||
650 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ | 661 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ |
651 | static int | 662 | static int |
652 | STALE_CLIENTID(clientid_t *clid) | 663 | STALE_CLIENTID(clientid_t *clid) |
@@ -680,27 +691,9 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
680 | return clp; | 691 | return clp; |
681 | } | 692 | } |
682 | 693 | ||
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 | 694 | static inline void |
699 | free_client(struct nfs4_client *clp) | 695 | free_client(struct nfs4_client *clp) |
700 | { | 696 | { |
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) | 697 | if (clp->cl_cred.cr_group_info) |
705 | put_group_info(clp->cl_cred.cr_group_info); | 698 | put_group_info(clp->cl_cred.cr_group_info); |
706 | kfree(clp->cl_principal); | 699 | kfree(clp->cl_principal); |
@@ -709,10 +702,34 @@ free_client(struct nfs4_client *clp) | |||
709 | } | 702 | } |
710 | 703 | ||
711 | void | 704 | void |
712 | put_nfs4_client(struct nfs4_client *clp) | 705 | release_session_client(struct nfsd4_session *session) |
713 | { | 706 | { |
714 | if (atomic_dec_and_test(&clp->cl_count)) | 707 | struct nfs4_client *clp = session->se_client; |
708 | |||
709 | if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) | ||
710 | return; | ||
711 | if (is_client_expired(clp)) { | ||
715 | free_client(clp); | 712 | free_client(clp); |
713 | session->se_client = NULL; | ||
714 | } else | ||
715 | renew_client_locked(clp); | ||
716 | spin_unlock(&client_lock); | ||
717 | nfsd4_put_session(session); | ||
718 | } | ||
719 | |||
720 | /* must be called under the client_lock */ | ||
721 | static inline void | ||
722 | unhash_client_locked(struct nfs4_client *clp) | ||
723 | { | ||
724 | mark_client_expired(clp); | ||
725 | list_del(&clp->cl_lru); | ||
726 | while (!list_empty(&clp->cl_sessions)) { | ||
727 | struct nfsd4_session *ses; | ||
728 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | ||
729 | se_perclnt); | ||
730 | unhash_session(ses); | ||
731 | nfsd4_put_session(ses); | ||
732 | } | ||
716 | } | 733 | } |
717 | 734 | ||
718 | static void | 735 | static void |
@@ -722,9 +739,6 @@ expire_client(struct nfs4_client *clp) | |||
722 | struct nfs4_delegation *dp; | 739 | struct nfs4_delegation *dp; |
723 | struct list_head reaplist; | 740 | struct list_head reaplist; |
724 | 741 | ||
725 | dprintk("NFSD: expire_client cl_count %d\n", | ||
726 | atomic_read(&clp->cl_count)); | ||
727 | |||
728 | INIT_LIST_HEAD(&reaplist); | 742 | INIT_LIST_HEAD(&reaplist); |
729 | spin_lock(&recall_lock); | 743 | spin_lock(&recall_lock); |
730 | while (!list_empty(&clp->cl_delegations)) { | 744 | while (!list_empty(&clp->cl_delegations)) { |
@@ -740,20 +754,20 @@ expire_client(struct nfs4_client *clp) | |||
740 | list_del_init(&dp->dl_recall_lru); | 754 | list_del_init(&dp->dl_recall_lru); |
741 | unhash_delegation(dp); | 755 | unhash_delegation(dp); |
742 | } | 756 | } |
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)) { | 757 | while (!list_empty(&clp->cl_openowners)) { |
747 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); | 758 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); |
748 | release_openowner(sop); | 759 | release_openowner(sop); |
749 | } | 760 | } |
750 | while (!list_empty(&clp->cl_sessions)) { | 761 | nfsd4_set_callback_client(clp, NULL); |
751 | struct nfsd4_session *ses; | 762 | if (clp->cl_cb_conn.cb_xprt) |
752 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 763 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); |
753 | se_perclnt); | 764 | list_del(&clp->cl_idhash); |
754 | release_session(ses); | 765 | list_del(&clp->cl_strhash); |
755 | } | 766 | spin_lock(&client_lock); |
756 | put_nfs4_client(clp); | 767 | unhash_client_locked(clp); |
768 | if (atomic_read(&clp->cl_refcount) == 0) | ||
769 | free_client(clp); | ||
770 | spin_unlock(&client_lock); | ||
757 | } | 771 | } |
758 | 772 | ||
759 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) | 773 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) |
@@ -839,14 +853,15 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
839 | } | 853 | } |
840 | 854 | ||
841 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 855 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
842 | atomic_set(&clp->cl_count, 1); | 856 | atomic_set(&clp->cl_refcount, 0); |
843 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | 857 | atomic_set(&clp->cl_cb_set, 0); |
844 | INIT_LIST_HEAD(&clp->cl_idhash); | 858 | INIT_LIST_HEAD(&clp->cl_idhash); |
845 | INIT_LIST_HEAD(&clp->cl_strhash); | 859 | INIT_LIST_HEAD(&clp->cl_strhash); |
846 | INIT_LIST_HEAD(&clp->cl_openowners); | 860 | INIT_LIST_HEAD(&clp->cl_openowners); |
847 | INIT_LIST_HEAD(&clp->cl_delegations); | 861 | INIT_LIST_HEAD(&clp->cl_delegations); |
848 | INIT_LIST_HEAD(&clp->cl_sessions); | 862 | INIT_LIST_HEAD(&clp->cl_sessions); |
849 | INIT_LIST_HEAD(&clp->cl_lru); | 863 | INIT_LIST_HEAD(&clp->cl_lru); |
864 | clp->cl_time = get_seconds(); | ||
850 | clear_bit(0, &clp->cl_cb_slot_busy); | 865 | clear_bit(0, &clp->cl_cb_slot_busy); |
851 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 866 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
852 | copy_verf(clp, verf); | 867 | copy_verf(clp, verf); |
@@ -877,8 +892,7 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | |||
877 | list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); | 892 | list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); |
878 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 893 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
879 | list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); | 894 | list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); |
880 | list_add_tail(&clp->cl_lru, &client_lru); | 895 | renew_client(clp); |
881 | clp->cl_time = get_seconds(); | ||
882 | } | 896 | } |
883 | 897 | ||
884 | static void | 898 | static void |
@@ -888,10 +902,9 @@ move_to_confirmed(struct nfs4_client *clp) | |||
888 | unsigned int strhashval; | 902 | unsigned int strhashval; |
889 | 903 | ||
890 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); | 904 | 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]); | 905 | list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); |
893 | strhashval = clientstr_hashval(clp->cl_recdir); | 906 | strhashval = clientstr_hashval(clp->cl_recdir); |
894 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); | 907 | list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); |
895 | renew_client(clp); | 908 | renew_client(clp); |
896 | } | 909 | } |
897 | 910 | ||
@@ -1327,15 +1340,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1327 | cs_slot->sl_seqid++; /* from 0 to 1 */ | 1340 | cs_slot->sl_seqid++; /* from 0 to 1 */ |
1328 | move_to_confirmed(unconf); | 1341 | move_to_confirmed(unconf); |
1329 | 1342 | ||
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) { | 1343 | if (cr_ses->flags & SESSION4_BACK_CHAN) { |
1337 | unconf->cl_cb_xprt = rqstp->rq_xprt; | 1344 | unconf->cl_cb_conn.cb_xprt = rqstp->rq_xprt; |
1338 | svc_xprt_get(unconf->cl_cb_xprt); | 1345 | svc_xprt_get(rqstp->rq_xprt); |
1339 | rpc_copy_addr( | 1346 | rpc_copy_addr( |
1340 | (struct sockaddr *)&unconf->cl_cb_conn.cb_addr, | 1347 | (struct sockaddr *)&unconf->cl_cb_conn.cb_addr, |
1341 | sa); | 1348 | sa); |
@@ -1344,7 +1351,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1344 | cstate->minorversion; | 1351 | cstate->minorversion; |
1345 | unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; | 1352 | unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; |
1346 | unconf->cl_cb_seq_nr = 1; | 1353 | unconf->cl_cb_seq_nr = 1; |
1347 | nfsd4_probe_callback(unconf); | 1354 | nfsd4_probe_callback(unconf, &unconf->cl_cb_conn); |
1348 | } | 1355 | } |
1349 | conf = unconf; | 1356 | conf = unconf; |
1350 | } else { | 1357 | } else { |
@@ -1352,6 +1359,12 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1352 | goto out; | 1359 | goto out; |
1353 | } | 1360 | } |
1354 | 1361 | ||
1362 | /* | ||
1363 | * We do not support RDMA or persistent sessions | ||
1364 | */ | ||
1365 | cr_ses->flags &= ~SESSION4_PERSIST; | ||
1366 | cr_ses->flags &= ~SESSION4_RDMA; | ||
1367 | |||
1355 | status = alloc_init_session(rqstp, conf, cr_ses); | 1368 | status = alloc_init_session(rqstp, conf, cr_ses); |
1356 | if (status) | 1369 | if (status) |
1357 | goto out; | 1370 | goto out; |
@@ -1369,6 +1382,21 @@ out: | |||
1369 | return status; | 1382 | return status; |
1370 | } | 1383 | } |
1371 | 1384 | ||
1385 | static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | ||
1386 | { | ||
1387 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1388 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
1389 | |||
1390 | return argp->opcnt == resp->opcnt; | ||
1391 | } | ||
1392 | |||
1393 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) | ||
1394 | { | ||
1395 | if (!session) | ||
1396 | return 0; | ||
1397 | return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); | ||
1398 | } | ||
1399 | |||
1372 | __be32 | 1400 | __be32 |
1373 | nfsd4_destroy_session(struct svc_rqst *r, | 1401 | nfsd4_destroy_session(struct svc_rqst *r, |
1374 | struct nfsd4_compound_state *cstate, | 1402 | struct nfsd4_compound_state *cstate, |
@@ -1384,19 +1412,25 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1384 | * - Do we need to clear any callback info from previous session? | 1412 | * - Do we need to clear any callback info from previous session? |
1385 | */ | 1413 | */ |
1386 | 1414 | ||
1415 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { | ||
1416 | if (!nfsd4_last_compound_op(r)) | ||
1417 | return nfserr_not_only_op; | ||
1418 | } | ||
1387 | dump_sessionid(__func__, &sessionid->sessionid); | 1419 | dump_sessionid(__func__, &sessionid->sessionid); |
1388 | spin_lock(&sessionid_lock); | 1420 | spin_lock(&client_lock); |
1389 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); | 1421 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); |
1390 | if (!ses) { | 1422 | if (!ses) { |
1391 | spin_unlock(&sessionid_lock); | 1423 | spin_unlock(&client_lock); |
1392 | goto out; | 1424 | goto out; |
1393 | } | 1425 | } |
1394 | 1426 | ||
1395 | unhash_session(ses); | 1427 | unhash_session(ses); |
1396 | spin_unlock(&sessionid_lock); | 1428 | spin_unlock(&client_lock); |
1397 | 1429 | ||
1430 | nfs4_lock_state(); | ||
1398 | /* wait for callbacks */ | 1431 | /* wait for callbacks */ |
1399 | shutdown_callback_client(ses->se_client); | 1432 | nfsd4_set_callback_client(ses->se_client, NULL); |
1433 | nfs4_unlock_state(); | ||
1400 | nfsd4_put_session(ses); | 1434 | nfsd4_put_session(ses); |
1401 | status = nfs_ok; | 1435 | status = nfs_ok; |
1402 | out: | 1436 | out: |
@@ -1417,7 +1451,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1417 | if (resp->opcnt != 1) | 1451 | if (resp->opcnt != 1) |
1418 | return nfserr_sequence_pos; | 1452 | return nfserr_sequence_pos; |
1419 | 1453 | ||
1420 | spin_lock(&sessionid_lock); | 1454 | spin_lock(&client_lock); |
1421 | status = nfserr_badsession; | 1455 | status = nfserr_badsession; |
1422 | session = find_in_sessionid_hashtbl(&seq->sessionid); | 1456 | session = find_in_sessionid_hashtbl(&seq->sessionid); |
1423 | if (!session) | 1457 | if (!session) |
@@ -1456,23 +1490,47 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1456 | cstate->slot = slot; | 1490 | cstate->slot = slot; |
1457 | cstate->session = session; | 1491 | cstate->session = session; |
1458 | 1492 | ||
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: | 1493 | out: |
1464 | spin_unlock(&sessionid_lock); | 1494 | /* Hold a session reference until done processing the compound. */ |
1465 | /* Renew the clientid on success and on replay */ | ||
1466 | if (cstate->session) { | 1495 | if (cstate->session) { |
1467 | nfs4_lock_state(); | 1496 | nfsd4_get_session(cstate->session); |
1468 | renew_client(session->se_client); | 1497 | atomic_inc(&session->se_client->cl_refcount); |
1469 | nfs4_unlock_state(); | ||
1470 | } | 1498 | } |
1499 | spin_unlock(&client_lock); | ||
1471 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 1500 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
1472 | return status; | 1501 | return status; |
1473 | } | 1502 | } |
1474 | 1503 | ||
1475 | __be32 | 1504 | __be32 |
1505 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | ||
1506 | { | ||
1507 | if (rc->rca_one_fs) { | ||
1508 | if (!cstate->current_fh.fh_dentry) | ||
1509 | return nfserr_nofilehandle; | ||
1510 | /* | ||
1511 | * We don't take advantage of the rca_one_fs case. | ||
1512 | * That's OK, it's optional, we can safely ignore it. | ||
1513 | */ | ||
1514 | return nfs_ok; | ||
1515 | } | ||
1516 | nfs4_lock_state(); | ||
1517 | if (is_client_expired(cstate->session->se_client)) { | ||
1518 | nfs4_unlock_state(); | ||
1519 | /* | ||
1520 | * The following error isn't really legal. | ||
1521 | * But we only get here if the client just explicitly | ||
1522 | * destroyed the client. Surely it no longer cares what | ||
1523 | * error it gets back on an operation for the dead | ||
1524 | * client. | ||
1525 | */ | ||
1526 | return nfserr_stale_clientid; | ||
1527 | } | ||
1528 | nfsd4_create_clid_dir(cstate->session->se_client); | ||
1529 | nfs4_unlock_state(); | ||
1530 | return nfs_ok; | ||
1531 | } | ||
1532 | |||
1533 | __be32 | ||
1476 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1534 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1477 | struct nfsd4_setclientid *setclid) | 1535 | struct nfsd4_setclientid *setclid) |
1478 | { | 1536 | { |
@@ -1631,9 +1689,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1631 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 1689 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) |
1632 | status = nfserr_clid_inuse; | 1690 | status = nfserr_clid_inuse; |
1633 | else { | 1691 | else { |
1634 | /* XXX: We just turn off callbacks until we can handle | 1692 | atomic_set(&conf->cl_cb_set, 0); |
1635 | * change request correctly. */ | 1693 | nfsd4_probe_callback(conf, &unconf->cl_cb_conn); |
1636 | atomic_set(&conf->cl_cb_conn.cb_set, 0); | ||
1637 | expire_client(unconf); | 1694 | expire_client(unconf); |
1638 | status = nfs_ok; | 1695 | status = nfs_ok; |
1639 | 1696 | ||
@@ -1667,7 +1724,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1667 | } | 1724 | } |
1668 | move_to_confirmed(unconf); | 1725 | move_to_confirmed(unconf); |
1669 | conf = unconf; | 1726 | conf = unconf; |
1670 | nfsd4_probe_callback(conf); | 1727 | nfsd4_probe_callback(conf, &conf->cl_cb_conn); |
1671 | status = nfs_ok; | 1728 | status = nfs_ok; |
1672 | } | 1729 | } |
1673 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | 1730 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) |
@@ -1700,12 +1757,12 @@ alloc_init_file(struct inode *ino) | |||
1700 | INIT_LIST_HEAD(&fp->fi_hash); | 1757 | INIT_LIST_HEAD(&fp->fi_hash); |
1701 | INIT_LIST_HEAD(&fp->fi_stateids); | 1758 | INIT_LIST_HEAD(&fp->fi_stateids); |
1702 | INIT_LIST_HEAD(&fp->fi_delegations); | 1759 | 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); | 1760 | fp->fi_inode = igrab(ino); |
1707 | fp->fi_id = current_fileid++; | 1761 | fp->fi_id = current_fileid++; |
1708 | fp->fi_had_conflict = false; | 1762 | fp->fi_had_conflict = false; |
1763 | spin_lock(&recall_lock); | ||
1764 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | ||
1765 | spin_unlock(&recall_lock); | ||
1709 | return fp; | 1766 | return fp; |
1710 | } | 1767 | } |
1711 | return NULL; | 1768 | return NULL; |
@@ -1827,7 +1884,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1827 | stp->st_stateowner = sop; | 1884 | stp->st_stateowner = sop; |
1828 | get_nfs4_file(fp); | 1885 | get_nfs4_file(fp); |
1829 | stp->st_file = fp; | 1886 | stp->st_file = fp; |
1830 | stp->st_stateid.si_boot = get_seconds(); | 1887 | stp->st_stateid.si_boot = boot_time; |
1831 | stp->st_stateid.si_stateownerid = sop->so_id; | 1888 | stp->st_stateid.si_stateownerid = sop->so_id; |
1832 | stp->st_stateid.si_fileid = fp->fi_id; | 1889 | stp->st_stateid.si_fileid = fp->fi_id; |
1833 | stp->st_stateid.si_generation = 0; | 1890 | stp->st_stateid.si_generation = 0; |
@@ -2028,7 +2085,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2028 | * lock) we know the server hasn't removed the lease yet, we know | 2085 | * lock) we know the server hasn't removed the lease yet, we know |
2029 | * it's safe to take a reference: */ | 2086 | * it's safe to take a reference: */ |
2030 | atomic_inc(&dp->dl_count); | 2087 | atomic_inc(&dp->dl_count); |
2031 | atomic_inc(&dp->dl_client->cl_count); | ||
2032 | 2088 | ||
2033 | spin_lock(&recall_lock); | 2089 | spin_lock(&recall_lock); |
2034 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); | 2090 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); |
@@ -2347,7 +2403,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2347 | { | 2403 | { |
2348 | struct nfs4_delegation *dp; | 2404 | struct nfs4_delegation *dp; |
2349 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2405 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2350 | struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn; | 2406 | int cb_up = atomic_read(&sop->so_client->cl_cb_set); |
2351 | struct file_lock fl, *flp = &fl; | 2407 | struct file_lock fl, *flp = &fl; |
2352 | int status, flag = 0; | 2408 | int status, flag = 0; |
2353 | 2409 | ||
@@ -2355,7 +2411,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2355 | open->op_recall = 0; | 2411 | open->op_recall = 0; |
2356 | switch (open->op_claim_type) { | 2412 | switch (open->op_claim_type) { |
2357 | case NFS4_OPEN_CLAIM_PREVIOUS: | 2413 | case NFS4_OPEN_CLAIM_PREVIOUS: |
2358 | if (!atomic_read(&cb->cb_set)) | 2414 | if (!cb_up) |
2359 | open->op_recall = 1; | 2415 | open->op_recall = 1; |
2360 | flag = open->op_delegate_type; | 2416 | flag = open->op_delegate_type; |
2361 | if (flag == NFS4_OPEN_DELEGATE_NONE) | 2417 | if (flag == NFS4_OPEN_DELEGATE_NONE) |
@@ -2366,7 +2422,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2366 | * had the chance to reclaim theirs.... */ | 2422 | * had the chance to reclaim theirs.... */ |
2367 | if (locks_in_grace()) | 2423 | if (locks_in_grace()) |
2368 | goto out; | 2424 | goto out; |
2369 | if (!atomic_read(&cb->cb_set) || !sop->so_confirmed) | 2425 | if (!cb_up || !sop->so_confirmed) |
2370 | goto out; | 2426 | goto out; |
2371 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 2427 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
2372 | flag = NFS4_OPEN_DELEGATE_WRITE; | 2428 | flag = NFS4_OPEN_DELEGATE_WRITE; |
@@ -2483,10 +2539,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2483 | } | 2539 | } |
2484 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2540 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); |
2485 | 2541 | ||
2486 | if (nfsd4_has_session(&resp->cstate)) { | 2542 | if (nfsd4_has_session(&resp->cstate)) |
2487 | open->op_stateowner->so_confirmed = 1; | 2543 | open->op_stateowner->so_confirmed = 1; |
2488 | nfsd4_create_clid_dir(open->op_stateowner->so_client); | ||
2489 | } | ||
2490 | 2544 | ||
2491 | /* | 2545 | /* |
2492 | * Attempt to hand out a delegation. No error return, because the | 2546 | * Attempt to hand out a delegation. No error return, because the |
@@ -2537,7 +2591,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2537 | renew_client(clp); | 2591 | renew_client(clp); |
2538 | status = nfserr_cb_path_down; | 2592 | status = nfserr_cb_path_down; |
2539 | if (!list_empty(&clp->cl_delegations) | 2593 | if (!list_empty(&clp->cl_delegations) |
2540 | && !atomic_read(&clp->cl_cb_conn.cb_set)) | 2594 | && !atomic_read(&clp->cl_cb_set)) |
2541 | goto out; | 2595 | goto out; |
2542 | status = nfs_ok; | 2596 | status = nfs_ok; |
2543 | out: | 2597 | out: |
@@ -2554,6 +2608,12 @@ nfsd4_end_grace(void) | |||
2554 | dprintk("NFSD: end of grace period\n"); | 2608 | dprintk("NFSD: end of grace period\n"); |
2555 | nfsd4_recdir_purge_old(); | 2609 | nfsd4_recdir_purge_old(); |
2556 | locks_end_grace(&nfsd4_manager); | 2610 | locks_end_grace(&nfsd4_manager); |
2611 | /* | ||
2612 | * Now that every NFSv4 client has had the chance to recover and | ||
2613 | * to see the (possibly new, possibly shorter) lease time, we | ||
2614 | * can safely set the next grace time to the current lease time: | ||
2615 | */ | ||
2616 | nfsd4_grace = nfsd4_lease; | ||
2557 | } | 2617 | } |
2558 | 2618 | ||
2559 | static time_t | 2619 | static time_t |
@@ -2563,15 +2623,17 @@ nfs4_laundromat(void) | |||
2563 | struct nfs4_stateowner *sop; | 2623 | struct nfs4_stateowner *sop; |
2564 | struct nfs4_delegation *dp; | 2624 | struct nfs4_delegation *dp; |
2565 | struct list_head *pos, *next, reaplist; | 2625 | struct list_head *pos, *next, reaplist; |
2566 | time_t cutoff = get_seconds() - NFSD_LEASE_TIME; | 2626 | time_t cutoff = get_seconds() - nfsd4_lease; |
2567 | time_t t, clientid_val = NFSD_LEASE_TIME; | 2627 | time_t t, clientid_val = nfsd4_lease; |
2568 | time_t u, test_val = NFSD_LEASE_TIME; | 2628 | time_t u, test_val = nfsd4_lease; |
2569 | 2629 | ||
2570 | nfs4_lock_state(); | 2630 | nfs4_lock_state(); |
2571 | 2631 | ||
2572 | dprintk("NFSD: laundromat service - starting\n"); | 2632 | dprintk("NFSD: laundromat service - starting\n"); |
2573 | if (locks_in_grace()) | 2633 | if (locks_in_grace()) |
2574 | nfsd4_end_grace(); | 2634 | nfsd4_end_grace(); |
2635 | INIT_LIST_HEAD(&reaplist); | ||
2636 | spin_lock(&client_lock); | ||
2575 | list_for_each_safe(pos, next, &client_lru) { | 2637 | list_for_each_safe(pos, next, &client_lru) { |
2576 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 2638 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
2577 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { | 2639 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { |
@@ -2580,12 +2642,22 @@ nfs4_laundromat(void) | |||
2580 | clientid_val = t; | 2642 | clientid_val = t; |
2581 | break; | 2643 | break; |
2582 | } | 2644 | } |
2645 | if (atomic_read(&clp->cl_refcount)) { | ||
2646 | dprintk("NFSD: client in use (clientid %08x)\n", | ||
2647 | clp->cl_clientid.cl_id); | ||
2648 | continue; | ||
2649 | } | ||
2650 | unhash_client_locked(clp); | ||
2651 | list_add(&clp->cl_lru, &reaplist); | ||
2652 | } | ||
2653 | spin_unlock(&client_lock); | ||
2654 | list_for_each_safe(pos, next, &reaplist) { | ||
2655 | clp = list_entry(pos, struct nfs4_client, cl_lru); | ||
2583 | dprintk("NFSD: purging unused client (clientid %08x)\n", | 2656 | dprintk("NFSD: purging unused client (clientid %08x)\n", |
2584 | clp->cl_clientid.cl_id); | 2657 | clp->cl_clientid.cl_id); |
2585 | nfsd4_remove_clid_dir(clp); | 2658 | nfsd4_remove_clid_dir(clp); |
2586 | expire_client(clp); | 2659 | expire_client(clp); |
2587 | } | 2660 | } |
2588 | INIT_LIST_HEAD(&reaplist); | ||
2589 | spin_lock(&recall_lock); | 2661 | spin_lock(&recall_lock); |
2590 | list_for_each_safe(pos, next, &del_recall_lru) { | 2662 | list_for_each_safe(pos, next, &del_recall_lru) { |
2591 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 2663 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
@@ -2605,7 +2677,7 @@ nfs4_laundromat(void) | |||
2605 | list_del_init(&dp->dl_recall_lru); | 2677 | list_del_init(&dp->dl_recall_lru); |
2606 | unhash_delegation(dp); | 2678 | unhash_delegation(dp); |
2607 | } | 2679 | } |
2608 | test_val = NFSD_LEASE_TIME; | 2680 | test_val = nfsd4_lease; |
2609 | list_for_each_safe(pos, next, &close_lru) { | 2681 | list_for_each_safe(pos, next, &close_lru) { |
2610 | sop = list_entry(pos, struct nfs4_stateowner, so_close_lru); | 2682 | sop = list_entry(pos, struct nfs4_stateowner, so_close_lru); |
2611 | if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) { | 2683 | if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) { |
@@ -2661,39 +2733,11 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | |||
2661 | static int | 2733 | static int |
2662 | STALE_STATEID(stateid_t *stateid) | 2734 | STALE_STATEID(stateid_t *stateid) |
2663 | { | 2735 | { |
2664 | if (time_after((unsigned long)boot_time, | 2736 | if (stateid->si_boot == boot_time) |
2665 | (unsigned long)stateid->si_boot)) { | 2737 | return 0; |
2666 | dprintk("NFSD: stale stateid " STATEID_FMT "!\n", | 2738 | 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)); | 2739 | STATEID_VAL(stateid)); |
2696 | return nfserr_bad_stateid; | 2740 | return 1; |
2697 | } | 2741 | } |
2698 | 2742 | ||
2699 | static inline int | 2743 | static inline int |
@@ -2817,10 +2861,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2817 | status = nfserr_bad_stateid; | 2861 | status = nfserr_bad_stateid; |
2818 | if (is_delegation_stateid(stateid)) { | 2862 | if (is_delegation_stateid(stateid)) { |
2819 | dp = find_delegation_stateid(ino, stateid); | 2863 | dp = find_delegation_stateid(ino, stateid); |
2820 | if (!dp) { | 2864 | if (!dp) |
2821 | status = stateid_error_map(stateid); | ||
2822 | goto out; | 2865 | goto out; |
2823 | } | ||
2824 | status = check_stateid_generation(stateid, &dp->dl_stateid, | 2866 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2825 | flags); | 2867 | flags); |
2826 | if (status) | 2868 | if (status) |
@@ -2833,10 +2875,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2833 | *filpp = dp->dl_vfs_file; | 2875 | *filpp = dp->dl_vfs_file; |
2834 | } else { /* open or lock stateid */ | 2876 | } else { /* open or lock stateid */ |
2835 | stp = find_stateid(stateid, flags); | 2877 | stp = find_stateid(stateid, flags); |
2836 | if (!stp) { | 2878 | if (!stp) |
2837 | status = stateid_error_map(stateid); | ||
2838 | goto out; | 2879 | goto out; |
2839 | } | ||
2840 | if (nfs4_check_fh(current_fh, stp)) | 2880 | if (nfs4_check_fh(current_fh, stp)) |
2841 | goto out; | 2881 | goto out; |
2842 | if (!stp->st_stateowner->so_confirmed) | 2882 | if (!stp->st_stateowner->so_confirmed) |
@@ -2908,7 +2948,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2908 | */ | 2948 | */ |
2909 | sop = search_close_lru(stateid->si_stateownerid, flags); | 2949 | sop = search_close_lru(stateid->si_stateownerid, flags); |
2910 | if (sop == NULL) | 2950 | if (sop == NULL) |
2911 | return stateid_error_map(stateid); | 2951 | return nfserr_bad_stateid; |
2912 | *sopp = sop; | 2952 | *sopp = sop; |
2913 | goto check_replay; | 2953 | goto check_replay; |
2914 | } | 2954 | } |
@@ -3175,10 +3215,8 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3175 | if (!is_delegation_stateid(stateid)) | 3215 | if (!is_delegation_stateid(stateid)) |
3176 | goto out; | 3216 | goto out; |
3177 | dp = find_delegation_stateid(inode, stateid); | 3217 | dp = find_delegation_stateid(inode, stateid); |
3178 | if (!dp) { | 3218 | if (!dp) |
3179 | status = stateid_error_map(stateid); | ||
3180 | goto out; | 3219 | goto out; |
3181 | } | ||
3182 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3220 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3183 | if (status) | 3221 | if (status) |
3184 | goto out; | 3222 | goto out; |
@@ -3404,7 +3442,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3404 | stp->st_stateowner = sop; | 3442 | stp->st_stateowner = sop; |
3405 | get_nfs4_file(fp); | 3443 | get_nfs4_file(fp); |
3406 | stp->st_file = fp; | 3444 | stp->st_file = fp; |
3407 | stp->st_stateid.si_boot = get_seconds(); | 3445 | stp->st_stateid.si_boot = boot_time; |
3408 | stp->st_stateid.si_stateownerid = sop->so_id; | 3446 | stp->st_stateid.si_stateownerid = sop->so_id; |
3409 | stp->st_stateid.si_fileid = fp->fi_id; | 3447 | stp->st_stateid.si_fileid = fp->fi_id; |
3410 | stp->st_stateid.si_generation = 0; | 3448 | stp->st_stateid.si_generation = 0; |
@@ -3976,12 +4014,6 @@ nfsd4_load_reboot_recovery_data(void) | |||
3976 | printk("NFSD: Failure reading reboot recovery data\n"); | 4014 | printk("NFSD: Failure reading reboot recovery data\n"); |
3977 | } | 4015 | } |
3978 | 4016 | ||
3979 | unsigned long | ||
3980 | get_nfs4_grace_period(void) | ||
3981 | { | ||
3982 | return max(user_lease_time, lease_time) * HZ; | ||
3983 | } | ||
3984 | |||
3985 | /* | 4017 | /* |
3986 | * Since the lifetime of a delegation isn't limited to that of an open, a | 4018 | * 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 | 4019 | * client may quite reasonably hang on to a delegation as long as it has |
@@ -4008,20 +4040,27 @@ set_max_delegations(void) | |||
4008 | static int | 4040 | static int |
4009 | __nfs4_state_start(void) | 4041 | __nfs4_state_start(void) |
4010 | { | 4042 | { |
4011 | unsigned long grace_time; | 4043 | int ret; |
4012 | 4044 | ||
4013 | boot_time = get_seconds(); | 4045 | boot_time = get_seconds(); |
4014 | grace_time = get_nfs4_grace_period(); | ||
4015 | lease_time = user_lease_time; | ||
4016 | locks_start_grace(&nfsd4_manager); | 4046 | locks_start_grace(&nfsd4_manager); |
4017 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4047 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
4018 | grace_time/HZ); | 4048 | nfsd4_grace); |
4049 | ret = set_callback_cred(); | ||
4050 | if (ret) | ||
4051 | return -ENOMEM; | ||
4019 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4052 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4020 | if (laundry_wq == NULL) | 4053 | if (laundry_wq == NULL) |
4021 | return -ENOMEM; | 4054 | return -ENOMEM; |
4022 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); | 4055 | ret = nfsd4_create_callback_queue(); |
4056 | if (ret) | ||
4057 | goto out_free_laundry; | ||
4058 | queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); | ||
4023 | set_max_delegations(); | 4059 | set_max_delegations(); |
4024 | return set_callback_cred(); | 4060 | return 0; |
4061 | out_free_laundry: | ||
4062 | destroy_workqueue(laundry_wq); | ||
4063 | return ret; | ||
4025 | } | 4064 | } |
4026 | 4065 | ||
4027 | int | 4066 | int |
@@ -4039,12 +4078,6 @@ nfs4_state_start(void) | |||
4039 | return 0; | 4078 | return 0; |
4040 | } | 4079 | } |
4041 | 4080 | ||
4042 | time_t | ||
4043 | nfs4_lease_time(void) | ||
4044 | { | ||
4045 | return lease_time; | ||
4046 | } | ||
4047 | |||
4048 | static void | 4081 | static void |
4049 | __nfs4_state_shutdown(void) | 4082 | __nfs4_state_shutdown(void) |
4050 | { | 4083 | { |
@@ -4089,6 +4122,7 @@ nfs4_state_shutdown(void) | |||
4089 | nfs4_lock_state(); | 4122 | nfs4_lock_state(); |
4090 | nfs4_release_reclaim(); | 4123 | nfs4_release_reclaim(); |
4091 | __nfs4_state_shutdown(); | 4124 | __nfs4_state_shutdown(); |
4125 | nfsd4_destroy_callback_queue(); | ||
4092 | nfs4_unlock_state(); | 4126 | nfs4_unlock_state(); |
4093 | } | 4127 | } |
4094 | 4128 | ||
@@ -4128,21 +4162,3 @@ nfs4_recoverydir(void) | |||
4128 | { | 4162 | { |
4129 | return user_recovery_dirname; | 4163 | return user_recovery_dirname; |
4130 | } | 4164 | } |
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 | } | ||