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 /fs/nfsd | |
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.
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/acl.h | 59 | ||||
-rw-r--r-- | fs/nfsd/export.c | 4 | ||||
-rw-r--r-- | fs/nfsd/idmap.h | 62 | ||||
-rw-r--r-- | fs/nfsd/nfs3proc.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfs4acl.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 151 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 15 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 59 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 243 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 115 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 1 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 6 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/state.h | 16 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 85 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 9 |
18 files changed, 572 insertions, 270 deletions
diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h new file mode 100644 index 000000000000..34e5c40af5ef --- /dev/null +++ b/fs/nfsd/acl.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Common NFSv4 ACL handling definitions. | ||
3 | * | ||
4 | * Copyright (c) 2002 The Regents of the University of Michigan. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Marius Aamodt Eriksen <marius@umich.edu> | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * 3. Neither the name of the University nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
25 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #ifndef LINUX_NFS4_ACL_H | ||
36 | #define LINUX_NFS4_ACL_H | ||
37 | |||
38 | #include <linux/posix_acl.h> | ||
39 | |||
40 | /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to | ||
41 | * fit in a page: */ | ||
42 | #define NFS4_ACL_MAX 170 | ||
43 | |||
44 | struct nfs4_acl *nfs4_acl_new(int); | ||
45 | int nfs4_acl_get_whotype(char *, u32); | ||
46 | int nfs4_acl_write_who(int who, char *p); | ||
47 | int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group, | ||
48 | uid_t who, u32 mask); | ||
49 | |||
50 | #define NFS4_ACL_TYPE_DEFAULT 0x01 | ||
51 | #define NFS4_ACL_DIR 0x02 | ||
52 | #define NFS4_ACL_OWNER 0x04 | ||
53 | |||
54 | struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *, | ||
55 | struct posix_acl *, unsigned int flags); | ||
56 | int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **, | ||
57 | struct posix_acl **, unsigned int flags); | ||
58 | |||
59 | #endif /* LINUX_NFS4_ACL_H */ | ||
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/fs/nfsd/idmap.h b/fs/nfsd/idmap.h new file mode 100644 index 000000000000..2f3be1321534 --- /dev/null +++ b/fs/nfsd/idmap.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Mapping of UID to name and vice versa. | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003 The Regents of the University of | ||
5 | * Michigan. All rights reserved. | ||
6 | > * | ||
7 | * Marius Aamodt Eriksen <marius@umich.edu> | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * 3. Neither the name of the University nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
25 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #ifndef LINUX_NFSD_IDMAP_H | ||
36 | #define LINUX_NFSD_IDMAP_H | ||
37 | |||
38 | #include <linux/in.h> | ||
39 | #include <linux/sunrpc/svc.h> | ||
40 | |||
41 | /* XXX from linux/nfs_idmap.h */ | ||
42 | #define IDMAP_NAMESZ 128 | ||
43 | |||
44 | #ifdef CONFIG_NFSD_V4 | ||
45 | int nfsd_idmap_init(void); | ||
46 | void nfsd_idmap_shutdown(void); | ||
47 | #else | ||
48 | static inline int nfsd_idmap_init(void) | ||
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | static inline void nfsd_idmap_shutdown(void) | ||
53 | { | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | __be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *); | ||
58 | __be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *); | ||
59 | int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *); | ||
60 | int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *); | ||
61 | |||
62 | #endif /* LINUX_NFSD_IDMAP_H */ | ||
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 *); |