diff options
38 files changed, 608 insertions, 383 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 977d8919cc69..ef9349a4b5d1 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -343,7 +343,6 @@ prototypes: | |||
343 | int (*fl_grant)(struct file_lock *, struct file_lock *, int); | 343 | int (*fl_grant)(struct file_lock *, struct file_lock *, int); |
344 | void (*fl_release_private)(struct file_lock *); | 344 | void (*fl_release_private)(struct file_lock *); |
345 | void (*fl_break)(struct file_lock *); /* break_lease callback */ | 345 | void (*fl_break)(struct file_lock *); /* break_lease callback */ |
346 | int (*fl_mylease)(struct file_lock *, struct file_lock *); | ||
347 | int (*fl_change)(struct file_lock **, int); | 346 | int (*fl_change)(struct file_lock **, int); |
348 | 347 | ||
349 | locking rules: | 348 | locking rules: |
@@ -353,7 +352,6 @@ fl_notify: yes no | |||
353 | fl_grant: no no | 352 | fl_grant: no no |
354 | fl_release_private: maybe no | 353 | fl_release_private: maybe no |
355 | fl_break: yes no | 354 | fl_break: yes no |
356 | fl_mylease: yes no | ||
357 | fl_change yes no | 355 | fl_change yes no |
358 | 356 | ||
359 | --------------------------- buffer_head ----------------------------------- | 357 | --------------------------- buffer_head ----------------------------------- |
diff --git a/fs/locks.c b/fs/locks.c index 08415b2a6d36..0f3998291f78 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -444,15 +444,9 @@ static void lease_release_private_callback(struct file_lock *fl) | |||
444 | fl->fl_file->f_owner.signum = 0; | 444 | fl->fl_file->f_owner.signum = 0; |
445 | } | 445 | } |
446 | 446 | ||
447 | static int lease_mylease_callback(struct file_lock *fl, struct file_lock *try) | ||
448 | { | ||
449 | return fl->fl_file == try->fl_file; | ||
450 | } | ||
451 | |||
452 | static const struct lock_manager_operations lease_manager_ops = { | 447 | static const struct lock_manager_operations lease_manager_ops = { |
453 | .fl_break = lease_break_callback, | 448 | .fl_break = lease_break_callback, |
454 | .fl_release_private = lease_release_private_callback, | 449 | .fl_release_private = lease_release_private_callback, |
455 | .fl_mylease = lease_mylease_callback, | ||
456 | .fl_change = lease_modify, | 450 | .fl_change = lease_modify, |
457 | }; | 451 | }; |
458 | 452 | ||
@@ -1405,7 +1399,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1405 | for (before = &inode->i_flock; | 1399 | for (before = &inode->i_flock; |
1406 | ((fl = *before) != NULL) && IS_LEASE(fl); | 1400 | ((fl = *before) != NULL) && IS_LEASE(fl); |
1407 | before = &fl->fl_next) { | 1401 | before = &fl->fl_next) { |
1408 | if (lease->fl_lmops->fl_mylease(fl, lease)) | 1402 | if (fl->fl_file == filp) |
1409 | my_before = before; | 1403 | my_before = before; |
1410 | else if (fl->fl_type == (F_INPROGRESS | F_UNLCK)) | 1404 | else if (fl->fl_type == (F_INPROGRESS | F_UNLCK)) |
1411 | /* | 1405 | /* |
diff --git a/include/linux/nfs4_acl.h b/fs/nfsd/acl.h index c9c05a78e9bb..34e5c40af5ef 100644 --- a/include/linux/nfs4_acl.h +++ b/fs/nfsd/acl.h | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * include/linux/nfs4_acl.c | ||
3 | * | ||
4 | * Common NFSv4 ACL handling definitions. | 2 | * Common NFSv4 ACL handling definitions. |
5 | * | 3 | * |
6 | * Copyright (c) 2002 The Regents of the University of Michigan. | 4 | * Copyright (c) 2002 The Regents of the University of Michigan. |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index c0fcb7ab7f6d..8b31e5f8795d 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define MSNFS /* HACK HACK */ | ||
2 | /* | 1 | /* |
3 | * NFS exporting and validation. | 2 | * NFS exporting and validation. |
4 | * | 3 | * |
@@ -1444,9 +1443,6 @@ static struct flags { | |||
1444 | { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, | 1443 | { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, |
1445 | { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, | 1444 | { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, |
1446 | { NFSEXP_V4ROOT, {"v4root", ""}}, | 1445 | { NFSEXP_V4ROOT, {"v4root", ""}}, |
1447 | #ifdef MSNFS | ||
1448 | { NFSEXP_MSNFS, {"msnfs", ""}}, | ||
1449 | #endif | ||
1450 | { 0, {"", ""}} | 1446 | { 0, {"", ""}} |
1451 | }; | 1447 | }; |
1452 | 1448 | ||
diff --git a/include/linux/nfsd_idmap.h b/fs/nfsd/idmap.h index d4a2ac18bd4c..2f3be1321534 100644 --- a/include/linux/nfsd_idmap.h +++ b/fs/nfsd/idmap.h | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * include/linux/nfsd_idmap.h | ||
3 | * | ||
4 | * Mapping of UID to name and vice versa. | 2 | * Mapping of UID to name and vice versa. |
5 | * | 3 | * |
6 | * Copyright (c) 2002, 2003 The Regents of the University of | 4 | * Copyright (c) 2002, 2003 The Regents of the University of |
@@ -56,8 +54,8 @@ static inline void nfsd_idmap_shutdown(void) | |||
56 | } | 54 | } |
57 | #endif | 55 | #endif |
58 | 56 | ||
59 | int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *); | 57 | __be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *); |
60 | int nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *); | 58 | __be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *); |
61 | int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *); | 59 | int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *); |
62 | int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *); | 60 | int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *); |
63 | 61 | ||
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 5b7e3021e06b..2247fc91d5e9 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -151,10 +151,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, | |||
151 | __be32 nfserr; | 151 | __be32 nfserr; |
152 | u32 max_blocksize = svc_max_payload(rqstp); | 152 | u32 max_blocksize = svc_max_payload(rqstp); |
153 | 153 | ||
154 | dprintk("nfsd: READ(3) %s %lu bytes at %lu\n", | 154 | dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n", |
155 | SVCFH_fmt(&argp->fh), | 155 | SVCFH_fmt(&argp->fh), |
156 | (unsigned long) argp->count, | 156 | (unsigned long) argp->count, |
157 | (unsigned long) argp->offset); | 157 | (unsigned long long) argp->offset); |
158 | 158 | ||
159 | /* Obtain buffer pointer for payload. | 159 | /* Obtain buffer pointer for payload. |
160 | * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) | 160 | * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) |
@@ -191,10 +191,10 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, | |||
191 | __be32 nfserr; | 191 | __be32 nfserr; |
192 | unsigned long cnt = argp->len; | 192 | unsigned long cnt = argp->len; |
193 | 193 | ||
194 | dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n", | 194 | dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n", |
195 | SVCFH_fmt(&argp->fh), | 195 | SVCFH_fmt(&argp->fh), |
196 | argp->len, | 196 | argp->len, |
197 | (unsigned long) argp->offset, | 197 | (unsigned long long) argp->offset, |
198 | argp->stable? " stable" : ""); | 198 | argp->stable? " stable" : ""); |
199 | 199 | ||
200 | fh_copy(&resp->fh, &argp->fh); | 200 | fh_copy(&resp->fh, &argp->fh); |
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index e48052615159..ad88f1c0a4c3 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -36,7 +36,7 @@ | |||
36 | 36 | ||
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/nfs_fs.h> | 38 | #include <linux/nfs_fs.h> |
39 | #include <linux/nfs4_acl.h> | 39 | #include "acl.h" |
40 | 40 | ||
41 | 41 | ||
42 | /* mode bit translations: */ | 42 | /* mode bit translations: */ |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 21a63da305ff..3be975e18919 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -628,10 +628,8 @@ static int max_cb_time(void) | |||
628 | return max(nfsd4_lease/10, (time_t)1) * HZ; | 628 | return max(nfsd4_lease/10, (time_t)1) * HZ; |
629 | } | 629 | } |
630 | 630 | ||
631 | /* Reference counting, callback cleanup, etc., all look racy as heck. | ||
632 | * And why is cl_cb_set an atomic? */ | ||
633 | 631 | ||
634 | int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn) | 632 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) |
635 | { | 633 | { |
636 | struct rpc_timeout timeparms = { | 634 | struct rpc_timeout timeparms = { |
637 | .to_initval = max_cb_time(), | 635 | .to_initval = max_cb_time(), |
@@ -641,6 +639,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn) | |||
641 | .net = &init_net, | 639 | .net = &init_net, |
642 | .address = (struct sockaddr *) &conn->cb_addr, | 640 | .address = (struct sockaddr *) &conn->cb_addr, |
643 | .addrsize = conn->cb_addrlen, | 641 | .addrsize = conn->cb_addrlen, |
642 | .saddress = (struct sockaddr *) &conn->cb_saddr, | ||
644 | .timeout = &timeparms, | 643 | .timeout = &timeparms, |
645 | .program = &cb_program, | 644 | .program = &cb_program, |
646 | .version = 0, | 645 | .version = 0, |
@@ -657,6 +656,10 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn) | |||
657 | args.protocol = XPRT_TRANSPORT_TCP; | 656 | args.protocol = XPRT_TRANSPORT_TCP; |
658 | clp->cl_cb_ident = conn->cb_ident; | 657 | clp->cl_cb_ident = conn->cb_ident; |
659 | } else { | 658 | } else { |
659 | if (!conn->cb_xprt) | ||
660 | return -EINVAL; | ||
661 | clp->cl_cb_conn.cb_xprt = conn->cb_xprt; | ||
662 | clp->cl_cb_session = ses; | ||
660 | args.bc_xprt = conn->cb_xprt; | 663 | args.bc_xprt = conn->cb_xprt; |
661 | args.prognumber = clp->cl_cb_session->se_cb_prog; | 664 | args.prognumber = clp->cl_cb_session->se_cb_prog; |
662 | args.protocol = XPRT_TRANSPORT_BC_TCP; | 665 | args.protocol = XPRT_TRANSPORT_BC_TCP; |
@@ -679,14 +682,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason) | |||
679 | (int)clp->cl_name.len, clp->cl_name.data, reason); | 682 | (int)clp->cl_name.len, clp->cl_name.data, reason); |
680 | } | 683 | } |
681 | 684 | ||
685 | static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) | ||
686 | { | ||
687 | clp->cl_cb_state = NFSD4_CB_DOWN; | ||
688 | warn_no_callback_path(clp, reason); | ||
689 | } | ||
690 | |||
682 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) | 691 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) |
683 | { | 692 | { |
684 | struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); | 693 | struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); |
685 | 694 | ||
686 | if (task->tk_status) | 695 | if (task->tk_status) |
687 | warn_no_callback_path(clp, task->tk_status); | 696 | nfsd4_mark_cb_down(clp, task->tk_status); |
688 | else | 697 | else |
689 | atomic_set(&clp->cl_cb_set, 1); | 698 | clp->cl_cb_state = NFSD4_CB_UP; |
690 | } | 699 | } |
691 | 700 | ||
692 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { | 701 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { |
@@ -709,6 +718,11 @@ int set_callback_cred(void) | |||
709 | 718 | ||
710 | static struct workqueue_struct *callback_wq; | 719 | static struct workqueue_struct *callback_wq; |
711 | 720 | ||
721 | static void run_nfsd4_cb(struct nfsd4_callback *cb) | ||
722 | { | ||
723 | queue_work(callback_wq, &cb->cb_work); | ||
724 | } | ||
725 | |||
712 | static void do_probe_callback(struct nfs4_client *clp) | 726 | static void do_probe_callback(struct nfs4_client *clp) |
713 | { | 727 | { |
714 | struct nfsd4_callback *cb = &clp->cl_cb_null; | 728 | struct nfsd4_callback *cb = &clp->cl_cb_null; |
@@ -723,7 +737,7 @@ static void do_probe_callback(struct nfs4_client *clp) | |||
723 | 737 | ||
724 | cb->cb_ops = &nfsd4_cb_probe_ops; | 738 | cb->cb_ops = &nfsd4_cb_probe_ops; |
725 | 739 | ||
726 | queue_work(callback_wq, &cb->cb_work); | 740 | run_nfsd4_cb(cb); |
727 | } | 741 | } |
728 | 742 | ||
729 | /* | 743 | /* |
@@ -732,14 +746,21 @@ static void do_probe_callback(struct nfs4_client *clp) | |||
732 | */ | 746 | */ |
733 | void nfsd4_probe_callback(struct nfs4_client *clp) | 747 | void nfsd4_probe_callback(struct nfs4_client *clp) |
734 | { | 748 | { |
749 | /* XXX: atomicity? Also, should we be using cl_cb_flags? */ | ||
750 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; | ||
735 | set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); | 751 | set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); |
736 | do_probe_callback(clp); | 752 | do_probe_callback(clp); |
737 | } | 753 | } |
738 | 754 | ||
739 | void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) | 755 | void nfsd4_probe_callback_sync(struct nfs4_client *clp) |
740 | { | 756 | { |
741 | BUG_ON(atomic_read(&clp->cl_cb_set)); | 757 | nfsd4_probe_callback(clp); |
758 | flush_workqueue(callback_wq); | ||
759 | } | ||
742 | 760 | ||
761 | void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) | ||
762 | { | ||
763 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; | ||
743 | spin_lock(&clp->cl_lock); | 764 | spin_lock(&clp->cl_lock); |
744 | memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); | 765 | memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); |
745 | spin_unlock(&clp->cl_lock); | 766 | spin_unlock(&clp->cl_lock); |
@@ -750,24 +771,14 @@ void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) | |||
750 | * If the slot is available, then mark it busy. Otherwise, set the | 771 | * If the slot is available, then mark it busy. Otherwise, set the |
751 | * thread for sleeping on the callback RPC wait queue. | 772 | * thread for sleeping on the callback RPC wait queue. |
752 | */ | 773 | */ |
753 | static int nfsd41_cb_setup_sequence(struct nfs4_client *clp, | 774 | static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task) |
754 | struct rpc_task *task) | ||
755 | { | 775 | { |
756 | u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data; | ||
757 | int status = 0; | ||
758 | |||
759 | dprintk("%s: %u:%u:%u:%u\n", __func__, | ||
760 | ptr[0], ptr[1], ptr[2], ptr[3]); | ||
761 | |||
762 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { | 776 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { |
763 | rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); | 777 | rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); |
764 | dprintk("%s slot is busy\n", __func__); | 778 | dprintk("%s slot is busy\n", __func__); |
765 | status = -EAGAIN; | 779 | return false; |
766 | goto out; | ||
767 | } | 780 | } |
768 | out: | 781 | return true; |
769 | dprintk("%s status=%d\n", __func__, status); | ||
770 | return status; | ||
771 | } | 782 | } |
772 | 783 | ||
773 | /* | 784 | /* |
@@ -780,20 +791,19 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | |||
780 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | 791 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); |
781 | struct nfs4_client *clp = dp->dl_client; | 792 | struct nfs4_client *clp = dp->dl_client; |
782 | u32 minorversion = clp->cl_minorversion; | 793 | u32 minorversion = clp->cl_minorversion; |
783 | int status = 0; | ||
784 | 794 | ||
785 | cb->cb_minorversion = minorversion; | 795 | cb->cb_minorversion = minorversion; |
786 | if (minorversion) { | 796 | if (minorversion) { |
787 | status = nfsd41_cb_setup_sequence(clp, task); | 797 | if (!nfsd41_cb_get_slot(clp, task)) |
788 | if (status) { | ||
789 | if (status != -EAGAIN) { | ||
790 | /* terminate rpc task */ | ||
791 | task->tk_status = status; | ||
792 | task->tk_action = NULL; | ||
793 | } | ||
794 | return; | 798 | return; |
795 | } | ||
796 | } | 799 | } |
800 | spin_lock(&clp->cl_lock); | ||
801 | if (list_empty(&cb->cb_per_client)) { | ||
802 | /* This is the first call, not a restart */ | ||
803 | cb->cb_done = false; | ||
804 | list_add(&cb->cb_per_client, &clp->cl_callbacks); | ||
805 | } | ||
806 | spin_unlock(&clp->cl_lock); | ||
797 | rpc_call_start(task); | 807 | rpc_call_start(task); |
798 | } | 808 | } |
799 | 809 | ||
@@ -829,15 +839,18 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
829 | 839 | ||
830 | nfsd4_cb_done(task, calldata); | 840 | nfsd4_cb_done(task, calldata); |
831 | 841 | ||
832 | if (current_rpc_client == NULL) { | 842 | if (current_rpc_client != task->tk_client) { |
833 | /* We're shutting down; give up. */ | 843 | /* We're shutting down or changing cl_cb_client; leave |
834 | /* XXX: err, or is it ok just to fall through | 844 | * it to nfsd4_process_cb_update to restart the call if |
835 | * and rpc_restart_call? */ | 845 | * necessary. */ |
836 | return; | 846 | return; |
837 | } | 847 | } |
838 | 848 | ||
849 | if (cb->cb_done) | ||
850 | return; | ||
839 | switch (task->tk_status) { | 851 | switch (task->tk_status) { |
840 | case 0: | 852 | case 0: |
853 | cb->cb_done = true; | ||
841 | return; | 854 | return; |
842 | case -EBADHANDLE: | 855 | case -EBADHANDLE: |
843 | case -NFS4ERR_BAD_STATEID: | 856 | case -NFS4ERR_BAD_STATEID: |
@@ -846,32 +859,30 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
846 | break; | 859 | break; |
847 | default: | 860 | default: |
848 | /* Network partition? */ | 861 | /* Network partition? */ |
849 | atomic_set(&clp->cl_cb_set, 0); | 862 | nfsd4_mark_cb_down(clp, task->tk_status); |
850 | warn_no_callback_path(clp, task->tk_status); | ||
851 | if (current_rpc_client != task->tk_client) { | ||
852 | /* queue a callback on the new connection: */ | ||
853 | atomic_inc(&dp->dl_count); | ||
854 | nfsd4_cb_recall(dp); | ||
855 | return; | ||
856 | } | ||
857 | } | 863 | } |
858 | if (dp->dl_retries--) { | 864 | if (dp->dl_retries--) { |
859 | rpc_delay(task, 2*HZ); | 865 | rpc_delay(task, 2*HZ); |
860 | task->tk_status = 0; | 866 | task->tk_status = 0; |
861 | rpc_restart_call_prepare(task); | 867 | rpc_restart_call_prepare(task); |
862 | return; | 868 | return; |
863 | } else { | ||
864 | atomic_set(&clp->cl_cb_set, 0); | ||
865 | warn_no_callback_path(clp, task->tk_status); | ||
866 | } | 869 | } |
870 | nfsd4_mark_cb_down(clp, task->tk_status); | ||
871 | cb->cb_done = true; | ||
867 | } | 872 | } |
868 | 873 | ||
869 | static void nfsd4_cb_recall_release(void *calldata) | 874 | static void nfsd4_cb_recall_release(void *calldata) |
870 | { | 875 | { |
871 | struct nfsd4_callback *cb = calldata; | 876 | struct nfsd4_callback *cb = calldata; |
877 | struct nfs4_client *clp = cb->cb_clp; | ||
872 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | 878 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); |
873 | 879 | ||
874 | nfs4_put_delegation(dp); | 880 | if (cb->cb_done) { |
881 | spin_lock(&clp->cl_lock); | ||
882 | list_del(&cb->cb_per_client); | ||
883 | spin_unlock(&clp->cl_lock); | ||
884 | nfs4_put_delegation(dp); | ||
885 | } | ||
875 | } | 886 | } |
876 | 887 | ||
877 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | 888 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { |
@@ -906,16 +917,33 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp) | |||
906 | flush_workqueue(callback_wq); | 917 | flush_workqueue(callback_wq); |
907 | } | 918 | } |
908 | 919 | ||
909 | void nfsd4_release_cb(struct nfsd4_callback *cb) | 920 | static void nfsd4_release_cb(struct nfsd4_callback *cb) |
910 | { | 921 | { |
911 | if (cb->cb_ops->rpc_release) | 922 | if (cb->cb_ops->rpc_release) |
912 | cb->cb_ops->rpc_release(cb); | 923 | cb->cb_ops->rpc_release(cb); |
913 | } | 924 | } |
914 | 925 | ||
915 | void nfsd4_process_cb_update(struct nfsd4_callback *cb) | 926 | /* requires cl_lock: */ |
927 | static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp) | ||
928 | { | ||
929 | struct nfsd4_session *s; | ||
930 | struct nfsd4_conn *c; | ||
931 | |||
932 | list_for_each_entry(s, &clp->cl_sessions, se_perclnt) { | ||
933 | list_for_each_entry(c, &s->se_conns, cn_persession) { | ||
934 | if (c->cn_flags & NFS4_CDFC4_BACK) | ||
935 | return c; | ||
936 | } | ||
937 | } | ||
938 | return NULL; | ||
939 | } | ||
940 | |||
941 | static void nfsd4_process_cb_update(struct nfsd4_callback *cb) | ||
916 | { | 942 | { |
917 | struct nfs4_cb_conn conn; | 943 | struct nfs4_cb_conn conn; |
918 | struct nfs4_client *clp = cb->cb_clp; | 944 | struct nfs4_client *clp = cb->cb_clp; |
945 | struct nfsd4_session *ses = NULL; | ||
946 | struct nfsd4_conn *c; | ||
919 | int err; | 947 | int err; |
920 | 948 | ||
921 | /* | 949 | /* |
@@ -926,6 +954,10 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb) | |||
926 | rpc_shutdown_client(clp->cl_cb_client); | 954 | rpc_shutdown_client(clp->cl_cb_client); |
927 | clp->cl_cb_client = NULL; | 955 | clp->cl_cb_client = NULL; |
928 | } | 956 | } |
957 | if (clp->cl_cb_conn.cb_xprt) { | ||
958 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); | ||
959 | clp->cl_cb_conn.cb_xprt = NULL; | ||
960 | } | ||
929 | if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags)) | 961 | if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags)) |
930 | return; | 962 | return; |
931 | spin_lock(&clp->cl_lock); | 963 | spin_lock(&clp->cl_lock); |
@@ -936,11 +968,22 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb) | |||
936 | BUG_ON(!clp->cl_cb_flags); | 968 | BUG_ON(!clp->cl_cb_flags); |
937 | clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); | 969 | clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); |
938 | memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn)); | 970 | memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn)); |
971 | c = __nfsd4_find_backchannel(clp); | ||
972 | if (c) { | ||
973 | svc_xprt_get(c->cn_xprt); | ||
974 | conn.cb_xprt = c->cn_xprt; | ||
975 | ses = c->cn_session; | ||
976 | } | ||
939 | spin_unlock(&clp->cl_lock); | 977 | spin_unlock(&clp->cl_lock); |
940 | 978 | ||
941 | err = setup_callback_client(clp, &conn); | 979 | err = setup_callback_client(clp, &conn, ses); |
942 | if (err) | 980 | if (err) { |
943 | warn_no_callback_path(clp, err); | 981 | warn_no_callback_path(clp, err); |
982 | return; | ||
983 | } | ||
984 | /* Yay, the callback channel's back! Restart any callbacks: */ | ||
985 | list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client) | ||
986 | run_nfsd4_cb(cb); | ||
944 | } | 987 | } |
945 | 988 | ||
946 | void nfsd4_do_callback_rpc(struct work_struct *w) | 989 | void nfsd4_do_callback_rpc(struct work_struct *w) |
@@ -965,10 +1008,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w) | |||
965 | void nfsd4_cb_recall(struct nfs4_delegation *dp) | 1008 | void nfsd4_cb_recall(struct nfs4_delegation *dp) |
966 | { | 1009 | { |
967 | struct nfsd4_callback *cb = &dp->dl_recall; | 1010 | struct nfsd4_callback *cb = &dp->dl_recall; |
1011 | struct nfs4_client *clp = dp->dl_client; | ||
968 | 1012 | ||
969 | dp->dl_retries = 1; | 1013 | dp->dl_retries = 1; |
970 | cb->cb_op = dp; | 1014 | cb->cb_op = dp; |
971 | cb->cb_clp = dp->dl_client; | 1015 | cb->cb_clp = clp; |
972 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; | 1016 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; |
973 | cb->cb_msg.rpc_argp = cb; | 1017 | cb->cb_msg.rpc_argp = cb; |
974 | cb->cb_msg.rpc_resp = cb; | 1018 | cb->cb_msg.rpc_resp = cb; |
@@ -977,5 +1021,8 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
977 | cb->cb_ops = &nfsd4_cb_recall_ops; | 1021 | cb->cb_ops = &nfsd4_cb_recall_ops; |
978 | dp->dl_retries = 1; | 1022 | dp->dl_retries = 1; |
979 | 1023 | ||
980 | queue_work(callback_wq, &dp->dl_recall.cb_work); | 1024 | INIT_LIST_HEAD(&cb->cb_per_client); |
1025 | cb->cb_done = true; | ||
1026 | |||
1027 | run_nfsd4_cb(&dp->dl_recall); | ||
981 | } | 1028 | } |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index f0695e815f0e..6d2c397d458b 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -33,10 +33,11 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/nfsd_idmap.h> | ||
37 | #include <linux/seq_file.h> | 36 | #include <linux/seq_file.h> |
38 | #include <linux/sched.h> | 37 | #include <linux/sched.h> |
39 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include "idmap.h" | ||
40 | #include "nfsd.h" | ||
40 | 41 | ||
41 | /* | 42 | /* |
42 | * Cache entry | 43 | * Cache entry |
@@ -514,7 +515,7 @@ rqst_authname(struct svc_rqst *rqstp) | |||
514 | return clp->name; | 515 | return clp->name; |
515 | } | 516 | } |
516 | 517 | ||
517 | static int | 518 | static __be32 |
518 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, | 519 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, |
519 | uid_t *id) | 520 | uid_t *id) |
520 | { | 521 | { |
@@ -524,15 +525,15 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen | |||
524 | int ret; | 525 | int ret; |
525 | 526 | ||
526 | if (namelen + 1 > sizeof(key.name)) | 527 | if (namelen + 1 > sizeof(key.name)) |
527 | return -EINVAL; | 528 | return nfserr_badowner; |
528 | memcpy(key.name, name, namelen); | 529 | memcpy(key.name, name, namelen); |
529 | key.name[namelen] = '\0'; | 530 | key.name[namelen] = '\0'; |
530 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); | 531 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); |
531 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); | 532 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); |
532 | if (ret == -ENOENT) | 533 | if (ret == -ENOENT) |
533 | ret = -ESRCH; /* nfserr_badname */ | 534 | return nfserr_badowner; |
534 | if (ret) | 535 | if (ret) |
535 | return ret; | 536 | return nfserrno(ret); |
536 | *id = item->id; | 537 | *id = item->id; |
537 | cache_put(&item->h, &nametoid_cache); | 538 | cache_put(&item->h, &nametoid_cache); |
538 | return 0; | 539 | return 0; |
@@ -560,14 +561,14 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | |||
560 | return ret; | 561 | return ret; |
561 | } | 562 | } |
562 | 563 | ||
563 | int | 564 | __be32 |
564 | nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, | 565 | nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, |
565 | __u32 *id) | 566 | __u32 *id) |
566 | { | 567 | { |
567 | return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); | 568 | return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); |
568 | } | 569 | } |
569 | 570 | ||
570 | int | 571 | __be32 |
571 | nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, | 572 | nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, |
572 | __u32 *id) | 573 | __u32 *id) |
573 | { | 574 | { |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0cdfd022bb7b..db52546143d1 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -604,9 +604,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
604 | return status; | 604 | return status; |
605 | } | 605 | } |
606 | 606 | ||
607 | static __be32 | 607 | static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh) |
608 | nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
609 | void *arg) | ||
610 | { | 608 | { |
611 | struct svc_fh tmp_fh; | 609 | struct svc_fh tmp_fh; |
612 | __be32 ret; | 610 | __be32 ret; |
@@ -615,13 +613,19 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
615 | ret = exp_pseudoroot(rqstp, &tmp_fh); | 613 | ret = exp_pseudoroot(rqstp, &tmp_fh); |
616 | if (ret) | 614 | if (ret) |
617 | return ret; | 615 | return ret; |
618 | if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { | 616 | if (tmp_fh.fh_dentry == fh->fh_dentry) { |
619 | fh_put(&tmp_fh); | 617 | fh_put(&tmp_fh); |
620 | return nfserr_noent; | 618 | return nfserr_noent; |
621 | } | 619 | } |
622 | fh_put(&tmp_fh); | 620 | fh_put(&tmp_fh); |
623 | return nfsd_lookup(rqstp, &cstate->current_fh, | 621 | return nfsd_lookup(rqstp, fh, "..", 2, fh); |
624 | "..", 2, &cstate->current_fh); | 622 | } |
623 | |||
624 | static __be32 | ||
625 | nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
626 | void *arg) | ||
627 | { | ||
628 | return nfsd4_do_lookupp(rqstp, &cstate->current_fh); | ||
625 | } | 629 | } |
626 | 630 | ||
627 | static __be32 | 631 | static __be32 |
@@ -769,10 +773,36 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
769 | } else | 773 | } else |
770 | secinfo->si_exp = exp; | 774 | secinfo->si_exp = exp; |
771 | dput(dentry); | 775 | dput(dentry); |
776 | if (cstate->minorversion) | ||
777 | /* See rfc 5661 section 2.6.3.1.1.8 */ | ||
778 | fh_put(&cstate->current_fh); | ||
772 | return err; | 779 | return err; |
773 | } | 780 | } |
774 | 781 | ||
775 | static __be32 | 782 | static __be32 |
783 | nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
784 | struct nfsd4_secinfo_no_name *sin) | ||
785 | { | ||
786 | __be32 err; | ||
787 | |||
788 | switch (sin->sin_style) { | ||
789 | case NFS4_SECINFO_STYLE4_CURRENT_FH: | ||
790 | break; | ||
791 | case NFS4_SECINFO_STYLE4_PARENT: | ||
792 | err = nfsd4_do_lookupp(rqstp, &cstate->current_fh); | ||
793 | if (err) | ||
794 | return err; | ||
795 | break; | ||
796 | default: | ||
797 | return nfserr_inval; | ||
798 | } | ||
799 | exp_get(cstate->current_fh.fh_export); | ||
800 | sin->sin_exp = cstate->current_fh.fh_export; | ||
801 | fh_put(&cstate->current_fh); | ||
802 | return nfs_ok; | ||
803 | } | ||
804 | |||
805 | static __be32 | ||
776 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 806 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
777 | struct nfsd4_setattr *setattr) | 807 | struct nfsd4_setattr *setattr) |
778 | { | 808 | { |
@@ -974,8 +1004,8 @@ static const char *nfsd4_op_name(unsigned opnum); | |||
974 | * Also note, enforced elsewhere: | 1004 | * Also note, enforced elsewhere: |
975 | * - SEQUENCE other than as first op results in | 1005 | * - SEQUENCE other than as first op results in |
976 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) | 1006 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) |
977 | * - BIND_CONN_TO_SESSION must be the only op in its compound | 1007 | * - BIND_CONN_TO_SESSION must be the only op in its compound. |
978 | * (Will be enforced in nfsd4_bind_conn_to_session().) | 1008 | * (Enforced in nfsd4_bind_conn_to_session().) |
979 | * - DESTROY_SESSION must be the final operation in a compound, if | 1009 | * - DESTROY_SESSION must be the final operation in a compound, if |
980 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. | 1010 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. |
981 | * (Enforced in nfsd4_destroy_session().) | 1011 | * (Enforced in nfsd4_destroy_session().) |
@@ -1126,10 +1156,6 @@ encode_op: | |||
1126 | 1156 | ||
1127 | nfsd4_increment_op_stats(op->opnum); | 1157 | nfsd4_increment_op_stats(op->opnum); |
1128 | } | 1158 | } |
1129 | if (!rqstp->rq_usedeferral && status == nfserr_dropit) { | ||
1130 | dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__); | ||
1131 | status = nfserr_jukebox; | ||
1132 | } | ||
1133 | 1159 | ||
1134 | resp->cstate.status = status; | 1160 | resp->cstate.status = status; |
1135 | fh_put(&resp->cstate.current_fh); | 1161 | fh_put(&resp->cstate.current_fh); |
@@ -1300,6 +1326,11 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1300 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1326 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
1301 | .op_name = "OP_EXCHANGE_ID", | 1327 | .op_name = "OP_EXCHANGE_ID", |
1302 | }, | 1328 | }, |
1329 | [OP_BIND_CONN_TO_SESSION] = { | ||
1330 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | ||
1331 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | ||
1332 | .op_name = "OP_BIND_CONN_TO_SESSION", | ||
1333 | }, | ||
1303 | [OP_CREATE_SESSION] = { | 1334 | [OP_CREATE_SESSION] = { |
1304 | .op_func = (nfsd4op_func)nfsd4_create_session, | 1335 | .op_func = (nfsd4op_func)nfsd4_create_session, |
1305 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1336 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
@@ -1320,6 +1351,10 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1320 | .op_flags = ALLOWED_WITHOUT_FH, | 1351 | .op_flags = ALLOWED_WITHOUT_FH, |
1321 | .op_name = "OP_RECLAIM_COMPLETE", | 1352 | .op_name = "OP_RECLAIM_COMPLETE", |
1322 | }, | 1353 | }, |
1354 | [OP_SECINFO_NO_NAME] = { | ||
1355 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, | ||
1356 | .op_name = "OP_SECINFO_NO_NAME", | ||
1357 | }, | ||
1323 | }; | 1358 | }; |
1324 | 1359 | ||
1325 | static const char *nfsd4_op_name(unsigned opnum) | 1360 | static const char *nfsd4_op_name(unsigned opnum) |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 7e26caab2a26..ffb59ef6f82f 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -302,7 +302,6 @@ purge_old(struct dentry *parent, struct dentry *child) | |||
302 | { | 302 | { |
303 | int status; | 303 | int status; |
304 | 304 | ||
305 | /* note: we currently use this path only for minorversion 0 */ | ||
306 | if (nfs4_has_reclaimed_state(child->d_name.name, false)) | 305 | if (nfs4_has_reclaimed_state(child->d_name.name, false)) |
307 | return 0; | 306 | return 0; |
308 | 307 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fbd18c3074bb..d98d0213285d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -230,7 +230,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
230 | dp->dl_client = clp; | 230 | dp->dl_client = clp; |
231 | get_nfs4_file(fp); | 231 | get_nfs4_file(fp); |
232 | dp->dl_file = fp; | 232 | dp->dl_file = fp; |
233 | nfs4_file_get_access(fp, O_RDONLY); | 233 | dp->dl_vfs_file = find_readable_file(fp); |
234 | get_file(dp->dl_vfs_file); | ||
234 | dp->dl_flock = NULL; | 235 | dp->dl_flock = NULL; |
235 | dp->dl_type = type; | 236 | dp->dl_type = type; |
236 | dp->dl_stateid.si_boot = boot_time; | 237 | dp->dl_stateid.si_boot = boot_time; |
@@ -252,6 +253,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
252 | if (atomic_dec_and_test(&dp->dl_count)) { | 253 | if (atomic_dec_and_test(&dp->dl_count)) { |
253 | dprintk("NFSD: freeing dp %p\n",dp); | 254 | dprintk("NFSD: freeing dp %p\n",dp); |
254 | put_nfs4_file(dp->dl_file); | 255 | put_nfs4_file(dp->dl_file); |
256 | fput(dp->dl_vfs_file); | ||
255 | kmem_cache_free(deleg_slab, dp); | 257 | kmem_cache_free(deleg_slab, dp); |
256 | num_delegations--; | 258 | num_delegations--; |
257 | } | 259 | } |
@@ -265,12 +267,10 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
265 | static void | 267 | static void |
266 | nfs4_close_delegation(struct nfs4_delegation *dp) | 268 | nfs4_close_delegation(struct nfs4_delegation *dp) |
267 | { | 269 | { |
268 | struct file *filp = find_readable_file(dp->dl_file); | ||
269 | |||
270 | dprintk("NFSD: close_delegation dp %p\n",dp); | 270 | dprintk("NFSD: close_delegation dp %p\n",dp); |
271 | /* XXX: do we even need this check?: */ | ||
271 | if (dp->dl_flock) | 272 | if (dp->dl_flock) |
272 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); | 273 | vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock); |
273 | nfs4_file_put_access(dp->dl_file, O_RDONLY); | ||
274 | } | 274 | } |
275 | 275 | ||
276 | /* Called under the state lock. */ | 276 | /* Called under the state lock. */ |
@@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u) | |||
642 | free_conn(c); | 642 | free_conn(c); |
643 | } | 643 | } |
644 | spin_unlock(&clp->cl_lock); | 644 | spin_unlock(&clp->cl_lock); |
645 | nfsd4_probe_callback(clp); | ||
645 | } | 646 | } |
646 | 647 | ||
647 | static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) | 648 | static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) |
@@ -679,15 +680,12 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn) | |||
679 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); | 680 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); |
680 | } | 681 | } |
681 | 682 | ||
682 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) | 683 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) |
683 | { | 684 | { |
684 | struct nfsd4_conn *conn; | 685 | struct nfsd4_conn *conn; |
685 | u32 flags = NFS4_CDFC4_FORE; | ||
686 | int ret; | 686 | int ret; |
687 | 687 | ||
688 | if (ses->se_flags & SESSION4_BACK_CHAN) | 688 | conn = alloc_conn(rqstp, dir); |
689 | flags |= NFS4_CDFC4_BACK; | ||
690 | conn = alloc_conn(rqstp, flags); | ||
691 | if (!conn) | 689 | if (!conn) |
692 | return nfserr_jukebox; | 690 | return nfserr_jukebox; |
693 | nfsd4_hash_conn(conn, ses); | 691 | nfsd4_hash_conn(conn, ses); |
@@ -698,6 +696,17 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) | |||
698 | return nfs_ok; | 696 | return nfs_ok; |
699 | } | 697 | } |
700 | 698 | ||
699 | static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) | ||
700 | { | ||
701 | u32 dir = NFS4_CDFC4_FORE; | ||
702 | |||
703 | if (ses->se_flags & SESSION4_BACK_CHAN) | ||
704 | dir |= NFS4_CDFC4_BACK; | ||
705 | |||
706 | return nfsd4_new_conn(rqstp, ses, dir); | ||
707 | } | ||
708 | |||
709 | /* must be called under client_lock */ | ||
701 | static void nfsd4_del_conns(struct nfsd4_session *s) | 710 | static void nfsd4_del_conns(struct nfsd4_session *s) |
702 | { | 711 | { |
703 | struct nfs4_client *clp = s->se_client; | 712 | struct nfs4_client *clp = s->se_client; |
@@ -749,6 +758,8 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
749 | */ | 758 | */ |
750 | slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); | 759 | slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); |
751 | numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); | 760 | numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); |
761 | if (numslots < 1) | ||
762 | return NULL; | ||
752 | 763 | ||
753 | new = alloc_session(slotsize, numslots); | 764 | new = alloc_session(slotsize, numslots); |
754 | if (!new) { | 765 | if (!new) { |
@@ -769,25 +780,30 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
769 | idx = hash_sessionid(&new->se_sessionid); | 780 | idx = hash_sessionid(&new->se_sessionid); |
770 | spin_lock(&client_lock); | 781 | spin_lock(&client_lock); |
771 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | 782 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); |
783 | spin_lock(&clp->cl_lock); | ||
772 | list_add(&new->se_perclnt, &clp->cl_sessions); | 784 | list_add(&new->se_perclnt, &clp->cl_sessions); |
785 | spin_unlock(&clp->cl_lock); | ||
773 | spin_unlock(&client_lock); | 786 | spin_unlock(&client_lock); |
774 | 787 | ||
775 | status = nfsd4_new_conn(rqstp, new); | 788 | status = nfsd4_new_conn_from_crses(rqstp, new); |
776 | /* whoops: benny points out, status is ignored! (err, or bogus) */ | 789 | /* whoops: benny points out, status is ignored! (err, or bogus) */ |
777 | if (status) { | 790 | if (status) { |
778 | free_session(&new->se_ref); | 791 | free_session(&new->se_ref); |
779 | return NULL; | 792 | return NULL; |
780 | } | 793 | } |
781 | if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) { | 794 | if (cses->flags & SESSION4_BACK_CHAN) { |
782 | struct sockaddr *sa = svc_addr(rqstp); | 795 | struct sockaddr *sa = svc_addr(rqstp); |
783 | 796 | /* | |
784 | clp->cl_cb_session = new; | 797 | * This is a little silly; with sessions there's no real |
785 | clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt; | 798 | * use for the callback address. Use the peer address |
786 | svc_xprt_get(rqstp->rq_xprt); | 799 | * as a reasonable default for now, but consider fixing |
800 | * the rpc client not to require an address in the | ||
801 | * future: | ||
802 | */ | ||
787 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); | 803 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); |
788 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | 804 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); |
789 | nfsd4_probe_callback(clp); | ||
790 | } | 805 | } |
806 | nfsd4_probe_callback(clp); | ||
791 | return new; | 807 | return new; |
792 | } | 808 | } |
793 | 809 | ||
@@ -817,7 +833,9 @@ static void | |||
817 | unhash_session(struct nfsd4_session *ses) | 833 | unhash_session(struct nfsd4_session *ses) |
818 | { | 834 | { |
819 | list_del(&ses->se_hash); | 835 | list_del(&ses->se_hash); |
836 | spin_lock(&ses->se_client->cl_lock); | ||
820 | list_del(&ses->se_perclnt); | 837 | list_del(&ses->se_perclnt); |
838 | spin_unlock(&ses->se_client->cl_lock); | ||
821 | } | 839 | } |
822 | 840 | ||
823 | /* must be called under the client_lock */ | 841 | /* must be called under the client_lock */ |
@@ -923,8 +941,10 @@ unhash_client_locked(struct nfs4_client *clp) | |||
923 | 941 | ||
924 | mark_client_expired(clp); | 942 | mark_client_expired(clp); |
925 | list_del(&clp->cl_lru); | 943 | list_del(&clp->cl_lru); |
944 | spin_lock(&clp->cl_lock); | ||
926 | list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) | 945 | list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) |
927 | list_del_init(&ses->se_hash); | 946 | list_del_init(&ses->se_hash); |
947 | spin_unlock(&clp->cl_lock); | ||
928 | } | 948 | } |
929 | 949 | ||
930 | static void | 950 | static void |
@@ -1051,12 +1071,13 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
1051 | 1071 | ||
1052 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1072 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
1053 | atomic_set(&clp->cl_refcount, 0); | 1073 | atomic_set(&clp->cl_refcount, 0); |
1054 | atomic_set(&clp->cl_cb_set, 0); | 1074 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
1055 | INIT_LIST_HEAD(&clp->cl_idhash); | 1075 | INIT_LIST_HEAD(&clp->cl_idhash); |
1056 | INIT_LIST_HEAD(&clp->cl_strhash); | 1076 | INIT_LIST_HEAD(&clp->cl_strhash); |
1057 | INIT_LIST_HEAD(&clp->cl_openowners); | 1077 | INIT_LIST_HEAD(&clp->cl_openowners); |
1058 | INIT_LIST_HEAD(&clp->cl_delegations); | 1078 | INIT_LIST_HEAD(&clp->cl_delegations); |
1059 | INIT_LIST_HEAD(&clp->cl_lru); | 1079 | INIT_LIST_HEAD(&clp->cl_lru); |
1080 | INIT_LIST_HEAD(&clp->cl_callbacks); | ||
1060 | spin_lock_init(&clp->cl_lock); | 1081 | spin_lock_init(&clp->cl_lock); |
1061 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); | 1082 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); |
1062 | clp->cl_time = get_seconds(); | 1083 | clp->cl_time = get_seconds(); |
@@ -1132,54 +1153,55 @@ find_unconfirmed_client(clientid_t *clid) | |||
1132 | return NULL; | 1153 | return NULL; |
1133 | } | 1154 | } |
1134 | 1155 | ||
1135 | /* | 1156 | static bool clp_used_exchangeid(struct nfs4_client *clp) |
1136 | * Return 1 iff clp's clientid establishment method matches the use_exchange_id | ||
1137 | * parameter. Matching is based on the fact the at least one of the | ||
1138 | * EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1 | ||
1139 | * | ||
1140 | * FIXME: we need to unify the clientid namespaces for nfsv4.x | ||
1141 | * and correctly deal with client upgrade/downgrade in EXCHANGE_ID | ||
1142 | * and SET_CLIENTID{,_CONFIRM} | ||
1143 | */ | ||
1144 | static inline int | ||
1145 | match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id) | ||
1146 | { | 1157 | { |
1147 | bool has_exchange_flags = (clp->cl_exchange_flags != 0); | 1158 | return clp->cl_exchange_flags != 0; |
1148 | return use_exchange_id == has_exchange_flags; | 1159 | } |
1149 | } | ||
1150 | 1160 | ||
1151 | static struct nfs4_client * | 1161 | static struct nfs4_client * |
1152 | find_confirmed_client_by_str(const char *dname, unsigned int hashval, | 1162 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) |
1153 | bool use_exchange_id) | ||
1154 | { | 1163 | { |
1155 | struct nfs4_client *clp; | 1164 | struct nfs4_client *clp; |
1156 | 1165 | ||
1157 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | 1166 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { |
1158 | if (same_name(clp->cl_recdir, dname) && | 1167 | if (same_name(clp->cl_recdir, dname)) |
1159 | match_clientid_establishment(clp, use_exchange_id)) | ||
1160 | return clp; | 1168 | return clp; |
1161 | } | 1169 | } |
1162 | return NULL; | 1170 | return NULL; |
1163 | } | 1171 | } |
1164 | 1172 | ||
1165 | static struct nfs4_client * | 1173 | static struct nfs4_client * |
1166 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval, | 1174 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) |
1167 | bool use_exchange_id) | ||
1168 | { | 1175 | { |
1169 | struct nfs4_client *clp; | 1176 | struct nfs4_client *clp; |
1170 | 1177 | ||
1171 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | 1178 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { |
1172 | if (same_name(clp->cl_recdir, dname) && | 1179 | if (same_name(clp->cl_recdir, dname)) |
1173 | match_clientid_establishment(clp, use_exchange_id)) | ||
1174 | return clp; | 1180 | return clp; |
1175 | } | 1181 | } |
1176 | return NULL; | 1182 | return NULL; |
1177 | } | 1183 | } |
1178 | 1184 | ||
1185 | static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr) | ||
1186 | { | ||
1187 | switch (family) { | ||
1188 | case AF_INET: | ||
1189 | ((struct sockaddr_in *)sa)->sin_family = AF_INET; | ||
1190 | ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr; | ||
1191 | return; | ||
1192 | case AF_INET6: | ||
1193 | ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; | ||
1194 | ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6; | ||
1195 | return; | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1179 | static void | 1199 | static void |
1180 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) | 1200 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) |
1181 | { | 1201 | { |
1182 | struct nfs4_cb_conn *conn = &clp->cl_cb_conn; | 1202 | struct nfs4_cb_conn *conn = &clp->cl_cb_conn; |
1203 | struct sockaddr *sa = svc_addr(rqstp); | ||
1204 | u32 scopeid = rpc_get_scope_id(sa); | ||
1183 | unsigned short expected_family; | 1205 | unsigned short expected_family; |
1184 | 1206 | ||
1185 | /* Currently, we only support tcp and tcp6 for the callback channel */ | 1207 | /* Currently, we only support tcp and tcp6 for the callback channel */ |
@@ -1205,6 +1227,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) | |||
1205 | 1227 | ||
1206 | conn->cb_prog = se->se_callback_prog; | 1228 | conn->cb_prog = se->se_callback_prog; |
1207 | conn->cb_ident = se->se_callback_ident; | 1229 | conn->cb_ident = se->se_callback_ident; |
1230 | rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr); | ||
1208 | return; | 1231 | return; |
1209 | out_err: | 1232 | out_err: |
1210 | conn->cb_addr.ss_family = AF_UNSPEC; | 1233 | conn->cb_addr.ss_family = AF_UNSPEC; |
@@ -1344,7 +1367,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1344 | case SP4_NONE: | 1367 | case SP4_NONE: |
1345 | break; | 1368 | break; |
1346 | case SP4_SSV: | 1369 | case SP4_SSV: |
1347 | return nfserr_encr_alg_unsupp; | 1370 | return nfserr_serverfault; |
1348 | default: | 1371 | default: |
1349 | BUG(); /* checked by xdr code */ | 1372 | BUG(); /* checked by xdr code */ |
1350 | case SP4_MACH_CRED: | 1373 | case SP4_MACH_CRED: |
@@ -1361,8 +1384,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1361 | nfs4_lock_state(); | 1384 | nfs4_lock_state(); |
1362 | status = nfs_ok; | 1385 | status = nfs_ok; |
1363 | 1386 | ||
1364 | conf = find_confirmed_client_by_str(dname, strhashval, true); | 1387 | conf = find_confirmed_client_by_str(dname, strhashval); |
1365 | if (conf) { | 1388 | if (conf) { |
1389 | if (!clp_used_exchangeid(conf)) { | ||
1390 | status = nfserr_clid_inuse; /* XXX: ? */ | ||
1391 | goto out; | ||
1392 | } | ||
1366 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1393 | if (!same_verf(&verf, &conf->cl_verifier)) { |
1367 | /* 18.35.4 case 8 */ | 1394 | /* 18.35.4 case 8 */ |
1368 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1395 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
@@ -1403,7 +1430,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1403 | goto out; | 1430 | goto out; |
1404 | } | 1431 | } |
1405 | 1432 | ||
1406 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1433 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1407 | if (unconf) { | 1434 | if (unconf) { |
1408 | /* | 1435 | /* |
1409 | * Possible retry or client restart. Per 18.35.4 case 4, | 1436 | * Possible retry or client restart. Per 18.35.4 case 4, |
@@ -1560,6 +1587,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1560 | status = nfs_ok; | 1587 | status = nfs_ok; |
1561 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, | 1588 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, |
1562 | NFS4_MAX_SESSIONID_LEN); | 1589 | NFS4_MAX_SESSIONID_LEN); |
1590 | memcpy(&cr_ses->fore_channel, &new->se_fchannel, | ||
1591 | sizeof(struct nfsd4_channel_attrs)); | ||
1563 | cs_slot->sl_seqid++; | 1592 | cs_slot->sl_seqid++; |
1564 | cr_ses->seqid = cs_slot->sl_seqid; | 1593 | cr_ses->seqid = cs_slot->sl_seqid; |
1565 | 1594 | ||
@@ -1581,6 +1610,45 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | |||
1581 | return argp->opcnt == resp->opcnt; | 1610 | return argp->opcnt == resp->opcnt; |
1582 | } | 1611 | } |
1583 | 1612 | ||
1613 | static __be32 nfsd4_map_bcts_dir(u32 *dir) | ||
1614 | { | ||
1615 | switch (*dir) { | ||
1616 | case NFS4_CDFC4_FORE: | ||
1617 | case NFS4_CDFC4_BACK: | ||
1618 | return nfs_ok; | ||
1619 | case NFS4_CDFC4_FORE_OR_BOTH: | ||
1620 | case NFS4_CDFC4_BACK_OR_BOTH: | ||
1621 | *dir = NFS4_CDFC4_BOTH; | ||
1622 | return nfs_ok; | ||
1623 | }; | ||
1624 | return nfserr_inval; | ||
1625 | } | ||
1626 | |||
1627 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | ||
1628 | struct nfsd4_compound_state *cstate, | ||
1629 | struct nfsd4_bind_conn_to_session *bcts) | ||
1630 | { | ||
1631 | __be32 status; | ||
1632 | |||
1633 | if (!nfsd4_last_compound_op(rqstp)) | ||
1634 | return nfserr_not_only_op; | ||
1635 | spin_lock(&client_lock); | ||
1636 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); | ||
1637 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires | ||
1638 | * client_lock iself: */ | ||
1639 | if (cstate->session) { | ||
1640 | nfsd4_get_session(cstate->session); | ||
1641 | atomic_inc(&cstate->session->se_client->cl_refcount); | ||
1642 | } | ||
1643 | spin_unlock(&client_lock); | ||
1644 | if (!cstate->session) | ||
1645 | return nfserr_badsession; | ||
1646 | |||
1647 | status = nfsd4_map_bcts_dir(&bcts->dir); | ||
1648 | nfsd4_new_conn(rqstp, cstate->session, bcts->dir); | ||
1649 | return nfs_ok; | ||
1650 | } | ||
1651 | |||
1584 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) | 1652 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) |
1585 | { | 1653 | { |
1586 | if (!session) | 1654 | if (!session) |
@@ -1619,8 +1687,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1619 | spin_unlock(&client_lock); | 1687 | spin_unlock(&client_lock); |
1620 | 1688 | ||
1621 | nfs4_lock_state(); | 1689 | nfs4_lock_state(); |
1622 | /* wait for callbacks */ | 1690 | nfsd4_probe_callback_sync(ses->se_client); |
1623 | nfsd4_shutdown_callback(ses->se_client); | ||
1624 | nfs4_unlock_state(); | 1691 | nfs4_unlock_state(); |
1625 | 1692 | ||
1626 | nfsd4_del_conns(ses); | 1693 | nfsd4_del_conns(ses); |
@@ -1733,8 +1800,12 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1733 | out: | 1800 | out: |
1734 | /* Hold a session reference until done processing the compound. */ | 1801 | /* Hold a session reference until done processing the compound. */ |
1735 | if (cstate->session) { | 1802 | if (cstate->session) { |
1803 | struct nfs4_client *clp = session->se_client; | ||
1804 | |||
1736 | nfsd4_get_session(cstate->session); | 1805 | nfsd4_get_session(cstate->session); |
1737 | atomic_inc(&session->se_client->cl_refcount); | 1806 | atomic_inc(&clp->cl_refcount); |
1807 | if (clp->cl_cb_state == NFSD4_CB_DOWN) | ||
1808 | seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN; | ||
1738 | } | 1809 | } |
1739 | kfree(conn); | 1810 | kfree(conn); |
1740 | spin_unlock(&client_lock); | 1811 | spin_unlock(&client_lock); |
@@ -1775,7 +1846,6 @@ __be32 | |||
1775 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1846 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1776 | struct nfsd4_setclientid *setclid) | 1847 | struct nfsd4_setclientid *setclid) |
1777 | { | 1848 | { |
1778 | struct sockaddr *sa = svc_addr(rqstp); | ||
1779 | struct xdr_netobj clname = { | 1849 | struct xdr_netobj clname = { |
1780 | .len = setclid->se_namelen, | 1850 | .len = setclid->se_namelen, |
1781 | .data = setclid->se_name, | 1851 | .data = setclid->se_name, |
@@ -1801,10 +1871,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1801 | strhashval = clientstr_hashval(dname); | 1871 | strhashval = clientstr_hashval(dname); |
1802 | 1872 | ||
1803 | nfs4_lock_state(); | 1873 | nfs4_lock_state(); |
1804 | conf = find_confirmed_client_by_str(dname, strhashval, false); | 1874 | conf = find_confirmed_client_by_str(dname, strhashval); |
1805 | if (conf) { | 1875 | if (conf) { |
1806 | /* RFC 3530 14.2.33 CASE 0: */ | 1876 | /* RFC 3530 14.2.33 CASE 0: */ |
1807 | status = nfserr_clid_inuse; | 1877 | status = nfserr_clid_inuse; |
1878 | if (clp_used_exchangeid(conf)) | ||
1879 | goto out; | ||
1808 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1880 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
1809 | char addr_str[INET6_ADDRSTRLEN]; | 1881 | char addr_str[INET6_ADDRSTRLEN]; |
1810 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, | 1882 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, |
@@ -1819,7 +1891,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1819 | * has a description of SETCLIENTID request processing consisting | 1891 | * has a description of SETCLIENTID request processing consisting |
1820 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | 1892 | * of 5 bullet points, labeled as CASE0 - CASE4 below. |
1821 | */ | 1893 | */ |
1822 | unconf = find_unconfirmed_client_by_str(dname, strhashval, false); | 1894 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1823 | status = nfserr_resource; | 1895 | status = nfserr_resource; |
1824 | if (!conf) { | 1896 | if (!conf) { |
1825 | /* | 1897 | /* |
@@ -1876,7 +1948,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1876 | * for consistent minorversion use throughout: | 1948 | * for consistent minorversion use throughout: |
1877 | */ | 1949 | */ |
1878 | new->cl_minorversion = 0; | 1950 | new->cl_minorversion = 0; |
1879 | gen_callback(new, setclid, rpc_get_scope_id(sa)); | 1951 | gen_callback(new, setclid, rqstp); |
1880 | add_to_unconfirmed(new, strhashval); | 1952 | add_to_unconfirmed(new, strhashval); |
1881 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 1953 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
1882 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 1954 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
@@ -1935,7 +2007,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1935 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 2007 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) |
1936 | status = nfserr_clid_inuse; | 2008 | status = nfserr_clid_inuse; |
1937 | else { | 2009 | else { |
1938 | atomic_set(&conf->cl_cb_set, 0); | ||
1939 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | 2010 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); |
1940 | nfsd4_probe_callback(conf); | 2011 | nfsd4_probe_callback(conf); |
1941 | expire_client(unconf); | 2012 | expire_client(unconf); |
@@ -1964,7 +2035,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1964 | unsigned int hash = | 2035 | unsigned int hash = |
1965 | clientstr_hashval(unconf->cl_recdir); | 2036 | clientstr_hashval(unconf->cl_recdir); |
1966 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | 2037 | conf = find_confirmed_client_by_str(unconf->cl_recdir, |
1967 | hash, false); | 2038 | hash); |
1968 | if (conf) { | 2039 | if (conf) { |
1969 | nfsd4_remove_clid_dir(conf); | 2040 | nfsd4_remove_clid_dir(conf); |
1970 | expire_client(conf); | 2041 | expire_client(conf); |
@@ -2300,41 +2371,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2300 | nfsd4_cb_recall(dp); | 2371 | nfsd4_cb_recall(dp); |
2301 | } | 2372 | } |
2302 | 2373 | ||
2303 | /* | ||
2304 | * The file_lock is being reapd. | ||
2305 | * | ||
2306 | * Called by locks_free_lock() with lock_flocks() held. | ||
2307 | */ | ||
2308 | static | ||
2309 | void nfsd_release_deleg_cb(struct file_lock *fl) | ||
2310 | { | ||
2311 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; | ||
2312 | |||
2313 | dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count)); | ||
2314 | |||
2315 | if (!(fl->fl_flags & FL_LEASE) || !dp) | ||
2316 | return; | ||
2317 | dp->dl_flock = NULL; | ||
2318 | } | ||
2319 | |||
2320 | /* | ||
2321 | * Called from setlease() with lock_flocks() held | ||
2322 | */ | ||
2323 | static | ||
2324 | int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try) | ||
2325 | { | ||
2326 | struct nfs4_delegation *onlistd = | ||
2327 | (struct nfs4_delegation *)onlist->fl_owner; | ||
2328 | struct nfs4_delegation *tryd = | ||
2329 | (struct nfs4_delegation *)try->fl_owner; | ||
2330 | |||
2331 | if (onlist->fl_lmops != try->fl_lmops) | ||
2332 | return 0; | ||
2333 | |||
2334 | return onlistd->dl_client == tryd->dl_client; | ||
2335 | } | ||
2336 | |||
2337 | |||
2338 | static | 2374 | static |
2339 | int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | 2375 | int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) |
2340 | { | 2376 | { |
@@ -2346,8 +2382,6 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
2346 | 2382 | ||
2347 | static const struct lock_manager_operations nfsd_lease_mng_ops = { | 2383 | static const struct lock_manager_operations nfsd_lease_mng_ops = { |
2348 | .fl_break = nfsd_break_deleg_cb, | 2384 | .fl_break = nfsd_break_deleg_cb, |
2349 | .fl_release_private = nfsd_release_deleg_cb, | ||
2350 | .fl_mylease = nfsd_same_client_deleg_cb, | ||
2351 | .fl_change = nfsd_change_deleg_cb, | 2385 | .fl_change = nfsd_change_deleg_cb, |
2352 | }; | 2386 | }; |
2353 | 2387 | ||
@@ -2514,8 +2548,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | |||
2514 | if (!fp->fi_fds[oflag]) { | 2548 | if (!fp->fi_fds[oflag]) { |
2515 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | 2549 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, |
2516 | &fp->fi_fds[oflag]); | 2550 | &fp->fi_fds[oflag]); |
2517 | if (status == nfserr_dropit) | ||
2518 | status = nfserr_jukebox; | ||
2519 | if (status) | 2551 | if (status) |
2520 | return status; | 2552 | return status; |
2521 | } | 2553 | } |
@@ -2596,6 +2628,19 @@ nfs4_set_claim_prev(struct nfsd4_open *open) | |||
2596 | open->op_stateowner->so_client->cl_firststate = 1; | 2628 | open->op_stateowner->so_client->cl_firststate = 1; |
2597 | } | 2629 | } |
2598 | 2630 | ||
2631 | /* Should we give out recallable state?: */ | ||
2632 | static bool nfsd4_cb_channel_good(struct nfs4_client *clp) | ||
2633 | { | ||
2634 | if (clp->cl_cb_state == NFSD4_CB_UP) | ||
2635 | return true; | ||
2636 | /* | ||
2637 | * In the sessions case, since we don't have to establish a | ||
2638 | * separate connection for callbacks, we assume it's OK | ||
2639 | * until we hear otherwise: | ||
2640 | */ | ||
2641 | return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; | ||
2642 | } | ||
2643 | |||
2599 | /* | 2644 | /* |
2600 | * Attempt to hand out a delegation. | 2645 | * Attempt to hand out a delegation. |
2601 | */ | 2646 | */ |
@@ -2604,10 +2649,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2604 | { | 2649 | { |
2605 | struct nfs4_delegation *dp; | 2650 | struct nfs4_delegation *dp; |
2606 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2651 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2607 | int cb_up = atomic_read(&sop->so_client->cl_cb_set); | 2652 | int cb_up; |
2608 | struct file_lock *fl; | 2653 | struct file_lock *fl; |
2609 | int status, flag = 0; | 2654 | int status, flag = 0; |
2610 | 2655 | ||
2656 | cb_up = nfsd4_cb_channel_good(sop->so_client); | ||
2611 | flag = NFS4_OPEN_DELEGATE_NONE; | 2657 | flag = NFS4_OPEN_DELEGATE_NONE; |
2612 | open->op_recall = 0; | 2658 | open->op_recall = 0; |
2613 | switch (open->op_claim_type) { | 2659 | switch (open->op_claim_type) { |
@@ -2655,7 +2701,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2655 | dp->dl_flock = fl; | 2701 | dp->dl_flock = fl; |
2656 | 2702 | ||
2657 | /* vfs_setlease checks to see if delegation should be handed out. | 2703 | /* vfs_setlease checks to see if delegation should be handed out. |
2658 | * the lock_manager callbacks fl_mylease and fl_change are used | 2704 | * the lock_manager callback fl_change is used |
2659 | */ | 2705 | */ |
2660 | if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { | 2706 | if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { |
2661 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 2707 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
@@ -2794,7 +2840,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2794 | renew_client(clp); | 2840 | renew_client(clp); |
2795 | status = nfserr_cb_path_down; | 2841 | status = nfserr_cb_path_down; |
2796 | if (!list_empty(&clp->cl_delegations) | 2842 | if (!list_empty(&clp->cl_delegations) |
2797 | && !atomic_read(&clp->cl_cb_set)) | 2843 | && clp->cl_cb_state != NFSD4_CB_UP) |
2798 | goto out; | 2844 | goto out; |
2799 | status = nfs_ok; | 2845 | status = nfs_ok; |
2800 | out: | 2846 | out: |
@@ -3081,9 +3127,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
3081 | if (status) | 3127 | if (status) |
3082 | goto out; | 3128 | goto out; |
3083 | renew_client(dp->dl_client); | 3129 | renew_client(dp->dl_client); |
3084 | if (filpp) | 3130 | if (filpp) { |
3085 | *filpp = find_readable_file(dp->dl_file); | 3131 | *filpp = find_readable_file(dp->dl_file); |
3086 | BUG_ON(!*filpp); | 3132 | BUG_ON(!*filpp); |
3133 | } | ||
3087 | } else { /* open or lock stateid */ | 3134 | } else { /* open or lock stateid */ |
3088 | stp = find_stateid(stateid, flags); | 3135 | stp = find_stateid(stateid, flags); |
3089 | if (!stp) | 3136 | if (!stp) |
@@ -4107,7 +4154,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) | |||
4107 | unsigned int strhashval = clientstr_hashval(name); | 4154 | unsigned int strhashval = clientstr_hashval(name); |
4108 | struct nfs4_client *clp; | 4155 | struct nfs4_client *clp; |
4109 | 4156 | ||
4110 | clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id); | 4157 | clp = find_confirmed_client_by_str(name, strhashval); |
4111 | return clp ? 1 : 0; | 4158 | return clp ? 1 : 0; |
4112 | } | 4159 | } |
4113 | 4160 | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f35a94a04026..956629b9cdc9 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -44,13 +44,14 @@ | |||
44 | #include <linux/namei.h> | 44 | #include <linux/namei.h> |
45 | #include <linux/statfs.h> | 45 | #include <linux/statfs.h> |
46 | #include <linux/utsname.h> | 46 | #include <linux/utsname.h> |
47 | #include <linux/nfsd_idmap.h> | ||
48 | #include <linux/nfs4_acl.h> | ||
49 | #include <linux/sunrpc/svcauth_gss.h> | 47 | #include <linux/sunrpc/svcauth_gss.h> |
50 | 48 | ||
49 | #include "idmap.h" | ||
50 | #include "acl.h" | ||
51 | #include "xdr4.h" | 51 | #include "xdr4.h" |
52 | #include "vfs.h" | 52 | #include "vfs.h" |
53 | 53 | ||
54 | |||
54 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 55 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
55 | 56 | ||
56 | /* | 57 | /* |
@@ -288,17 +289,17 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
288 | len += XDR_QUADLEN(dummy32) << 2; | 289 | len += XDR_QUADLEN(dummy32) << 2; |
289 | READMEM(buf, dummy32); | 290 | READMEM(buf, dummy32); |
290 | ace->whotype = nfs4_acl_get_whotype(buf, dummy32); | 291 | ace->whotype = nfs4_acl_get_whotype(buf, dummy32); |
291 | host_err = 0; | 292 | status = nfs_ok; |
292 | if (ace->whotype != NFS4_ACL_WHO_NAMED) | 293 | if (ace->whotype != NFS4_ACL_WHO_NAMED) |
293 | ace->who = 0; | 294 | ace->who = 0; |
294 | else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) | 295 | else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) |
295 | host_err = nfsd_map_name_to_gid(argp->rqstp, | 296 | status = nfsd_map_name_to_gid(argp->rqstp, |
296 | buf, dummy32, &ace->who); | 297 | buf, dummy32, &ace->who); |
297 | else | 298 | else |
298 | host_err = nfsd_map_name_to_uid(argp->rqstp, | 299 | status = nfsd_map_name_to_uid(argp->rqstp, |
299 | buf, dummy32, &ace->who); | 300 | buf, dummy32, &ace->who); |
300 | if (host_err) | 301 | if (status) |
301 | goto out_nfserr; | 302 | return status; |
302 | } | 303 | } |
303 | } else | 304 | } else |
304 | *acl = NULL; | 305 | *acl = NULL; |
@@ -420,6 +421,21 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access | |||
420 | DECODE_TAIL; | 421 | DECODE_TAIL; |
421 | } | 422 | } |
422 | 423 | ||
424 | static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) | ||
425 | { | ||
426 | DECODE_HEAD; | ||
427 | u32 dummy; | ||
428 | |||
429 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 8); | ||
430 | COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); | ||
431 | READ32(bcts->dir); | ||
432 | /* XXX: Perhaps Tom Tucker could help us figure out how we | ||
433 | * should be using ctsa_use_conn_in_rdma_mode: */ | ||
434 | READ32(dummy); | ||
435 | |||
436 | DECODE_TAIL; | ||
437 | } | ||
438 | |||
423 | static __be32 | 439 | static __be32 |
424 | nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) | 440 | nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) |
425 | { | 441 | { |
@@ -847,6 +863,17 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, | |||
847 | } | 863 | } |
848 | 864 | ||
849 | static __be32 | 865 | static __be32 |
866 | nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, | ||
867 | struct nfsd4_secinfo_no_name *sin) | ||
868 | { | ||
869 | DECODE_HEAD; | ||
870 | |||
871 | READ_BUF(4); | ||
872 | READ32(sin->sin_style); | ||
873 | DECODE_TAIL; | ||
874 | } | ||
875 | |||
876 | static __be32 | ||
850 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) | 877 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) |
851 | { | 878 | { |
852 | __be32 status; | 879 | __be32 status; |
@@ -1005,7 +1032,7 @@ static __be32 | |||
1005 | nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, | 1032 | nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, |
1006 | struct nfsd4_exchange_id *exid) | 1033 | struct nfsd4_exchange_id *exid) |
1007 | { | 1034 | { |
1008 | int dummy; | 1035 | int dummy, tmp; |
1009 | DECODE_HEAD; | 1036 | DECODE_HEAD; |
1010 | 1037 | ||
1011 | READ_BUF(NFS4_VERIFIER_SIZE); | 1038 | READ_BUF(NFS4_VERIFIER_SIZE); |
@@ -1053,15 +1080,23 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, | |||
1053 | 1080 | ||
1054 | /* ssp_hash_algs<> */ | 1081 | /* ssp_hash_algs<> */ |
1055 | READ_BUF(4); | 1082 | READ_BUF(4); |
1056 | READ32(dummy); | 1083 | READ32(tmp); |
1057 | READ_BUF(dummy); | 1084 | while (tmp--) { |
1058 | p += XDR_QUADLEN(dummy); | 1085 | READ_BUF(4); |
1086 | READ32(dummy); | ||
1087 | READ_BUF(dummy); | ||
1088 | p += XDR_QUADLEN(dummy); | ||
1089 | } | ||
1059 | 1090 | ||
1060 | /* ssp_encr_algs<> */ | 1091 | /* ssp_encr_algs<> */ |
1061 | READ_BUF(4); | 1092 | READ_BUF(4); |
1062 | READ32(dummy); | 1093 | READ32(tmp); |
1063 | READ_BUF(dummy); | 1094 | while (tmp--) { |
1064 | p += XDR_QUADLEN(dummy); | 1095 | READ_BUF(4); |
1096 | READ32(dummy); | ||
1097 | READ_BUF(dummy); | ||
1098 | p += XDR_QUADLEN(dummy); | ||
1099 | } | ||
1065 | 1100 | ||
1066 | /* ssp_window and ssp_num_gss_handles */ | 1101 | /* ssp_window and ssp_num_gss_handles */ |
1067 | READ_BUF(8); | 1102 | READ_BUF(8); |
@@ -1339,7 +1374,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
1339 | 1374 | ||
1340 | /* new operations for NFSv4.1 */ | 1375 | /* new operations for NFSv4.1 */ |
1341 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, | 1376 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, |
1342 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp, | 1377 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, |
1343 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, | 1378 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
1344 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, | 1379 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
1345 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, | 1380 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
@@ -1350,7 +1385,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
1350 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, | 1385 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, |
1351 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, | 1386 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, |
1352 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, | 1387 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, |
1353 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp, | 1388 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, |
1354 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, | 1389 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, |
1355 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, | 1390 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
1356 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, | 1391 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
@@ -2309,8 +2344,6 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, | |||
2309 | case nfserr_resource: | 2344 | case nfserr_resource: |
2310 | nfserr = nfserr_toosmall; | 2345 | nfserr = nfserr_toosmall; |
2311 | goto fail; | 2346 | goto fail; |
2312 | case nfserr_dropit: | ||
2313 | goto fail; | ||
2314 | case nfserr_noent: | 2347 | case nfserr_noent: |
2315 | goto skip_entry; | 2348 | goto skip_entry; |
2316 | default: | 2349 | default: |
@@ -2365,6 +2398,21 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2365 | return nfserr; | 2398 | return nfserr; |
2366 | } | 2399 | } |
2367 | 2400 | ||
2401 | static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) | ||
2402 | { | ||
2403 | __be32 *p; | ||
2404 | |||
2405 | if (!nfserr) { | ||
2406 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8); | ||
2407 | WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); | ||
2408 | WRITE32(bcts->dir); | ||
2409 | /* XXX: ? */ | ||
2410 | WRITE32(0); | ||
2411 | ADJUST_ARGS(); | ||
2412 | } | ||
2413 | return nfserr; | ||
2414 | } | ||
2415 | |||
2368 | static __be32 | 2416 | static __be32 |
2369 | nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) | 2417 | nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) |
2370 | { | 2418 | { |
@@ -2826,11 +2874,10 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2826 | } | 2874 | } |
2827 | 2875 | ||
2828 | static __be32 | 2876 | static __be32 |
2829 | nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | 2877 | nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, |
2830 | struct nfsd4_secinfo *secinfo) | 2878 | __be32 nfserr,struct svc_export *exp) |
2831 | { | 2879 | { |
2832 | int i = 0; | 2880 | int i = 0; |
2833 | struct svc_export *exp = secinfo->si_exp; | ||
2834 | u32 nflavs; | 2881 | u32 nflavs; |
2835 | struct exp_flavor_info *flavs; | 2882 | struct exp_flavor_info *flavs; |
2836 | struct exp_flavor_info def_flavs[2]; | 2883 | struct exp_flavor_info def_flavs[2]; |
@@ -2892,6 +2939,20 @@ out: | |||
2892 | return nfserr; | 2939 | return nfserr; |
2893 | } | 2940 | } |
2894 | 2941 | ||
2942 | static __be32 | ||
2943 | nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
2944 | struct nfsd4_secinfo *secinfo) | ||
2945 | { | ||
2946 | return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp); | ||
2947 | } | ||
2948 | |||
2949 | static __be32 | ||
2950 | nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
2951 | struct nfsd4_secinfo_no_name *secinfo) | ||
2952 | { | ||
2953 | return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp); | ||
2954 | } | ||
2955 | |||
2895 | /* | 2956 | /* |
2896 | * The SETATTR encode routine is special -- it always encodes a bitmap, | 2957 | * The SETATTR encode routine is special -- it always encodes a bitmap, |
2897 | * regardless of the error status. | 2958 | * regardless of the error status. |
@@ -3076,13 +3137,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | |||
3076 | WRITE32(seq->seqid); | 3137 | WRITE32(seq->seqid); |
3077 | WRITE32(seq->slotid); | 3138 | WRITE32(seq->slotid); |
3078 | WRITE32(seq->maxslots); | 3139 | WRITE32(seq->maxslots); |
3079 | /* | 3140 | /* For now: target_maxslots = maxslots */ |
3080 | * FIXME: for now: | ||
3081 | * target_maxslots = maxslots | ||
3082 | * status_flags = 0 | ||
3083 | */ | ||
3084 | WRITE32(seq->maxslots); | 3141 | WRITE32(seq->maxslots); |
3085 | WRITE32(0); | 3142 | WRITE32(seq->status_flags); |
3086 | 3143 | ||
3087 | ADJUST_ARGS(); | 3144 | ADJUST_ARGS(); |
3088 | resp->cstate.datap = p; /* DRC cache data pointer */ | 3145 | resp->cstate.datap = p; /* DRC cache data pointer */ |
@@ -3143,7 +3200,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3143 | 3200 | ||
3144 | /* NFSv4.1 operations */ | 3201 | /* NFSv4.1 operations */ |
3145 | [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, | 3202 | [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, |
3146 | [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop, | 3203 | [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session, |
3147 | [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, | 3204 | [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, |
3148 | [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, | 3205 | [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, |
3149 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, | 3206 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, |
@@ -3154,7 +3211,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3154 | [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, | 3211 | [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, |
3155 | [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, | 3212 | [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, |
3156 | [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, | 3213 | [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, |
3157 | [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_noop, | 3214 | [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, |
3158 | [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, | 3215 | [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, |
3159 | [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, | 3216 | [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, |
3160 | [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop, | 3217 | [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop, |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 4514ebbee4d6..33b3e2b06779 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -8,12 +8,12 @@ | |||
8 | #include <linux/namei.h> | 8 | #include <linux/namei.h> |
9 | #include <linux/ctype.h> | 9 | #include <linux/ctype.h> |
10 | 10 | ||
11 | #include <linux/nfsd_idmap.h> | ||
12 | #include <linux/sunrpc/svcsock.h> | 11 | #include <linux/sunrpc/svcsock.h> |
13 | #include <linux/nfsd/syscall.h> | 12 | #include <linux/nfsd/syscall.h> |
14 | #include <linux/lockd/lockd.h> | 13 | #include <linux/lockd/lockd.h> |
15 | #include <linux/sunrpc/clnt.h> | 14 | #include <linux/sunrpc/clnt.h> |
16 | 15 | ||
16 | #include "idmap.h" | ||
17 | #include "nfsd.h" | 17 | #include "nfsd.h" |
18 | #include "cache.h" | 18 | #include "cache.h" |
19 | 19 | ||
@@ -127,6 +127,7 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu | |||
127 | 127 | ||
128 | static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) | 128 | static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) |
129 | { | 129 | { |
130 | #ifdef CONFIG_NFSD_DEPRECATED | ||
130 | static int warned; | 131 | static int warned; |
131 | if (file->f_dentry->d_name.name[0] == '.' && !warned) { | 132 | if (file->f_dentry->d_name.name[0] == '.' && !warned) { |
132 | printk(KERN_INFO | 133 | printk(KERN_INFO |
@@ -135,6 +136,7 @@ static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size | |||
135 | current->comm, file->f_dentry->d_name.name); | 136 | current->comm, file->f_dentry->d_name.name); |
136 | warned = 1; | 137 | warned = 1; |
137 | } | 138 | } |
139 | #endif | ||
138 | if (! file->private_data) { | 140 | if (! file->private_data) { |
139 | /* An attempt to read a transaction file without writing | 141 | /* An attempt to read a transaction file without writing |
140 | * causes a 0-byte write so that the file can return | 142 | * causes a 0-byte write so that the file can return |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 6b641cf2c19a..7ecfa2420307 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -158,6 +158,7 @@ void nfsd_lockd_shutdown(void); | |||
158 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) | 158 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) |
159 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) | 159 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) |
160 | #define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE) | 160 | #define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE) |
161 | #define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER) | ||
161 | #define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD) | 162 | #define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD) |
162 | #define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL) | 163 | #define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL) |
163 | #define nfserr_grace cpu_to_be32(NFSERR_GRACE) | 164 | #define nfserr_grace cpu_to_be32(NFSERR_GRACE) |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 08e17264784b..e15dc45fc5ec 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -735,9 +735,9 @@ nfserrno (int errno) | |||
735 | { nfserr_stale, -ESTALE }, | 735 | { nfserr_stale, -ESTALE }, |
736 | { nfserr_jukebox, -ETIMEDOUT }, | 736 | { nfserr_jukebox, -ETIMEDOUT }, |
737 | { nfserr_jukebox, -ERESTARTSYS }, | 737 | { nfserr_jukebox, -ERESTARTSYS }, |
738 | { nfserr_dropit, -EAGAIN }, | 738 | { nfserr_jukebox, -EAGAIN }, |
739 | { nfserr_dropit, -ENOMEM }, | 739 | { nfserr_jukebox, -EWOULDBLOCK }, |
740 | { nfserr_badname, -ESRCH }, | 740 | { nfserr_jukebox, -ENOMEM }, |
741 | { nfserr_io, -ETXTBSY }, | 741 | { nfserr_io, -ETXTBSY }, |
742 | { nfserr_notsupp, -EOPNOTSUPP }, | 742 | { nfserr_notsupp, -EOPNOTSUPP }, |
743 | { nfserr_toosmall, -ETOOSMALL }, | 743 | { nfserr_toosmall, -ETOOSMALL }, |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 2bae1d86f5f2..18743c4d8bca 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -608,7 +608,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
608 | /* Now call the procedure handler, and encode NFS status. */ | 608 | /* Now call the procedure handler, and encode NFS status. */ |
609 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | 609 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); |
610 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); | 610 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); |
611 | if (nfserr == nfserr_dropit) { | 611 | if (nfserr == nfserr_dropit || rqstp->rq_dropme) { |
612 | dprintk("nfsd: Dropping request; may be revisited later\n"); | 612 | dprintk("nfsd: Dropping request; may be revisited later\n"); |
613 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); | 613 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
614 | return 0; | 614 | return 0; |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 39adc27b0685..3074656ba7bf 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -68,10 +68,12 @@ typedef struct { | |||
68 | struct nfsd4_callback { | 68 | struct nfsd4_callback { |
69 | void *cb_op; | 69 | void *cb_op; |
70 | struct nfs4_client *cb_clp; | 70 | struct nfs4_client *cb_clp; |
71 | struct list_head cb_per_client; | ||
71 | u32 cb_minorversion; | 72 | u32 cb_minorversion; |
72 | struct rpc_message cb_msg; | 73 | struct rpc_message cb_msg; |
73 | const struct rpc_call_ops *cb_ops; | 74 | const struct rpc_call_ops *cb_ops; |
74 | struct work_struct cb_work; | 75 | struct work_struct cb_work; |
76 | bool cb_done; | ||
75 | }; | 77 | }; |
76 | 78 | ||
77 | struct nfs4_delegation { | 79 | struct nfs4_delegation { |
@@ -81,6 +83,7 @@ struct nfs4_delegation { | |||
81 | atomic_t dl_count; /* ref count */ | 83 | atomic_t dl_count; /* ref count */ |
82 | struct nfs4_client *dl_client; | 84 | struct nfs4_client *dl_client; |
83 | struct nfs4_file *dl_file; | 85 | struct nfs4_file *dl_file; |
86 | struct file *dl_vfs_file; | ||
84 | struct file_lock *dl_flock; | 87 | struct file_lock *dl_flock; |
85 | u32 dl_type; | 88 | u32 dl_type; |
86 | time_t dl_time; | 89 | time_t dl_time; |
@@ -95,6 +98,7 @@ struct nfs4_delegation { | |||
95 | struct nfs4_cb_conn { | 98 | struct nfs4_cb_conn { |
96 | /* SETCLIENTID info */ | 99 | /* SETCLIENTID info */ |
97 | struct sockaddr_storage cb_addr; | 100 | struct sockaddr_storage cb_addr; |
101 | struct sockaddr_storage cb_saddr; | ||
98 | size_t cb_addrlen; | 102 | size_t cb_addrlen; |
99 | u32 cb_prog; /* used only in 4.0 case; | 103 | u32 cb_prog; /* used only in 4.0 case; |
100 | per-session otherwise */ | 104 | per-session otherwise */ |
@@ -146,6 +150,11 @@ struct nfsd4_create_session { | |||
146 | u32 gid; | 150 | u32 gid; |
147 | }; | 151 | }; |
148 | 152 | ||
153 | struct nfsd4_bind_conn_to_session { | ||
154 | struct nfs4_sessionid sessionid; | ||
155 | u32 dir; | ||
156 | }; | ||
157 | |||
149 | /* The single slot clientid cache structure */ | 158 | /* The single slot clientid cache structure */ |
150 | struct nfsd4_clid_slot { | 159 | struct nfsd4_clid_slot { |
151 | u32 sl_seqid; | 160 | u32 sl_seqid; |
@@ -235,9 +244,13 @@ struct nfs4_client { | |||
235 | unsigned long cl_cb_flags; | 244 | unsigned long cl_cb_flags; |
236 | struct rpc_clnt *cl_cb_client; | 245 | struct rpc_clnt *cl_cb_client; |
237 | u32 cl_cb_ident; | 246 | u32 cl_cb_ident; |
238 | atomic_t cl_cb_set; | 247 | #define NFSD4_CB_UP 0 |
248 | #define NFSD4_CB_UNKNOWN 1 | ||
249 | #define NFSD4_CB_DOWN 2 | ||
250 | int cl_cb_state; | ||
239 | struct nfsd4_callback cl_cb_null; | 251 | struct nfsd4_callback cl_cb_null; |
240 | struct nfsd4_session *cl_cb_session; | 252 | struct nfsd4_session *cl_cb_session; |
253 | struct list_head cl_callbacks; /* list of in-progress callbacks */ | ||
241 | 254 | ||
242 | /* for all client information that callback code might need: */ | 255 | /* for all client information that callback code might need: */ |
243 | spinlock_t cl_lock; | 256 | spinlock_t cl_lock; |
@@ -454,6 +467,7 @@ extern __be32 nfs4_check_open_reclaim(clientid_t *clid); | |||
454 | extern void nfs4_free_stateowner(struct kref *kref); | 467 | extern void nfs4_free_stateowner(struct kref *kref); |
455 | extern int set_callback_cred(void); | 468 | extern int set_callback_cred(void); |
456 | extern void nfsd4_probe_callback(struct nfs4_client *clp); | 469 | extern void nfsd4_probe_callback(struct nfs4_client *clp); |
470 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); | ||
457 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); | 471 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); |
458 | extern void nfsd4_do_callback_rpc(struct work_struct *); | 472 | extern void nfsd4_do_callback_rpc(struct work_struct *); |
459 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); | 473 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 230b79fbf005..a3c7f701395a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define MSNFS /* HACK HACK */ | ||
2 | /* | 1 | /* |
3 | * File operations used by nfsd. Some of these have been ripped from | 2 | * File operations used by nfsd. Some of these have been ripped from |
4 | * other parts of the kernel because they weren't exported, others | 3 | * other parts of the kernel because they weren't exported, others |
@@ -35,8 +34,8 @@ | |||
35 | #endif /* CONFIG_NFSD_V3 */ | 34 | #endif /* CONFIG_NFSD_V3 */ |
36 | 35 | ||
37 | #ifdef CONFIG_NFSD_V4 | 36 | #ifdef CONFIG_NFSD_V4 |
38 | #include <linux/nfs4_acl.h> | 37 | #include "acl.h" |
39 | #include <linux/nfsd_idmap.h> | 38 | #include "idmap.h" |
40 | #endif /* CONFIG_NFSD_V4 */ | 39 | #endif /* CONFIG_NFSD_V4 */ |
41 | 40 | ||
42 | #include "nfsd.h" | 41 | #include "nfsd.h" |
@@ -273,6 +272,13 @@ out: | |||
273 | return err; | 272 | return err; |
274 | } | 273 | } |
275 | 274 | ||
275 | static int nfsd_break_lease(struct inode *inode) | ||
276 | { | ||
277 | if (!S_ISREG(inode->i_mode)) | ||
278 | return 0; | ||
279 | return break_lease(inode, O_WRONLY | O_NONBLOCK); | ||
280 | } | ||
281 | |||
276 | /* | 282 | /* |
277 | * Commit metadata changes to stable storage. | 283 | * Commit metadata changes to stable storage. |
278 | */ | 284 | */ |
@@ -375,16 +381,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
375 | goto out; | 381 | goto out; |
376 | } | 382 | } |
377 | 383 | ||
378 | /* | ||
379 | * If we are changing the size of the file, then | ||
380 | * we need to break all leases. | ||
381 | */ | ||
382 | host_err = break_lease(inode, O_WRONLY | O_NONBLOCK); | ||
383 | if (host_err == -EWOULDBLOCK) | ||
384 | host_err = -ETIMEDOUT; | ||
385 | if (host_err) /* ENOMEM or EWOULDBLOCK */ | ||
386 | goto out_nfserr; | ||
387 | |||
388 | host_err = get_write_access(inode); | 384 | host_err = get_write_access(inode); |
389 | if (host_err) | 385 | if (host_err) |
390 | goto out_nfserr; | 386 | goto out_nfserr; |
@@ -425,7 +421,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
425 | 421 | ||
426 | err = nfserr_notsync; | 422 | err = nfserr_notsync; |
427 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { | 423 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { |
424 | host_err = nfsd_break_lease(inode); | ||
425 | if (host_err) | ||
426 | goto out_nfserr; | ||
428 | fh_lock(fhp); | 427 | fh_lock(fhp); |
428 | |||
429 | host_err = notify_change(dentry, iap); | 429 | host_err = notify_change(dentry, iap); |
430 | err = nfserrno(host_err); | 430 | err = nfserrno(host_err); |
431 | fh_unlock(fhp); | 431 | fh_unlock(fhp); |
@@ -752,8 +752,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
752 | */ | 752 | */ |
753 | if (!(access & NFSD_MAY_NOT_BREAK_LEASE)) | 753 | if (!(access & NFSD_MAY_NOT_BREAK_LEASE)) |
754 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); | 754 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); |
755 | if (host_err == -EWOULDBLOCK) | ||
756 | host_err = -ETIMEDOUT; | ||
757 | if (host_err) /* NOMEM or WOULDBLOCK */ | 755 | if (host_err) /* NOMEM or WOULDBLOCK */ |
758 | goto out_nfserr; | 756 | goto out_nfserr; |
759 | 757 | ||
@@ -874,15 +872,6 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, | |||
874 | return __splice_from_pipe(pipe, sd, nfsd_splice_actor); | 872 | return __splice_from_pipe(pipe, sd, nfsd_splice_actor); |
875 | } | 873 | } |
876 | 874 | ||
877 | static inline int svc_msnfs(struct svc_fh *ffhp) | ||
878 | { | ||
879 | #ifdef MSNFS | ||
880 | return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS); | ||
881 | #else | ||
882 | return 0; | ||
883 | #endif | ||
884 | } | ||
885 | |||
886 | static __be32 | 875 | static __be32 |
887 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 876 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
888 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | 877 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
@@ -895,9 +884,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
895 | err = nfserr_perm; | 884 | err = nfserr_perm; |
896 | inode = file->f_path.dentry->d_inode; | 885 | inode = file->f_path.dentry->d_inode; |
897 | 886 | ||
898 | if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) | ||
899 | goto out; | ||
900 | |||
901 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { | 887 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { |
902 | struct splice_desc sd = { | 888 | struct splice_desc sd = { |
903 | .len = 0, | 889 | .len = 0, |
@@ -922,7 +908,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
922 | fsnotify_access(file); | 908 | fsnotify_access(file); |
923 | } else | 909 | } else |
924 | err = nfserrno(host_err); | 910 | err = nfserrno(host_err); |
925 | out: | ||
926 | return err; | 911 | return err; |
927 | } | 912 | } |
928 | 913 | ||
@@ -987,14 +972,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
987 | int stable = *stablep; | 972 | int stable = *stablep; |
988 | int use_wgather; | 973 | int use_wgather; |
989 | 974 | ||
990 | #ifdef MSNFS | ||
991 | err = nfserr_perm; | ||
992 | |||
993 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | ||
994 | (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt))) | ||
995 | goto out; | ||
996 | #endif | ||
997 | |||
998 | dentry = file->f_path.dentry; | 975 | dentry = file->f_path.dentry; |
999 | inode = dentry->d_inode; | 976 | inode = dentry->d_inode; |
1000 | exp = fhp->fh_export; | 977 | exp = fhp->fh_export; |
@@ -1045,7 +1022,6 @@ out_nfserr: | |||
1045 | err = 0; | 1022 | err = 0; |
1046 | else | 1023 | else |
1047 | err = nfserrno(host_err); | 1024 | err = nfserrno(host_err); |
1048 | out: | ||
1049 | return err; | 1025 | return err; |
1050 | } | 1026 | } |
1051 | 1027 | ||
@@ -1665,6 +1641,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1665 | err = nfserrno(host_err); | 1641 | err = nfserrno(host_err); |
1666 | goto out_dput; | 1642 | goto out_dput; |
1667 | } | 1643 | } |
1644 | err = nfserr_noent; | ||
1645 | if (!dold->d_inode) | ||
1646 | goto out_drop_write; | ||
1647 | host_err = nfsd_break_lease(dold->d_inode); | ||
1648 | if (host_err) | ||
1649 | goto out_drop_write; | ||
1668 | host_err = vfs_link(dold, dirp, dnew); | 1650 | host_err = vfs_link(dold, dirp, dnew); |
1669 | if (!host_err) { | 1651 | if (!host_err) { |
1670 | err = nfserrno(commit_metadata(ffhp)); | 1652 | err = nfserrno(commit_metadata(ffhp)); |
@@ -1676,6 +1658,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1676 | else | 1658 | else |
1677 | err = nfserrno(host_err); | 1659 | err = nfserrno(host_err); |
1678 | } | 1660 | } |
1661 | out_drop_write: | ||
1679 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); | 1662 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); |
1680 | out_dput: | 1663 | out_dput: |
1681 | dput(dnew); | 1664 | dput(dnew); |
@@ -1750,12 +1733,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1750 | if (ndentry == trap) | 1733 | if (ndentry == trap) |
1751 | goto out_dput_new; | 1734 | goto out_dput_new; |
1752 | 1735 | ||
1753 | if (svc_msnfs(ffhp) && | ||
1754 | ((odentry->d_count > 1) || (ndentry->d_count > 1))) { | ||
1755 | host_err = -EPERM; | ||
1756 | goto out_dput_new; | ||
1757 | } | ||
1758 | |||
1759 | host_err = -EXDEV; | 1736 | host_err = -EXDEV; |
1760 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) | 1737 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) |
1761 | goto out_dput_new; | 1738 | goto out_dput_new; |
@@ -1763,15 +1740,17 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1763 | if (host_err) | 1740 | if (host_err) |
1764 | goto out_dput_new; | 1741 | goto out_dput_new; |
1765 | 1742 | ||
1743 | host_err = nfsd_break_lease(odentry->d_inode); | ||
1744 | if (host_err) | ||
1745 | goto out_drop_write; | ||
1766 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1746 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1767 | if (!host_err) { | 1747 | if (!host_err) { |
1768 | host_err = commit_metadata(tfhp); | 1748 | host_err = commit_metadata(tfhp); |
1769 | if (!host_err) | 1749 | if (!host_err) |
1770 | host_err = commit_metadata(ffhp); | 1750 | host_err = commit_metadata(ffhp); |
1771 | } | 1751 | } |
1772 | 1752 | out_drop_write: | |
1773 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 1753 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); |
1774 | |||
1775 | out_dput_new: | 1754 | out_dput_new: |
1776 | dput(ndentry); | 1755 | dput(ndentry); |
1777 | out_dput_old: | 1756 | out_dput_old: |
@@ -1834,18 +1813,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1834 | if (host_err) | 1813 | if (host_err) |
1835 | goto out_nfserr; | 1814 | goto out_nfserr; |
1836 | 1815 | ||
1837 | if (type != S_IFDIR) { /* It's UNLINK */ | 1816 | host_err = nfsd_break_lease(rdentry->d_inode); |
1838 | #ifdef MSNFS | 1817 | if (host_err) |
1839 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1818 | goto out_put; |
1840 | (rdentry->d_count > 1)) { | 1819 | if (type != S_IFDIR) |
1841 | host_err = -EPERM; | ||
1842 | } else | ||
1843 | #endif | ||
1844 | host_err = vfs_unlink(dirp, rdentry); | 1820 | host_err = vfs_unlink(dirp, rdentry); |
1845 | } else { /* It's RMDIR */ | 1821 | else |
1846 | host_err = vfs_rmdir(dirp, rdentry); | 1822 | host_err = vfs_rmdir(dirp, rdentry); |
1847 | } | 1823 | out_put: |
1848 | |||
1849 | dput(rdentry); | 1824 | dput(rdentry); |
1850 | 1825 | ||
1851 | if (!host_err) | 1826 | if (!host_err) |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 60fce3dc5cb5..366401e1a536 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -311,6 +311,11 @@ struct nfsd4_secinfo { | |||
311 | struct svc_export *si_exp; /* response */ | 311 | struct svc_export *si_exp; /* response */ |
312 | }; | 312 | }; |
313 | 313 | ||
314 | struct nfsd4_secinfo_no_name { | ||
315 | u32 sin_style; /* request */ | ||
316 | struct svc_export *sin_exp; /* response */ | ||
317 | }; | ||
318 | |||
314 | struct nfsd4_setattr { | 319 | struct nfsd4_setattr { |
315 | stateid_t sa_stateid; /* request */ | 320 | stateid_t sa_stateid; /* request */ |
316 | u32 sa_bmval[3]; /* request */ | 321 | u32 sa_bmval[3]; /* request */ |
@@ -373,8 +378,8 @@ struct nfsd4_sequence { | |||
373 | u32 cachethis; /* request */ | 378 | u32 cachethis; /* request */ |
374 | #if 0 | 379 | #if 0 |
375 | u32 target_maxslots; /* response */ | 380 | u32 target_maxslots; /* response */ |
376 | u32 status_flags; /* response */ | ||
377 | #endif /* not yet */ | 381 | #endif /* not yet */ |
382 | u32 status_flags; /* response */ | ||
378 | }; | 383 | }; |
379 | 384 | ||
380 | struct nfsd4_destroy_session { | 385 | struct nfsd4_destroy_session { |
@@ -422,6 +427,7 @@ struct nfsd4_op { | |||
422 | 427 | ||
423 | /* NFSv4.1 */ | 428 | /* NFSv4.1 */ |
424 | struct nfsd4_exchange_id exchange_id; | 429 | struct nfsd4_exchange_id exchange_id; |
430 | struct nfsd4_bind_conn_to_session bind_conn_to_session; | ||
425 | struct nfsd4_create_session create_session; | 431 | struct nfsd4_create_session create_session; |
426 | struct nfsd4_destroy_session destroy_session; | 432 | struct nfsd4_destroy_session destroy_session; |
427 | struct nfsd4_sequence sequence; | 433 | struct nfsd4_sequence sequence; |
@@ -518,6 +524,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
518 | struct nfsd4_sequence *seq); | 524 | struct nfsd4_sequence *seq); |
519 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, | 525 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, |
520 | struct nfsd4_compound_state *, struct nfsd4_exchange_id *); | 526 | struct nfsd4_compound_state *, struct nfsd4_exchange_id *); |
527 | extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *); | ||
521 | extern __be32 nfsd4_create_session(struct svc_rqst *, | 528 | extern __be32 nfsd4_create_session(struct svc_rqst *, |
522 | struct nfsd4_compound_state *, | 529 | struct nfsd4_compound_state *, |
523 | struct nfsd4_create_session *); | 530 | struct nfsd4_create_session *); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 3984f2358d1f..ed6ee473cc8a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1066,7 +1066,6 @@ struct lock_manager_operations { | |||
1066 | int (*fl_grant)(struct file_lock *, struct file_lock *, int); | 1066 | int (*fl_grant)(struct file_lock *, struct file_lock *, int); |
1067 | void (*fl_release_private)(struct file_lock *); | 1067 | void (*fl_release_private)(struct file_lock *); |
1068 | void (*fl_break)(struct file_lock *); | 1068 | void (*fl_break)(struct file_lock *); |
1069 | int (*fl_mylease)(struct file_lock *, struct file_lock *); | ||
1070 | int (*fl_change)(struct file_lock **, int); | 1069 | int (*fl_change)(struct file_lock **, int); |
1071 | }; | 1070 | }; |
1072 | 1071 | ||
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 9b46300b4305..134716e5e350 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h | |||
@@ -65,6 +65,9 @@ | |||
65 | 65 | ||
66 | #define NFS4_CDFC4_FORE 0x1 | 66 | #define NFS4_CDFC4_FORE 0x1 |
67 | #define NFS4_CDFC4_BACK 0x2 | 67 | #define NFS4_CDFC4_BACK 0x2 |
68 | #define NFS4_CDFC4_BOTH 0x3 | ||
69 | #define NFS4_CDFC4_FORE_OR_BOTH 0x3 | ||
70 | #define NFS4_CDFC4_BACK_OR_BOTH 0x7 | ||
68 | 71 | ||
69 | #define NFS4_SET_TO_SERVER_TIME 0 | 72 | #define NFS4_SET_TO_SERVER_TIME 0 |
70 | #define NFS4_SET_TO_CLIENT_TIME 1 | 73 | #define NFS4_SET_TO_CLIENT_TIME 1 |
@@ -140,6 +143,9 @@ | |||
140 | #define SEQ4_STATUS_CB_PATH_DOWN_SESSION 0x00000200 | 143 | #define SEQ4_STATUS_CB_PATH_DOWN_SESSION 0x00000200 |
141 | #define SEQ4_STATUS_BACKCHANNEL_FAULT 0x00000400 | 144 | #define SEQ4_STATUS_BACKCHANNEL_FAULT 0x00000400 |
142 | 145 | ||
146 | #define NFS4_SECINFO_STYLE4_CURRENT_FH 0 | ||
147 | #define NFS4_SECINFO_STYLE4_PARENT 1 | ||
148 | |||
143 | #define NFS4_MAX_UINT64 (~(u64)0) | 149 | #define NFS4_MAX_UINT64 (~(u64)0) |
144 | 150 | ||
145 | /* An NFS4 sessions server must support at least NFS4_MAX_OPS operations. | 151 | /* An NFS4 sessions server must support at least NFS4_MAX_OPS operations. |
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 8ae78a61eea4..bd316159278c 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h | |||
@@ -35,7 +35,7 @@ | |||
35 | #define NFSEXP_NOHIDE 0x0200 | 35 | #define NFSEXP_NOHIDE 0x0200 |
36 | #define NFSEXP_NOSUBTREECHECK 0x0400 | 36 | #define NFSEXP_NOSUBTREECHECK 0x0400 |
37 | #define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ | 37 | #define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ |
38 | #define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect */ | 38 | #define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */ |
39 | #define NFSEXP_FSID 0x2000 | 39 | #define NFSEXP_FSID 0x2000 |
40 | #define NFSEXP_CROSSMOUNT 0x4000 | 40 | #define NFSEXP_CROSSMOUNT 0x4000 |
41 | #define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ | 41 | #define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ |
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 78aa104250b7..7898ea13de70 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h | |||
@@ -256,10 +256,13 @@ static inline time_t get_expiry(char **bpp) | |||
256 | return rv - boot.tv_sec; | 256 | return rv - boot.tv_sec; |
257 | } | 257 | } |
258 | 258 | ||
259 | #ifdef CONFIG_NFSD_DEPRECATED | ||
259 | static inline void sunrpc_invalidate(struct cache_head *h, | 260 | static inline void sunrpc_invalidate(struct cache_head *h, |
260 | struct cache_detail *detail) | 261 | struct cache_detail *detail) |
261 | { | 262 | { |
262 | h->expiry_time = seconds_since_boot() - 1; | 263 | h->expiry_time = seconds_since_boot() - 1; |
263 | detail->nextcheck = seconds_since_boot(); | 264 | detail->nextcheck = seconds_since_boot(); |
264 | } | 265 | } |
266 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
267 | |||
265 | #endif /* _LINUX_SUNRPC_CACHE_H_ */ | 268 | #endif /* _LINUX_SUNRPC_CACHE_H_ */ |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index c81d4d8be3a9..ea29330b78bd 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
@@ -269,6 +269,7 @@ struct svc_rqst { | |||
269 | struct cache_req rq_chandle; /* handle passed to caches for | 269 | struct cache_req rq_chandle; /* handle passed to caches for |
270 | * request delaying | 270 | * request delaying |
271 | */ | 271 | */ |
272 | bool rq_dropme; | ||
272 | /* Catering to nfsd */ | 273 | /* Catering to nfsd */ |
273 | struct auth_domain * rq_client; /* RPC peer info */ | 274 | struct auth_domain * rq_client; /* RPC peer info */ |
274 | struct auth_domain * rq_gssclient; /* "gss/"-style peer info */ | 275 | struct auth_domain * rq_gssclient; /* "gss/"-style peer info */ |
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 357da5e0daa3..059877b4d85b 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h | |||
@@ -63,7 +63,6 @@ struct svc_xprt { | |||
63 | #define XPT_LISTENER 11 /* listening endpoint */ | 63 | #define XPT_LISTENER 11 /* listening endpoint */ |
64 | #define XPT_CACHE_AUTH 12 /* cache auth info */ | 64 | #define XPT_CACHE_AUTH 12 /* cache auth info */ |
65 | 65 | ||
66 | struct svc_pool *xpt_pool; /* current pool iff queued */ | ||
67 | struct svc_serv *xpt_server; /* service for transport */ | 66 | struct svc_serv *xpt_server; /* service for transport */ |
68 | atomic_t xpt_reserved; /* space on outq that is rsvd */ | 67 | atomic_t xpt_reserved; /* space on outq that is rsvd */ |
69 | struct mutex xpt_mutex; /* to serialize sending data */ | 68 | struct mutex xpt_mutex; /* to serialize sending data */ |
@@ -81,6 +80,7 @@ struct svc_xprt { | |||
81 | void *xpt_bc_sid; /* back channel session ID */ | 80 | void *xpt_bc_sid; /* back channel session ID */ |
82 | 81 | ||
83 | struct net *xpt_net; | 82 | struct net *xpt_net; |
83 | struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */ | ||
84 | }; | 84 | }; |
85 | 85 | ||
86 | static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) | 86 | static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) |
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 1b353a76c304..04dba23c59f2 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h | |||
@@ -28,7 +28,6 @@ struct svc_sock { | |||
28 | /* private TCP part */ | 28 | /* private TCP part */ |
29 | u32 sk_reclen; /* length of record */ | 29 | u32 sk_reclen; /* length of record */ |
30 | u32 sk_tcplen; /* current read length */ | 30 | u32 sk_tcplen; /* current read length */ |
31 | struct rpc_xprt *sk_bc_xprt; /* NFSv4.1 backchannel xprt */ | ||
32 | }; | 31 | }; |
33 | 32 | ||
34 | /* | 33 | /* |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 89d10d279a20..bef0f535f746 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -321,6 +321,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); | |||
321 | #define XPRT_CLOSING (6) | 321 | #define XPRT_CLOSING (6) |
322 | #define XPRT_CONNECTION_ABORT (7) | 322 | #define XPRT_CONNECTION_ABORT (7) |
323 | #define XPRT_CONNECTION_CLOSE (8) | 323 | #define XPRT_CONNECTION_CLOSE (8) |
324 | #define XPRT_INITIALIZED (9) | ||
324 | 325 | ||
325 | static inline void xprt_set_connected(struct rpc_xprt *xprt) | 326 | static inline void xprt_set_connected(struct rpc_xprt *xprt) |
326 | { | 327 | { |
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 75ee993ea057..9576f35ab701 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
@@ -137,7 +137,7 @@ arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4]) | |||
137 | ms_usage = 13; | 137 | ms_usage = 13; |
138 | break; | 138 | break; |
139 | default: | 139 | default: |
140 | return EINVAL;; | 140 | return -EINVAL; |
141 | } | 141 | } |
142 | salt[0] = (ms_usage >> 0) & 0xff; | 142 | salt[0] = (ms_usage >> 0) & 0xff; |
143 | salt[1] = (ms_usage >> 8) & 0xff; | 143 | salt[1] = (ms_usage >> 8) & 0xff; |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index dec2a6fc7c12..bcdae78fdfc6 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -67,7 +67,6 @@ static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b) | |||
67 | 67 | ||
68 | #define RSI_HASHBITS 6 | 68 | #define RSI_HASHBITS 6 |
69 | #define RSI_HASHMAX (1<<RSI_HASHBITS) | 69 | #define RSI_HASHMAX (1<<RSI_HASHBITS) |
70 | #define RSI_HASHMASK (RSI_HASHMAX-1) | ||
71 | 70 | ||
72 | struct rsi { | 71 | struct rsi { |
73 | struct cache_head h; | 72 | struct cache_head h; |
@@ -319,7 +318,6 @@ static struct rsi *rsi_update(struct rsi *new, struct rsi *old) | |||
319 | 318 | ||
320 | #define RSC_HASHBITS 10 | 319 | #define RSC_HASHBITS 10 |
321 | #define RSC_HASHMAX (1<<RSC_HASHBITS) | 320 | #define RSC_HASHMAX (1<<RSC_HASHBITS) |
322 | #define RSC_HASHMASK (RSC_HASHMAX-1) | ||
323 | 321 | ||
324 | #define GSS_SEQ_WIN 128 | 322 | #define GSS_SEQ_WIN 128 |
325 | 323 | ||
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index e433e7580e27..72ad836e4fe0 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -37,7 +37,7 @@ | |||
37 | 37 | ||
38 | #define RPCDBG_FACILITY RPCDBG_CACHE | 38 | #define RPCDBG_FACILITY RPCDBG_CACHE |
39 | 39 | ||
40 | static void cache_defer_req(struct cache_req *req, struct cache_head *item); | 40 | static bool cache_defer_req(struct cache_req *req, struct cache_head *item); |
41 | static void cache_revisit_request(struct cache_head *item); | 41 | static void cache_revisit_request(struct cache_head *item); |
42 | 42 | ||
43 | static void cache_init(struct cache_head *h) | 43 | static void cache_init(struct cache_head *h) |
@@ -128,6 +128,7 @@ static void cache_fresh_locked(struct cache_head *head, time_t expiry) | |||
128 | { | 128 | { |
129 | head->expiry_time = expiry; | 129 | head->expiry_time = expiry; |
130 | head->last_refresh = seconds_since_boot(); | 130 | head->last_refresh = seconds_since_boot(); |
131 | smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */ | ||
131 | set_bit(CACHE_VALID, &head->flags); | 132 | set_bit(CACHE_VALID, &head->flags); |
132 | } | 133 | } |
133 | 134 | ||
@@ -208,11 +209,36 @@ static inline int cache_is_valid(struct cache_detail *detail, struct cache_head | |||
208 | /* entry is valid */ | 209 | /* entry is valid */ |
209 | if (test_bit(CACHE_NEGATIVE, &h->flags)) | 210 | if (test_bit(CACHE_NEGATIVE, &h->flags)) |
210 | return -ENOENT; | 211 | return -ENOENT; |
211 | else | 212 | else { |
213 | /* | ||
214 | * In combination with write barrier in | ||
215 | * sunrpc_cache_update, ensures that anyone | ||
216 | * using the cache entry after this sees the | ||
217 | * updated contents: | ||
218 | */ | ||
219 | smp_rmb(); | ||
212 | return 0; | 220 | return 0; |
221 | } | ||
213 | } | 222 | } |
214 | } | 223 | } |
215 | 224 | ||
225 | static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h) | ||
226 | { | ||
227 | int rv; | ||
228 | |||
229 | write_lock(&detail->hash_lock); | ||
230 | rv = cache_is_valid(detail, h); | ||
231 | if (rv != -EAGAIN) { | ||
232 | write_unlock(&detail->hash_lock); | ||
233 | return rv; | ||
234 | } | ||
235 | set_bit(CACHE_NEGATIVE, &h->flags); | ||
236 | cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); | ||
237 | write_unlock(&detail->hash_lock); | ||
238 | cache_fresh_unlocked(h, detail); | ||
239 | return -ENOENT; | ||
240 | } | ||
241 | |||
216 | /* | 242 | /* |
217 | * This is the generic cache management routine for all | 243 | * This is the generic cache management routine for all |
218 | * the authentication caches. | 244 | * the authentication caches. |
@@ -251,14 +277,8 @@ int cache_check(struct cache_detail *detail, | |||
251 | case -EINVAL: | 277 | case -EINVAL: |
252 | clear_bit(CACHE_PENDING, &h->flags); | 278 | clear_bit(CACHE_PENDING, &h->flags); |
253 | cache_revisit_request(h); | 279 | cache_revisit_request(h); |
254 | if (rv == -EAGAIN) { | 280 | rv = try_to_negate_entry(detail, h); |
255 | set_bit(CACHE_NEGATIVE, &h->flags); | ||
256 | cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); | ||
257 | cache_fresh_unlocked(h, detail); | ||
258 | rv = -ENOENT; | ||
259 | } | ||
260 | break; | 281 | break; |
261 | |||
262 | case -EAGAIN: | 282 | case -EAGAIN: |
263 | clear_bit(CACHE_PENDING, &h->flags); | 283 | clear_bit(CACHE_PENDING, &h->flags); |
264 | cache_revisit_request(h); | 284 | cache_revisit_request(h); |
@@ -268,9 +288,11 @@ int cache_check(struct cache_detail *detail, | |||
268 | } | 288 | } |
269 | 289 | ||
270 | if (rv == -EAGAIN) { | 290 | if (rv == -EAGAIN) { |
271 | cache_defer_req(rqstp, h); | 291 | if (!cache_defer_req(rqstp, h)) { |
272 | if (!test_bit(CACHE_PENDING, &h->flags)) { | 292 | /* |
273 | /* Request is not deferred */ | 293 | * Request was not deferred; handle it as best |
294 | * we can ourselves: | ||
295 | */ | ||
274 | rv = cache_is_valid(detail, h); | 296 | rv = cache_is_valid(detail, h); |
275 | if (rv == -EAGAIN) | 297 | if (rv == -EAGAIN) |
276 | rv = -ETIMEDOUT; | 298 | rv = -ETIMEDOUT; |
@@ -618,18 +640,19 @@ static void cache_limit_defers(void) | |||
618 | discard->revisit(discard, 1); | 640 | discard->revisit(discard, 1); |
619 | } | 641 | } |
620 | 642 | ||
621 | static void cache_defer_req(struct cache_req *req, struct cache_head *item) | 643 | /* Return true if and only if a deferred request is queued. */ |
644 | static bool cache_defer_req(struct cache_req *req, struct cache_head *item) | ||
622 | { | 645 | { |
623 | struct cache_deferred_req *dreq; | 646 | struct cache_deferred_req *dreq; |
624 | 647 | ||
625 | if (req->thread_wait) { | 648 | if (req->thread_wait) { |
626 | cache_wait_req(req, item); | 649 | cache_wait_req(req, item); |
627 | if (!test_bit(CACHE_PENDING, &item->flags)) | 650 | if (!test_bit(CACHE_PENDING, &item->flags)) |
628 | return; | 651 | return false; |
629 | } | 652 | } |
630 | dreq = req->defer(req); | 653 | dreq = req->defer(req); |
631 | if (dreq == NULL) | 654 | if (dreq == NULL) |
632 | return; | 655 | return false; |
633 | setup_deferral(dreq, item, 1); | 656 | setup_deferral(dreq, item, 1); |
634 | if (!test_bit(CACHE_PENDING, &item->flags)) | 657 | if (!test_bit(CACHE_PENDING, &item->flags)) |
635 | /* Bit could have been cleared before we managed to | 658 | /* Bit could have been cleared before we managed to |
@@ -638,6 +661,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
638 | cache_revisit_request(item); | 661 | cache_revisit_request(item); |
639 | 662 | ||
640 | cache_limit_defers(); | 663 | cache_limit_defers(); |
664 | return true; | ||
641 | } | 665 | } |
642 | 666 | ||
643 | static void cache_revisit_request(struct cache_head *item) | 667 | static void cache_revisit_request(struct cache_head *item) |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 0e659c665a8d..08e05a8ce025 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -1001,6 +1001,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | |||
1001 | rqstp->rq_splice_ok = 1; | 1001 | rqstp->rq_splice_ok = 1; |
1002 | /* Will be turned off only when NFSv4 Sessions are used */ | 1002 | /* Will be turned off only when NFSv4 Sessions are used */ |
1003 | rqstp->rq_usedeferral = 1; | 1003 | rqstp->rq_usedeferral = 1; |
1004 | rqstp->rq_dropme = false; | ||
1004 | 1005 | ||
1005 | /* Setup reply header */ | 1006 | /* Setup reply header */ |
1006 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); | 1007 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); |
@@ -1102,7 +1103,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) | |||
1102 | *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | 1103 | *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); |
1103 | 1104 | ||
1104 | /* Encode reply */ | 1105 | /* Encode reply */ |
1105 | if (*statp == rpc_drop_reply) { | 1106 | if (rqstp->rq_dropme) { |
1106 | if (procp->pc_release) | 1107 | if (procp->pc_release) |
1107 | procp->pc_release(rqstp, NULL, rqstp->rq_resp); | 1108 | procp->pc_release(rqstp, NULL, rqstp->rq_resp); |
1108 | goto dropit; | 1109 | goto dropit; |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 3f2c5559ca1a..ab86b7927f84 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/sunrpc/stats.h> | 13 | #include <linux/sunrpc/stats.h> |
14 | #include <linux/sunrpc/svc_xprt.h> | 14 | #include <linux/sunrpc/svc_xprt.h> |
15 | #include <linux/sunrpc/svcsock.h> | 15 | #include <linux/sunrpc/svcsock.h> |
16 | #include <linux/sunrpc/xprt.h> | ||
16 | 17 | ||
17 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT | 18 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
18 | 19 | ||
@@ -128,6 +129,9 @@ static void svc_xprt_free(struct kref *kref) | |||
128 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) | 129 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) |
129 | svcauth_unix_info_release(xprt); | 130 | svcauth_unix_info_release(xprt); |
130 | put_net(xprt->xpt_net); | 131 | put_net(xprt->xpt_net); |
132 | /* See comment on corresponding get in xs_setup_bc_tcp(): */ | ||
133 | if (xprt->xpt_bc_xprt) | ||
134 | xprt_put(xprt->xpt_bc_xprt); | ||
131 | xprt->xpt_ops->xpo_free(xprt); | 135 | xprt->xpt_ops->xpo_free(xprt); |
132 | module_put(owner); | 136 | module_put(owner); |
133 | } | 137 | } |
@@ -303,6 +307,15 @@ static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp) | |||
303 | list_del(&rqstp->rq_list); | 307 | list_del(&rqstp->rq_list); |
304 | } | 308 | } |
305 | 309 | ||
310 | static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) | ||
311 | { | ||
312 | if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE))) | ||
313 | return true; | ||
314 | if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED))) | ||
315 | return xprt->xpt_ops->xpo_has_wspace(xprt); | ||
316 | return false; | ||
317 | } | ||
318 | |||
306 | /* | 319 | /* |
307 | * Queue up a transport with data pending. If there are idle nfsd | 320 | * Queue up a transport with data pending. If there are idle nfsd |
308 | * processes, wake 'em up. | 321 | * processes, wake 'em up. |
@@ -315,8 +328,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
315 | struct svc_rqst *rqstp; | 328 | struct svc_rqst *rqstp; |
316 | int cpu; | 329 | int cpu; |
317 | 330 | ||
318 | if (!(xprt->xpt_flags & | 331 | if (!svc_xprt_has_something_to_do(xprt)) |
319 | ((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED)))) | ||
320 | return; | 332 | return; |
321 | 333 | ||
322 | cpu = get_cpu(); | 334 | cpu = get_cpu(); |
@@ -343,28 +355,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
343 | dprintk("svc: transport %p busy, not enqueued\n", xprt); | 355 | dprintk("svc: transport %p busy, not enqueued\n", xprt); |
344 | goto out_unlock; | 356 | goto out_unlock; |
345 | } | 357 | } |
346 | BUG_ON(xprt->xpt_pool != NULL); | ||
347 | xprt->xpt_pool = pool; | ||
348 | |||
349 | /* Handle pending connection */ | ||
350 | if (test_bit(XPT_CONN, &xprt->xpt_flags)) | ||
351 | goto process; | ||
352 | |||
353 | /* Handle close in-progress */ | ||
354 | if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) | ||
355 | goto process; | ||
356 | |||
357 | /* Check if we have space to reply to a request */ | ||
358 | if (!xprt->xpt_ops->xpo_has_wspace(xprt)) { | ||
359 | /* Don't enqueue while not enough space for reply */ | ||
360 | dprintk("svc: no write space, transport %p not enqueued\n", | ||
361 | xprt); | ||
362 | xprt->xpt_pool = NULL; | ||
363 | clear_bit(XPT_BUSY, &xprt->xpt_flags); | ||
364 | goto out_unlock; | ||
365 | } | ||
366 | 358 | ||
367 | process: | ||
368 | if (!list_empty(&pool->sp_threads)) { | 359 | if (!list_empty(&pool->sp_threads)) { |
369 | rqstp = list_entry(pool->sp_threads.next, | 360 | rqstp = list_entry(pool->sp_threads.next, |
370 | struct svc_rqst, | 361 | struct svc_rqst, |
@@ -381,13 +372,11 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
381 | rqstp->rq_reserved = serv->sv_max_mesg; | 372 | rqstp->rq_reserved = serv->sv_max_mesg; |
382 | atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); | 373 | atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); |
383 | pool->sp_stats.threads_woken++; | 374 | pool->sp_stats.threads_woken++; |
384 | BUG_ON(xprt->xpt_pool != pool); | ||
385 | wake_up(&rqstp->rq_wait); | 375 | wake_up(&rqstp->rq_wait); |
386 | } else { | 376 | } else { |
387 | dprintk("svc: transport %p put into queue\n", xprt); | 377 | dprintk("svc: transport %p put into queue\n", xprt); |
388 | list_add_tail(&xprt->xpt_ready, &pool->sp_sockets); | 378 | list_add_tail(&xprt->xpt_ready, &pool->sp_sockets); |
389 | pool->sp_stats.sockets_queued++; | 379 | pool->sp_stats.sockets_queued++; |
390 | BUG_ON(xprt->xpt_pool != pool); | ||
391 | } | 380 | } |
392 | 381 | ||
393 | out_unlock: | 382 | out_unlock: |
@@ -426,7 +415,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) | |||
426 | void svc_xprt_received(struct svc_xprt *xprt) | 415 | void svc_xprt_received(struct svc_xprt *xprt) |
427 | { | 416 | { |
428 | BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); | 417 | BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); |
429 | xprt->xpt_pool = NULL; | ||
430 | /* As soon as we clear busy, the xprt could be closed and | 418 | /* As soon as we clear busy, the xprt could be closed and |
431 | * 'put', so we need a reference to call svc_xprt_enqueue with: | 419 | * 'put', so we need a reference to call svc_xprt_enqueue with: |
432 | */ | 420 | */ |
@@ -722,7 +710,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
722 | if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { | 710 | if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { |
723 | dprintk("svc_recv: found XPT_CLOSE\n"); | 711 | dprintk("svc_recv: found XPT_CLOSE\n"); |
724 | svc_delete_xprt(xprt); | 712 | svc_delete_xprt(xprt); |
725 | } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { | 713 | /* Leave XPT_BUSY set on the dead xprt: */ |
714 | goto out; | ||
715 | } | ||
716 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { | ||
726 | struct svc_xprt *newxpt; | 717 | struct svc_xprt *newxpt; |
727 | newxpt = xprt->xpt_ops->xpo_accept(xprt); | 718 | newxpt = xprt->xpt_ops->xpo_accept(xprt); |
728 | if (newxpt) { | 719 | if (newxpt) { |
@@ -747,28 +738,23 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
747 | spin_unlock_bh(&serv->sv_lock); | 738 | spin_unlock_bh(&serv->sv_lock); |
748 | svc_xprt_received(newxpt); | 739 | svc_xprt_received(newxpt); |
749 | } | 740 | } |
750 | svc_xprt_received(xprt); | 741 | } else if (xprt->xpt_ops->xpo_has_wspace(xprt)) { |
751 | } else { | ||
752 | dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", | 742 | dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", |
753 | rqstp, pool->sp_id, xprt, | 743 | rqstp, pool->sp_id, xprt, |
754 | atomic_read(&xprt->xpt_ref.refcount)); | 744 | atomic_read(&xprt->xpt_ref.refcount)); |
755 | rqstp->rq_deferred = svc_deferred_dequeue(xprt); | 745 | rqstp->rq_deferred = svc_deferred_dequeue(xprt); |
756 | if (rqstp->rq_deferred) { | 746 | if (rqstp->rq_deferred) |
757 | svc_xprt_received(xprt); | ||
758 | len = svc_deferred_recv(rqstp); | 747 | len = svc_deferred_recv(rqstp); |
759 | } else { | 748 | else |
760 | len = xprt->xpt_ops->xpo_recvfrom(rqstp); | 749 | len = xprt->xpt_ops->xpo_recvfrom(rqstp); |
761 | svc_xprt_received(xprt); | ||
762 | } | ||
763 | dprintk("svc: got len=%d\n", len); | 750 | dprintk("svc: got len=%d\n", len); |
764 | } | 751 | } |
752 | svc_xprt_received(xprt); | ||
765 | 753 | ||
766 | /* No data, incomplete (TCP) read, or accept() */ | 754 | /* No data, incomplete (TCP) read, or accept() */ |
767 | if (len == 0 || len == -EAGAIN) { | 755 | if (len == 0 || len == -EAGAIN) |
768 | rqstp->rq_res.len = 0; | 756 | goto out; |
769 | svc_xprt_release(rqstp); | 757 | |
770 | return -EAGAIN; | ||
771 | } | ||
772 | clear_bit(XPT_OLD, &xprt->xpt_flags); | 758 | clear_bit(XPT_OLD, &xprt->xpt_flags); |
773 | 759 | ||
774 | rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp)); | 760 | rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp)); |
@@ -777,6 +763,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
777 | if (serv->sv_stats) | 763 | if (serv->sv_stats) |
778 | serv->sv_stats->netcnt++; | 764 | serv->sv_stats->netcnt++; |
779 | return len; | 765 | return len; |
766 | out: | ||
767 | rqstp->rq_res.len = 0; | ||
768 | svc_xprt_release(rqstp); | ||
769 | return -EAGAIN; | ||
780 | } | 770 | } |
781 | EXPORT_SYMBOL_GPL(svc_recv); | 771 | EXPORT_SYMBOL_GPL(svc_recv); |
782 | 772 | ||
@@ -935,7 +925,12 @@ void svc_close_xprt(struct svc_xprt *xprt) | |||
935 | if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) | 925 | if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) |
936 | /* someone else will have to effect the close */ | 926 | /* someone else will have to effect the close */ |
937 | return; | 927 | return; |
938 | 928 | /* | |
929 | * We expect svc_close_xprt() to work even when no threads are | ||
930 | * running (e.g., while configuring the server before starting | ||
931 | * any threads), so if the transport isn't busy, we delete | ||
932 | * it ourself: | ||
933 | */ | ||
939 | svc_delete_xprt(xprt); | 934 | svc_delete_xprt(xprt); |
940 | } | 935 | } |
941 | EXPORT_SYMBOL_GPL(svc_close_xprt); | 936 | EXPORT_SYMBOL_GPL(svc_close_xprt); |
@@ -945,16 +940,16 @@ void svc_close_all(struct list_head *xprt_list) | |||
945 | struct svc_xprt *xprt; | 940 | struct svc_xprt *xprt; |
946 | struct svc_xprt *tmp; | 941 | struct svc_xprt *tmp; |
947 | 942 | ||
943 | /* | ||
944 | * The server is shutting down, and no more threads are running. | ||
945 | * svc_xprt_enqueue() might still be running, but at worst it | ||
946 | * will re-add the xprt to sp_sockets, which will soon get | ||
947 | * freed. So we don't bother with any more locking, and don't | ||
948 | * leave the close to the (nonexistent) server threads: | ||
949 | */ | ||
948 | list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { | 950 | list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { |
949 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | 951 | set_bit(XPT_CLOSE, &xprt->xpt_flags); |
950 | if (test_bit(XPT_BUSY, &xprt->xpt_flags)) { | 952 | svc_delete_xprt(xprt); |
951 | /* Waiting to be processed, but no threads left, | ||
952 | * So just remove it from the waiting list | ||
953 | */ | ||
954 | list_del_init(&xprt->xpt_ready); | ||
955 | clear_bit(XPT_BUSY, &xprt->xpt_flags); | ||
956 | } | ||
957 | svc_close_xprt(xprt); | ||
958 | } | 953 | } |
959 | } | 954 | } |
960 | 955 | ||
@@ -1028,6 +1023,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req) | |||
1028 | } | 1023 | } |
1029 | svc_xprt_get(rqstp->rq_xprt); | 1024 | svc_xprt_get(rqstp->rq_xprt); |
1030 | dr->xprt = rqstp->rq_xprt; | 1025 | dr->xprt = rqstp->rq_xprt; |
1026 | rqstp->rq_dropme = true; | ||
1031 | 1027 | ||
1032 | dr->handle.revisit = svc_revisit; | 1028 | dr->handle.revisit = svc_revisit; |
1033 | return &dr->handle; | 1029 | return &dr->handle; |
@@ -1065,14 +1061,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) | |||
1065 | if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags)) | 1061 | if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags)) |
1066 | return NULL; | 1062 | return NULL; |
1067 | spin_lock(&xprt->xpt_lock); | 1063 | spin_lock(&xprt->xpt_lock); |
1068 | clear_bit(XPT_DEFERRED, &xprt->xpt_flags); | ||
1069 | if (!list_empty(&xprt->xpt_deferred)) { | 1064 | if (!list_empty(&xprt->xpt_deferred)) { |
1070 | dr = list_entry(xprt->xpt_deferred.next, | 1065 | dr = list_entry(xprt->xpt_deferred.next, |
1071 | struct svc_deferred_req, | 1066 | struct svc_deferred_req, |
1072 | handle.recent); | 1067 | handle.recent); |
1073 | list_del_init(&dr->handle.recent); | 1068 | list_del_init(&dr->handle.recent); |
1074 | set_bit(XPT_DEFERRED, &xprt->xpt_flags); | 1069 | } else |
1075 | } | 1070 | clear_bit(XPT_DEFERRED, &xprt->xpt_flags); |
1076 | spin_unlock(&xprt->xpt_lock); | 1071 | spin_unlock(&xprt->xpt_lock); |
1077 | return dr; | 1072 | return dr; |
1078 | } | 1073 | } |
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index 4e9393c24687..7963569fc04f 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c | |||
@@ -118,7 +118,6 @@ EXPORT_SYMBOL_GPL(svc_auth_unregister); | |||
118 | 118 | ||
119 | #define DN_HASHBITS 6 | 119 | #define DN_HASHBITS 6 |
120 | #define DN_HASHMAX (1<<DN_HASHBITS) | 120 | #define DN_HASHMAX (1<<DN_HASHBITS) |
121 | #define DN_HASHMASK (DN_HASHMAX-1) | ||
122 | 121 | ||
123 | static struct hlist_head auth_domain_table[DN_HASHMAX]; | 122 | static struct hlist_head auth_domain_table[DN_HASHMAX]; |
124 | static spinlock_t auth_domain_lock = | 123 | static spinlock_t auth_domain_lock = |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 560677d187f1..30916b06c12b 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -30,7 +30,9 @@ | |||
30 | 30 | ||
31 | struct unix_domain { | 31 | struct unix_domain { |
32 | struct auth_domain h; | 32 | struct auth_domain h; |
33 | #ifdef CONFIG_NFSD_DEPRECATED | ||
33 | int addr_changes; | 34 | int addr_changes; |
35 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
34 | /* other stuff later */ | 36 | /* other stuff later */ |
35 | }; | 37 | }; |
36 | 38 | ||
@@ -64,7 +66,9 @@ struct auth_domain *unix_domain_find(char *name) | |||
64 | return NULL; | 66 | return NULL; |
65 | } | 67 | } |
66 | new->h.flavour = &svcauth_unix; | 68 | new->h.flavour = &svcauth_unix; |
69 | #ifdef CONFIG_NFSD_DEPRECATED | ||
67 | new->addr_changes = 0; | 70 | new->addr_changes = 0; |
71 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
68 | rv = auth_domain_lookup(name, &new->h); | 72 | rv = auth_domain_lookup(name, &new->h); |
69 | } | 73 | } |
70 | } | 74 | } |
@@ -85,14 +89,15 @@ static void svcauth_unix_domain_release(struct auth_domain *dom) | |||
85 | */ | 89 | */ |
86 | #define IP_HASHBITS 8 | 90 | #define IP_HASHBITS 8 |
87 | #define IP_HASHMAX (1<<IP_HASHBITS) | 91 | #define IP_HASHMAX (1<<IP_HASHBITS) |
88 | #define IP_HASHMASK (IP_HASHMAX-1) | ||
89 | 92 | ||
90 | struct ip_map { | 93 | struct ip_map { |
91 | struct cache_head h; | 94 | struct cache_head h; |
92 | char m_class[8]; /* e.g. "nfsd" */ | 95 | char m_class[8]; /* e.g. "nfsd" */ |
93 | struct in6_addr m_addr; | 96 | struct in6_addr m_addr; |
94 | struct unix_domain *m_client; | 97 | struct unix_domain *m_client; |
98 | #ifdef CONFIG_NFSD_DEPRECATED | ||
95 | int m_add_change; | 99 | int m_add_change; |
100 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
96 | }; | 101 | }; |
97 | 102 | ||
98 | static void ip_map_put(struct kref *kref) | 103 | static void ip_map_put(struct kref *kref) |
@@ -146,7 +151,9 @@ static void update(struct cache_head *cnew, struct cache_head *citem) | |||
146 | 151 | ||
147 | kref_get(&item->m_client->h.ref); | 152 | kref_get(&item->m_client->h.ref); |
148 | new->m_client = item->m_client; | 153 | new->m_client = item->m_client; |
154 | #ifdef CONFIG_NFSD_DEPRECATED | ||
149 | new->m_add_change = item->m_add_change; | 155 | new->m_add_change = item->m_add_change; |
156 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
150 | } | 157 | } |
151 | static struct cache_head *ip_map_alloc(void) | 158 | static struct cache_head *ip_map_alloc(void) |
152 | { | 159 | { |
@@ -331,6 +338,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, | |||
331 | ip.h.flags = 0; | 338 | ip.h.flags = 0; |
332 | if (!udom) | 339 | if (!udom) |
333 | set_bit(CACHE_NEGATIVE, &ip.h.flags); | 340 | set_bit(CACHE_NEGATIVE, &ip.h.flags); |
341 | #ifdef CONFIG_NFSD_DEPRECATED | ||
334 | else { | 342 | else { |
335 | ip.m_add_change = udom->addr_changes; | 343 | ip.m_add_change = udom->addr_changes; |
336 | /* if this is from the legacy set_client system call, | 344 | /* if this is from the legacy set_client system call, |
@@ -339,6 +347,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, | |||
339 | if (expiry == NEVER) | 347 | if (expiry == NEVER) |
340 | ip.m_add_change++; | 348 | ip.m_add_change++; |
341 | } | 349 | } |
350 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
342 | ip.h.expiry_time = expiry; | 351 | ip.h.expiry_time = expiry; |
343 | ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, | 352 | ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, |
344 | hash_str(ipm->m_class, IP_HASHBITS) ^ | 353 | hash_str(ipm->m_class, IP_HASHBITS) ^ |
@@ -358,6 +367,7 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm, | |||
358 | return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); | 367 | return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); |
359 | } | 368 | } |
360 | 369 | ||
370 | #ifdef CONFIG_NFSD_DEPRECATED | ||
361 | int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom) | 371 | int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom) |
362 | { | 372 | { |
363 | struct unix_domain *udom; | 373 | struct unix_domain *udom; |
@@ -402,8 +412,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr) | |||
402 | return NULL; | 412 | return NULL; |
403 | 413 | ||
404 | if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { | 414 | if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { |
405 | if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0) | 415 | sunrpc_invalidate(&ipm->h, sn->ip_map_cache); |
406 | auth_domain_put(&ipm->m_client->h); | ||
407 | rv = NULL; | 416 | rv = NULL; |
408 | } else { | 417 | } else { |
409 | rv = &ipm->m_client->h; | 418 | rv = &ipm->m_client->h; |
@@ -413,6 +422,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr) | |||
413 | return rv; | 422 | return rv; |
414 | } | 423 | } |
415 | EXPORT_SYMBOL_GPL(auth_unix_lookup); | 424 | EXPORT_SYMBOL_GPL(auth_unix_lookup); |
425 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
416 | 426 | ||
417 | void svcauth_unix_purge(void) | 427 | void svcauth_unix_purge(void) |
418 | { | 428 | { |
@@ -497,7 +507,6 @@ svcauth_unix_info_release(struct svc_xprt *xpt) | |||
497 | */ | 507 | */ |
498 | #define GID_HASHBITS 8 | 508 | #define GID_HASHBITS 8 |
499 | #define GID_HASHMAX (1<<GID_HASHBITS) | 509 | #define GID_HASHMAX (1<<GID_HASHBITS) |
500 | #define GID_HASHMASK (GID_HASHMAX - 1) | ||
501 | 510 | ||
502 | struct unix_gid { | 511 | struct unix_gid { |
503 | struct cache_head h; | 512 | struct cache_head h; |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index d265aa700bb3..7bd3bbba4710 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -331,19 +331,21 @@ int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen, | |||
331 | len = onelen; | 331 | len = onelen; |
332 | break; | 332 | break; |
333 | } | 333 | } |
334 | if (toclose && strcmp(toclose, buf + len) == 0) | 334 | if (toclose && strcmp(toclose, buf + len) == 0) { |
335 | closesk = svsk; | 335 | closesk = svsk; |
336 | else | 336 | svc_xprt_get(&closesk->sk_xprt); |
337 | } else | ||
337 | len += onelen; | 338 | len += onelen; |
338 | } | 339 | } |
339 | spin_unlock_bh(&serv->sv_lock); | 340 | spin_unlock_bh(&serv->sv_lock); |
340 | 341 | ||
341 | if (closesk) | 342 | if (closesk) { |
342 | /* Should unregister with portmap, but you cannot | 343 | /* Should unregister with portmap, but you cannot |
343 | * unregister just one protocol... | 344 | * unregister just one protocol... |
344 | */ | 345 | */ |
345 | svc_close_xprt(&closesk->sk_xprt); | 346 | svc_close_xprt(&closesk->sk_xprt); |
346 | else if (toclose) | 347 | svc_xprt_put(&closesk->sk_xprt); |
348 | } else if (toclose) | ||
347 | return -ENOENT; | 349 | return -ENOENT; |
348 | return len; | 350 | return len; |
349 | } | 351 | } |
@@ -992,15 +994,17 @@ static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp, | |||
992 | vec[0] = rqstp->rq_arg.head[0]; | 994 | vec[0] = rqstp->rq_arg.head[0]; |
993 | } else { | 995 | } else { |
994 | /* REPLY */ | 996 | /* REPLY */ |
995 | if (svsk->sk_bc_xprt) | 997 | struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt; |
996 | req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid); | 998 | |
999 | if (bc_xprt) | ||
1000 | req = xprt_lookup_rqst(bc_xprt, xid); | ||
997 | 1001 | ||
998 | if (!req) { | 1002 | if (!req) { |
999 | printk(KERN_NOTICE | 1003 | printk(KERN_NOTICE |
1000 | "%s: Got unrecognized reply: " | 1004 | "%s: Got unrecognized reply: " |
1001 | "calldir 0x%x sk_bc_xprt %p xid %08x\n", | 1005 | "calldir 0x%x xpt_bc_xprt %p xid %08x\n", |
1002 | __func__, ntohl(calldir), | 1006 | __func__, ntohl(calldir), |
1003 | svsk->sk_bc_xprt, xid); | 1007 | bc_xprt, xid); |
1004 | vec[0] = rqstp->rq_arg.head[0]; | 1008 | vec[0] = rqstp->rq_arg.head[0]; |
1005 | goto out; | 1009 | goto out; |
1006 | } | 1010 | } |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 4c8f18aff7c3..856274d7e85c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -965,6 +965,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req) | |||
965 | xprt = kzalloc(size, GFP_KERNEL); | 965 | xprt = kzalloc(size, GFP_KERNEL); |
966 | if (xprt == NULL) | 966 | if (xprt == NULL) |
967 | goto out; | 967 | goto out; |
968 | kref_init(&xprt->kref); | ||
968 | 969 | ||
969 | xprt->max_reqs = max_req; | 970 | xprt->max_reqs = max_req; |
970 | xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL); | 971 | xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL); |
@@ -1101,8 +1102,10 @@ found: | |||
1101 | -PTR_ERR(xprt)); | 1102 | -PTR_ERR(xprt)); |
1102 | return xprt; | 1103 | return xprt; |
1103 | } | 1104 | } |
1105 | if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state)) | ||
1106 | /* ->setup returned a pre-initialized xprt: */ | ||
1107 | return xprt; | ||
1104 | 1108 | ||
1105 | kref_init(&xprt->kref); | ||
1106 | spin_lock_init(&xprt->transport_lock); | 1109 | spin_lock_init(&xprt->transport_lock); |
1107 | spin_lock_init(&xprt->reserve_lock); | 1110 | spin_lock_init(&xprt->reserve_lock); |
1108 | 1111 | ||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 96549df836ee..c431f5a57960 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -2359,6 +2359,15 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
2359 | struct svc_sock *bc_sock; | 2359 | struct svc_sock *bc_sock; |
2360 | struct rpc_xprt *ret; | 2360 | struct rpc_xprt *ret; |
2361 | 2361 | ||
2362 | if (args->bc_xprt->xpt_bc_xprt) { | ||
2363 | /* | ||
2364 | * This server connection already has a backchannel | ||
2365 | * export; we can't create a new one, as we wouldn't be | ||
2366 | * able to match replies based on xid any more. So, | ||
2367 | * reuse the already-existing one: | ||
2368 | */ | ||
2369 | return args->bc_xprt->xpt_bc_xprt; | ||
2370 | } | ||
2362 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); | 2371 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); |
2363 | if (IS_ERR(xprt)) | 2372 | if (IS_ERR(xprt)) |
2364 | return xprt; | 2373 | return xprt; |
@@ -2375,16 +2384,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
2375 | xprt->reestablish_timeout = 0; | 2384 | xprt->reestablish_timeout = 0; |
2376 | xprt->idle_timeout = 0; | 2385 | xprt->idle_timeout = 0; |
2377 | 2386 | ||
2378 | /* | ||
2379 | * The backchannel uses the same socket connection as the | ||
2380 | * forechannel | ||
2381 | */ | ||
2382 | xprt->bc_xprt = args->bc_xprt; | ||
2383 | bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt); | ||
2384 | bc_sock->sk_bc_xprt = xprt; | ||
2385 | transport->sock = bc_sock->sk_sock; | ||
2386 | transport->inet = bc_sock->sk_sk; | ||
2387 | |||
2388 | xprt->ops = &bc_tcp_ops; | 2387 | xprt->ops = &bc_tcp_ops; |
2389 | 2388 | ||
2390 | switch (addr->sa_family) { | 2389 | switch (addr->sa_family) { |
@@ -2407,6 +2406,20 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
2407 | xprt->address_strings[RPC_DISPLAY_PROTO]); | 2406 | xprt->address_strings[RPC_DISPLAY_PROTO]); |
2408 | 2407 | ||
2409 | /* | 2408 | /* |
2409 | * Once we've associated a backchannel xprt with a connection, | ||
2410 | * we want to keep it around as long as long as the connection | ||
2411 | * lasts, in case we need to start using it for a backchannel | ||
2412 | * again; this reference won't be dropped until bc_xprt is | ||
2413 | * destroyed. | ||
2414 | */ | ||
2415 | xprt_get(xprt); | ||
2416 | args->bc_xprt->xpt_bc_xprt = xprt; | ||
2417 | xprt->bc_xprt = args->bc_xprt; | ||
2418 | bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt); | ||
2419 | transport->sock = bc_sock->sk_sock; | ||
2420 | transport->inet = bc_sock->sk_sk; | ||
2421 | |||
2422 | /* | ||
2410 | * Since we don't want connections for the backchannel, we set | 2423 | * Since we don't want connections for the backchannel, we set |
2411 | * the xprt status to connected | 2424 | * the xprt status to connected |
2412 | */ | 2425 | */ |
@@ -2415,6 +2428,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
2415 | 2428 | ||
2416 | if (try_module_get(THIS_MODULE)) | 2429 | if (try_module_get(THIS_MODULE)) |
2417 | return xprt; | 2430 | return xprt; |
2431 | xprt_put(xprt); | ||
2418 | ret = ERR_PTR(-EINVAL); | 2432 | ret = ERR_PTR(-EINVAL); |
2419 | out_err: | 2433 | out_err: |
2420 | xprt_free(xprt); | 2434 | xprt_free(xprt); |