diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-14 16:17:26 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-14 16:17:26 -0500 |
| commit | 18bce371ae09af6c20ee62c1092a4d1d0e84dd49 (patch) | |
| tree | f3467fafd8e49392e3f6efef7b88a7b4dd3b7b06 | |
| parent | ec08bdb148767f1193f5f3028749ed865ac27181 (diff) | |
| parent | a8f2800b4f7b76cecb7209cb6a7d2b14904fc711 (diff) | |
Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.38' of git://linux-nfs.org/~bfields/linux: (62 commits)
nfsd4: fix callback restarting
nfsd: break lease on unlink, link, and rename
nfsd4: break lease on nfsd setattr
nfsd: don't support msnfs export option
nfsd4: initialize cb_per_client
nfsd4: allow restarting callbacks
nfsd4: simplify nfsd4_cb_prepare
nfsd4: give out delegations more quickly in 4.1 case
nfsd4: add helper function to run callbacks
nfsd4: make sure sequence flags are set after destroy_session
nfsd4: re-probe callback on connection loss
nfsd4: set sequence flag when backchannel is down
nfsd4: keep finer-grained callback status
rpc: allow xprt_class->setup to return a preexisting xprt
rpc: keep backchannel xprt as long as server connection
rpc: move sk_bc_xprt to svc_xprt
nfsd4: allow backchannel recovery
nfsd4: support BIND_CONN_TO_SESSION
nfsd4: modify session list under cl_lock
Documentation: fl_mylease no longer exists
...
Fix up conflicts in fs/nfsd/vfs.c with the vfs-scale work. The
vfs-scale work touched some msnfs cases, and this merge removes support
for that entirely, so the conflict was trivial to resolve.
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); |
