diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nfsd | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/Kconfig | 13 | ||||
-rw-r--r-- | fs/nfsd/acl.h | 59 | ||||
-rw-r--r-- | fs/nfsd/export.c | 84 | ||||
-rw-r--r-- | fs/nfsd/idmap.h | 62 | ||||
-rw-r--r-- | fs/nfsd/lockd.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs3proc.c | 10 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 10 | ||||
-rw-r--r-- | fs/nfsd/nfs4acl.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 1034 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 121 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 143 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 1117 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 145 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 67 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 3 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 6 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 7 | ||||
-rw-r--r-- | fs/nfsd/nfsxdr.c | 2 | ||||
-rw-r--r-- | fs/nfsd/state.h | 83 | ||||
-rw-r--r-- | fs/nfsd/stats.c | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 186 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 6 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 30 |
25 files changed, 1979 insertions, 1217 deletions
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 4264377552e2..fbb2a5ef5817 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig | |||
@@ -28,6 +28,18 @@ config NFSD | |||
28 | 28 | ||
29 | If unsure, say N. | 29 | If unsure, say N. |
30 | 30 | ||
31 | config NFSD_DEPRECATED | ||
32 | bool "Include support for deprecated syscall interface to NFSD" | ||
33 | depends on NFSD | ||
34 | default y | ||
35 | help | ||
36 | The syscall interface to nfsd was obsoleted in 2.6.0 by a new | ||
37 | filesystem based interface. The old interface is due for removal | ||
38 | in 2.6.40. If you wish to remove the interface before then | ||
39 | say N. | ||
40 | |||
41 | In unsure, say Y. | ||
42 | |||
31 | config NFSD_V2_ACL | 43 | config NFSD_V2_ACL |
32 | bool | 44 | bool |
33 | depends on NFSD | 45 | depends on NFSD |
@@ -70,6 +82,7 @@ config NFSD_V4 | |||
70 | select NFSD_V3 | 82 | select NFSD_V3 |
71 | select FS_POSIX_ACL | 83 | select FS_POSIX_ACL |
72 | select SUNRPC_GSS | 84 | select SUNRPC_GSS |
85 | select CRYPTO | ||
73 | help | 86 | help |
74 | This option enables support in your system's NFS server for | 87 | This option enables support in your system's NFS server for |
75 | version 4 of the NFS protocol (RFC 3530). | 88 | version 4 of the NFS protocol (RFC 3530). |
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 c2a4f71d87dd..b9566e46219f 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 | * |
@@ -28,9 +27,6 @@ | |||
28 | typedef struct auth_domain svc_client; | 27 | typedef struct auth_domain svc_client; |
29 | typedef struct svc_export svc_export; | 28 | typedef struct svc_export svc_export; |
30 | 29 | ||
31 | static void exp_do_unexport(svc_export *unexp); | ||
32 | static int exp_verify_string(char *cp, int max); | ||
33 | |||
34 | /* | 30 | /* |
35 | * We have two caches. | 31 | * We have two caches. |
36 | * One maps client+vfsmnt+dentry to export options - the export map | 32 | * One maps client+vfsmnt+dentry to export options - the export map |
@@ -303,7 +299,6 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) | |||
303 | 299 | ||
304 | #define EXPORT_HASHBITS 8 | 300 | #define EXPORT_HASHBITS 8 |
305 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) | 301 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) |
306 | #define EXPORT_HASHMASK (EXPORT_HASHMAX -1) | ||
307 | 302 | ||
308 | static struct cache_head *export_table[EXPORT_HASHMAX]; | 303 | static struct cache_head *export_table[EXPORT_HASHMAX]; |
309 | 304 | ||
@@ -802,6 +797,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | |||
802 | return ek; | 797 | return ek; |
803 | } | 798 | } |
804 | 799 | ||
800 | #ifdef CONFIG_NFSD_DEPRECATED | ||
805 | static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, | 801 | static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, |
806 | struct svc_export *exp) | 802 | struct svc_export *exp) |
807 | { | 803 | { |
@@ -852,6 +848,7 @@ exp_get_fsid_key(svc_client *clp, int fsid) | |||
852 | 848 | ||
853 | return exp_find_key(clp, FSID_NUM, fsidv, NULL); | 849 | return exp_find_key(clp, FSID_NUM, fsidv, NULL); |
854 | } | 850 | } |
851 | #endif | ||
855 | 852 | ||
856 | static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, | 853 | static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, |
857 | struct cache_req *reqp) | 854 | struct cache_req *reqp) |
@@ -893,6 +890,7 @@ static struct svc_export *exp_parent(svc_client *clp, struct path *path) | |||
893 | return exp; | 890 | return exp; |
894 | } | 891 | } |
895 | 892 | ||
893 | #ifdef CONFIG_NFSD_DEPRECATED | ||
896 | /* | 894 | /* |
897 | * Hashtable locking. Write locks are placed only by user processes | 895 | * Hashtable locking. Write locks are placed only by user processes |
898 | * wanting to modify export information. | 896 | * wanting to modify export information. |
@@ -925,6 +923,19 @@ exp_writeunlock(void) | |||
925 | { | 923 | { |
926 | up_write(&hash_sem); | 924 | up_write(&hash_sem); |
927 | } | 925 | } |
926 | #else | ||
927 | |||
928 | /* hash_sem not needed once deprecated interface is removed */ | ||
929 | void exp_readlock(void) {} | ||
930 | static inline void exp_writelock(void){} | ||
931 | void exp_readunlock(void) {} | ||
932 | static inline void exp_writeunlock(void){} | ||
933 | |||
934 | #endif | ||
935 | |||
936 | #ifdef CONFIG_NFSD_DEPRECATED | ||
937 | static void exp_do_unexport(svc_export *unexp); | ||
938 | static int exp_verify_string(char *cp, int max); | ||
928 | 939 | ||
929 | static void exp_fsid_unhash(struct svc_export *exp) | 940 | static void exp_fsid_unhash(struct svc_export *exp) |
930 | { | 941 | { |
@@ -935,10 +946,9 @@ static void exp_fsid_unhash(struct svc_export *exp) | |||
935 | 946 | ||
936 | ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); | 947 | ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); |
937 | if (!IS_ERR(ek)) { | 948 | if (!IS_ERR(ek)) { |
938 | ek->h.expiry_time = get_seconds()-1; | 949 | sunrpc_invalidate(&ek->h, &svc_expkey_cache); |
939 | cache_put(&ek->h, &svc_expkey_cache); | 950 | cache_put(&ek->h, &svc_expkey_cache); |
940 | } | 951 | } |
941 | svc_expkey_cache.nextcheck = get_seconds(); | ||
942 | } | 952 | } |
943 | 953 | ||
944 | static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) | 954 | static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) |
@@ -973,10 +983,9 @@ static void exp_unhash(struct svc_export *exp) | |||
973 | 983 | ||
974 | ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); | 984 | ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); |
975 | if (!IS_ERR(ek)) { | 985 | if (!IS_ERR(ek)) { |
976 | ek->h.expiry_time = get_seconds()-1; | 986 | sunrpc_invalidate(&ek->h, &svc_expkey_cache); |
977 | cache_put(&ek->h, &svc_expkey_cache); | 987 | cache_put(&ek->h, &svc_expkey_cache); |
978 | } | 988 | } |
979 | svc_expkey_cache.nextcheck = get_seconds(); | ||
980 | } | 989 | } |
981 | 990 | ||
982 | /* | 991 | /* |
@@ -1097,8 +1106,7 @@ out: | |||
1097 | static void | 1106 | static void |
1098 | exp_do_unexport(svc_export *unexp) | 1107 | exp_do_unexport(svc_export *unexp) |
1099 | { | 1108 | { |
1100 | unexp->h.expiry_time = get_seconds()-1; | 1109 | sunrpc_invalidate(&unexp->h, &svc_export_cache); |
1101 | svc_export_cache.nextcheck = get_seconds(); | ||
1102 | exp_unhash(unexp); | 1110 | exp_unhash(unexp); |
1103 | exp_fsid_unhash(unexp); | 1111 | exp_fsid_unhash(unexp); |
1104 | } | 1112 | } |
@@ -1150,6 +1158,7 @@ out_unlock: | |||
1150 | exp_writeunlock(); | 1158 | exp_writeunlock(); |
1151 | return err; | 1159 | return err; |
1152 | } | 1160 | } |
1161 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
1153 | 1162 | ||
1154 | /* | 1163 | /* |
1155 | * Obtain the root fh on behalf of a client. | 1164 | * Obtain the root fh on behalf of a client. |
@@ -1345,12 +1354,6 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
1345 | if (IS_ERR(exp)) | 1354 | if (IS_ERR(exp)) |
1346 | return nfserrno(PTR_ERR(exp)); | 1355 | return nfserrno(PTR_ERR(exp)); |
1347 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); | 1356 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); |
1348 | if (rv) | ||
1349 | goto out; | ||
1350 | rv = check_nfsd_access(exp, rqstp); | ||
1351 | if (rv) | ||
1352 | fh_put(fhp); | ||
1353 | out: | ||
1354 | exp_put(exp); | 1357 | exp_put(exp); |
1355 | return rv; | 1358 | return rv; |
1356 | } | 1359 | } |
@@ -1433,9 +1436,6 @@ static struct flags { | |||
1433 | { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, | 1436 | { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, |
1434 | { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, | 1437 | { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, |
1435 | { NFSEXP_V4ROOT, {"v4root", ""}}, | 1438 | { NFSEXP_V4ROOT, {"v4root", ""}}, |
1436 | #ifdef MSNFS | ||
1437 | { NFSEXP_MSNFS, {"msnfs", ""}}, | ||
1438 | #endif | ||
1439 | { 0, {"", ""}} | 1439 | { 0, {"", ""}} |
1440 | }; | 1440 | }; |
1441 | 1441 | ||
@@ -1459,25 +1459,43 @@ static void show_secinfo_flags(struct seq_file *m, int flags) | |||
1459 | show_expflags(m, flags, NFSEXP_SECINFO_FLAGS); | 1459 | show_expflags(m, flags, NFSEXP_SECINFO_FLAGS); |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | static bool secinfo_flags_equal(int f, int g) | ||
1463 | { | ||
1464 | f &= NFSEXP_SECINFO_FLAGS; | ||
1465 | g &= NFSEXP_SECINFO_FLAGS; | ||
1466 | return f == g; | ||
1467 | } | ||
1468 | |||
1469 | static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end) | ||
1470 | { | ||
1471 | int flags; | ||
1472 | |||
1473 | flags = (*fp)->flags; | ||
1474 | seq_printf(m, ",sec=%d", (*fp)->pseudoflavor); | ||
1475 | (*fp)++; | ||
1476 | while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) { | ||
1477 | seq_printf(m, ":%d", (*fp)->pseudoflavor); | ||
1478 | (*fp)++; | ||
1479 | } | ||
1480 | return flags; | ||
1481 | } | ||
1482 | |||
1462 | static void show_secinfo(struct seq_file *m, struct svc_export *exp) | 1483 | static void show_secinfo(struct seq_file *m, struct svc_export *exp) |
1463 | { | 1484 | { |
1464 | struct exp_flavor_info *f; | 1485 | struct exp_flavor_info *f; |
1465 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | 1486 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; |
1466 | int lastflags = 0, first = 0; | 1487 | int flags; |
1467 | 1488 | ||
1468 | if (exp->ex_nflavors == 0) | 1489 | if (exp->ex_nflavors == 0) |
1469 | return; | 1490 | return; |
1470 | for (f = exp->ex_flavors; f < end; f++) { | 1491 | f = exp->ex_flavors; |
1471 | if (first || f->flags != lastflags) { | 1492 | flags = show_secinfo_run(m, &f, end); |
1472 | if (!first) | 1493 | if (!secinfo_flags_equal(flags, exp->ex_flags)) |
1473 | show_secinfo_flags(m, lastflags); | 1494 | show_secinfo_flags(m, flags); |
1474 | seq_printf(m, ",sec=%d", f->pseudoflavor); | 1495 | while (f != end) { |
1475 | lastflags = f->flags; | 1496 | flags = show_secinfo_run(m, &f, end); |
1476 | } else { | 1497 | show_secinfo_flags(m, flags); |
1477 | seq_printf(m, ":%d", f->pseudoflavor); | ||
1478 | } | ||
1479 | } | 1498 | } |
1480 | show_secinfo_flags(m, lastflags); | ||
1481 | } | 1499 | } |
1482 | 1500 | ||
1483 | static void exp_flags(struct seq_file *m, int flag, int fsid, | 1501 | static void exp_flags(struct seq_file *m, int flag, int fsid, |
@@ -1532,6 +1550,7 @@ const struct seq_operations nfs_exports_op = { | |||
1532 | .show = e_show, | 1550 | .show = e_show, |
1533 | }; | 1551 | }; |
1534 | 1552 | ||
1553 | #ifdef CONFIG_NFSD_DEPRECATED | ||
1535 | /* | 1554 | /* |
1536 | * Add or modify a client. | 1555 | * Add or modify a client. |
1537 | * Change requests may involve the list of host addresses. The list of | 1556 | * Change requests may involve the list of host addresses. The list of |
@@ -1563,7 +1582,7 @@ exp_addclient(struct nfsctl_client *ncp) | |||
1563 | /* Insert client into hashtable. */ | 1582 | /* Insert client into hashtable. */ |
1564 | for (i = 0; i < ncp->cl_naddr; i++) { | 1583 | for (i = 0; i < ncp->cl_naddr; i++) { |
1565 | ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6); | 1584 | ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6); |
1566 | auth_unix_add_addr(&addr6, dom); | 1585 | auth_unix_add_addr(&init_net, &addr6, dom); |
1567 | } | 1586 | } |
1568 | auth_unix_forget_old(dom); | 1587 | auth_unix_forget_old(dom); |
1569 | auth_domain_put(dom); | 1588 | auth_domain_put(dom); |
@@ -1621,6 +1640,7 @@ exp_verify_string(char *cp, int max) | |||
1621 | printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp); | 1640 | printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp); |
1622 | return 0; | 1641 | return 0; |
1623 | } | 1642 | } |
1643 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
1624 | 1644 | ||
1625 | /* | 1645 | /* |
1626 | * Initialize the exports module. | 1646 | * Initialize the exports module. |
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/lockd.c b/fs/nfsd/lockd.c index 0c6d81670137..7c831a2731fa 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c | |||
@@ -38,7 +38,6 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) | |||
38 | exp_readlock(); | 38 | exp_readlock(); |
39 | nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); | 39 | nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); |
40 | fh_put(&fh); | 40 | fh_put(&fh); |
41 | rqstp->rq_client = NULL; | ||
42 | exp_readunlock(); | 41 | exp_readunlock(); |
43 | /* We return nlm error codes as nlm doesn't know | 42 | /* We return nlm error codes as nlm doesn't know |
44 | * about nfsd, but nfsd does know about nlm.. | 43 | * about nfsd, but nfsd does know about nlm.. |
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 5b7e3021e06b..9095f3c21df9 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); |
@@ -245,7 +245,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, | |||
245 | } | 245 | } |
246 | 246 | ||
247 | /* Now create the file and set attributes */ | 247 | /* Now create the file and set attributes */ |
248 | nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len, | 248 | nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, |
249 | attr, newfhp, | 249 | attr, newfhp, |
250 | argp->createmode, argp->verf, NULL, NULL); | 250 | argp->createmode, argp->verf, NULL, NULL); |
251 | 251 | ||
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 2a533a0af2a9..08c6e36ab2eb 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -260,9 +260,11 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
260 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 260 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
261 | &fhp->fh_post_attr); | 261 | &fhp->fh_post_attr); |
262 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | 262 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; |
263 | if (err) | 263 | if (err) { |
264 | fhp->fh_post_saved = 0; | 264 | fhp->fh_post_saved = 0; |
265 | else | 265 | /* Grab the ctime anyway - set_change_info might use it */ |
266 | fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime; | ||
267 | } else | ||
266 | fhp->fh_post_saved = 1; | 268 | fhp->fh_post_saved = 1; |
267 | } | 269 | } |
268 | 270 | ||
@@ -700,7 +702,7 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p, | |||
700 | *p++ = htonl(resp->eof); | 702 | *p++ = htonl(resp->eof); |
701 | *p++ = htonl(resp->count); /* xdr opaque count */ | 703 | *p++ = htonl(resp->count); /* xdr opaque count */ |
702 | xdr_ressize_check(rqstp, p); | 704 | xdr_ressize_check(rqstp, p); |
703 | /* now update rqstp->rq_res to reflect data aswell */ | 705 | /* now update rqstp->rq_res to reflect data as well */ |
704 | rqstp->rq_res.page_len = resp->count; | 706 | rqstp->rq_res.page_len = resp->count; |
705 | if (resp->count & 3) { | 707 | if (resp->count & 3) { |
706 | /* need to pad the tail */ | 708 | /* need to pad the tail */ |
@@ -840,7 +842,7 @@ out: | |||
840 | return rv; | 842 | return rv; |
841 | } | 843 | } |
842 | 844 | ||
843 | __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen) | 845 | static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen) |
844 | { | 846 | { |
845 | struct svc_fh fh; | 847 | struct svc_fh fh; |
846 | int err; | 848 | int err; |
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 988cbb3a19b6..02eb4edf0ece 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -41,7 +41,6 @@ | |||
41 | 41 | ||
42 | #define NFSPROC4_CB_NULL 0 | 42 | #define NFSPROC4_CB_NULL 0 |
43 | #define NFSPROC4_CB_COMPOUND 1 | 43 | #define NFSPROC4_CB_COMPOUND 1 |
44 | #define NFS4_STATEID_SIZE 16 | ||
45 | 44 | ||
46 | /* Index of predefined Linux callback client operations */ | 45 | /* Index of predefined Linux callback client operations */ |
47 | 46 | ||
@@ -51,11 +50,6 @@ enum { | |||
51 | NFSPROC4_CLNT_CB_SEQUENCE, | 50 | NFSPROC4_CLNT_CB_SEQUENCE, |
52 | }; | 51 | }; |
53 | 52 | ||
54 | enum nfs_cb_opnum4 { | ||
55 | OP_CB_RECALL = 4, | ||
56 | OP_CB_SEQUENCE = 11, | ||
57 | }; | ||
58 | |||
59 | #define NFS4_MAXTAGLEN 20 | 53 | #define NFS4_MAXTAGLEN 20 |
60 | 54 | ||
61 | #define NFS4_enc_cb_null_sz 0 | 55 | #define NFS4_enc_cb_null_sz 0 |
@@ -80,61 +74,6 @@ enum nfs_cb_opnum4 { | |||
80 | cb_sequence_dec_sz + \ | 74 | cb_sequence_dec_sz + \ |
81 | op_dec_sz) | 75 | op_dec_sz) |
82 | 76 | ||
83 | /* | ||
84 | * Generic encode routines from fs/nfs/nfs4xdr.c | ||
85 | */ | ||
86 | static inline __be32 * | ||
87 | xdr_writemem(__be32 *p, const void *ptr, int nbytes) | ||
88 | { | ||
89 | int tmp = XDR_QUADLEN(nbytes); | ||
90 | if (!tmp) | ||
91 | return p; | ||
92 | p[tmp-1] = 0; | ||
93 | memcpy(p, ptr, nbytes); | ||
94 | return p + tmp; | ||
95 | } | ||
96 | |||
97 | #define WRITE32(n) *p++ = htonl(n) | ||
98 | #define WRITEMEM(ptr,nbytes) do { \ | ||
99 | p = xdr_writemem(p, ptr, nbytes); \ | ||
100 | } while (0) | ||
101 | #define RESERVE_SPACE(nbytes) do { \ | ||
102 | p = xdr_reserve_space(xdr, nbytes); \ | ||
103 | if (!p) dprintk("NFSD: RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __func__); \ | ||
104 | BUG_ON(!p); \ | ||
105 | } while (0) | ||
106 | |||
107 | /* | ||
108 | * Generic decode routines from fs/nfs/nfs4xdr.c | ||
109 | */ | ||
110 | #define DECODE_TAIL \ | ||
111 | status = 0; \ | ||
112 | out: \ | ||
113 | return status; \ | ||
114 | xdr_error: \ | ||
115 | dprintk("NFSD: xdr error! (%s:%d)\n", __FILE__, __LINE__); \ | ||
116 | status = -EIO; \ | ||
117 | goto out | ||
118 | |||
119 | #define READ32(x) (x) = ntohl(*p++) | ||
120 | #define READ64(x) do { \ | ||
121 | (x) = (u64)ntohl(*p++) << 32; \ | ||
122 | (x) |= ntohl(*p++); \ | ||
123 | } while (0) | ||
124 | #define READTIME(x) do { \ | ||
125 | p++; \ | ||
126 | (x.tv_sec) = ntohl(*p++); \ | ||
127 | (x.tv_nsec) = ntohl(*p++); \ | ||
128 | } while (0) | ||
129 | #define READ_BUF(nbytes) do { \ | ||
130 | p = xdr_inline_decode(xdr, nbytes); \ | ||
131 | if (!p) { \ | ||
132 | dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \ | ||
133 | __func__, __LINE__); \ | ||
134 | return -EIO; \ | ||
135 | } \ | ||
136 | } while (0) | ||
137 | |||
138 | struct nfs4_cb_compound_hdr { | 77 | struct nfs4_cb_compound_hdr { |
139 | /* args */ | 78 | /* args */ |
140 | u32 ident; /* minorversion 0 only */ | 79 | u32 ident; /* minorversion 0 only */ |
@@ -145,270 +84,487 @@ struct nfs4_cb_compound_hdr { | |||
145 | int status; | 84 | int status; |
146 | }; | 85 | }; |
147 | 86 | ||
148 | static struct { | 87 | /* |
149 | int stat; | 88 | * Handle decode buffer overflows out-of-line. |
150 | int errno; | 89 | */ |
151 | } nfs_cb_errtbl[] = { | 90 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
152 | { NFS4_OK, 0 }, | 91 | { |
153 | { NFS4ERR_PERM, EPERM }, | 92 | dprintk("NFS: %s prematurely hit the end of our receive buffer. " |
154 | { NFS4ERR_NOENT, ENOENT }, | 93 | "Remaining buffer length is %tu words.\n", |
155 | { NFS4ERR_IO, EIO }, | 94 | func, xdr->end - xdr->p); |
156 | { NFS4ERR_NXIO, ENXIO }, | 95 | } |
157 | { NFS4ERR_ACCESS, EACCES }, | ||
158 | { NFS4ERR_EXIST, EEXIST }, | ||
159 | { NFS4ERR_XDEV, EXDEV }, | ||
160 | { NFS4ERR_NOTDIR, ENOTDIR }, | ||
161 | { NFS4ERR_ISDIR, EISDIR }, | ||
162 | { NFS4ERR_INVAL, EINVAL }, | ||
163 | { NFS4ERR_FBIG, EFBIG }, | ||
164 | { NFS4ERR_NOSPC, ENOSPC }, | ||
165 | { NFS4ERR_ROFS, EROFS }, | ||
166 | { NFS4ERR_MLINK, EMLINK }, | ||
167 | { NFS4ERR_NAMETOOLONG, ENAMETOOLONG }, | ||
168 | { NFS4ERR_NOTEMPTY, ENOTEMPTY }, | ||
169 | { NFS4ERR_DQUOT, EDQUOT }, | ||
170 | { NFS4ERR_STALE, ESTALE }, | ||
171 | { NFS4ERR_BADHANDLE, EBADHANDLE }, | ||
172 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, | ||
173 | { NFS4ERR_NOTSUPP, ENOTSUPP }, | ||
174 | { NFS4ERR_TOOSMALL, ETOOSMALL }, | ||
175 | { NFS4ERR_SERVERFAULT, ESERVERFAULT }, | ||
176 | { NFS4ERR_BADTYPE, EBADTYPE }, | ||
177 | { NFS4ERR_LOCKED, EAGAIN }, | ||
178 | { NFS4ERR_RESOURCE, EREMOTEIO }, | ||
179 | { NFS4ERR_SYMLINK, ELOOP }, | ||
180 | { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP }, | ||
181 | { NFS4ERR_DEADLOCK, EDEADLK }, | ||
182 | { -1, EIO } | ||
183 | }; | ||
184 | 96 | ||
185 | static int | 97 | static __be32 *xdr_encode_empty_array(__be32 *p) |
186 | nfs_cb_stat_to_errno(int stat) | ||
187 | { | 98 | { |
188 | int i; | 99 | *p++ = xdr_zero; |
189 | for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) { | 100 | return p; |
190 | if (nfs_cb_errtbl[i].stat == stat) | ||
191 | return nfs_cb_errtbl[i].errno; | ||
192 | } | ||
193 | /* If we cannot translate the error, the recovery routines should | ||
194 | * handle it. | ||
195 | * Note: remaining NFSv4 error codes have values > 10000, so should | ||
196 | * not conflict with native Linux error codes. | ||
197 | */ | ||
198 | return stat; | ||
199 | } | 101 | } |
200 | 102 | ||
201 | /* | 103 | /* |
202 | * XDR encode | 104 | * Encode/decode NFSv4 CB basic data types |
105 | * | ||
106 | * Basic NFSv4 callback data types are defined in section 15 of RFC | ||
107 | * 3530: "Network File System (NFS) version 4 Protocol" and section | ||
108 | * 20 of RFC 5661: "Network File System (NFS) Version 4 Minor Version | ||
109 | * 1 Protocol" | ||
203 | */ | 110 | */ |
204 | 111 | ||
205 | static void | 112 | /* |
206 | encode_stateid(struct xdr_stream *xdr, stateid_t *sid) | 113 | * nfs_cb_opnum4 |
114 | * | ||
115 | * enum nfs_cb_opnum4 { | ||
116 | * OP_CB_GETATTR = 3, | ||
117 | * ... | ||
118 | * }; | ||
119 | */ | ||
120 | enum nfs_cb_opnum4 { | ||
121 | OP_CB_GETATTR = 3, | ||
122 | OP_CB_RECALL = 4, | ||
123 | OP_CB_LAYOUTRECALL = 5, | ||
124 | OP_CB_NOTIFY = 6, | ||
125 | OP_CB_PUSH_DELEG = 7, | ||
126 | OP_CB_RECALL_ANY = 8, | ||
127 | OP_CB_RECALLABLE_OBJ_AVAIL = 9, | ||
128 | OP_CB_RECALL_SLOT = 10, | ||
129 | OP_CB_SEQUENCE = 11, | ||
130 | OP_CB_WANTS_CANCELLED = 12, | ||
131 | OP_CB_NOTIFY_LOCK = 13, | ||
132 | OP_CB_NOTIFY_DEVICEID = 14, | ||
133 | OP_CB_ILLEGAL = 10044 | ||
134 | }; | ||
135 | |||
136 | static void encode_nfs_cb_opnum4(struct xdr_stream *xdr, enum nfs_cb_opnum4 op) | ||
207 | { | 137 | { |
208 | __be32 *p; | 138 | __be32 *p; |
209 | 139 | ||
210 | RESERVE_SPACE(sizeof(stateid_t)); | 140 | p = xdr_reserve_space(xdr, 4); |
211 | WRITE32(sid->si_generation); | 141 | *p = cpu_to_be32(op); |
212 | WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); | ||
213 | } | 142 | } |
214 | 143 | ||
215 | static void | 144 | /* |
216 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) | 145 | * nfs_fh4 |
146 | * | ||
147 | * typedef opaque nfs_fh4<NFS4_FHSIZE>; | ||
148 | */ | ||
149 | static void encode_nfs_fh4(struct xdr_stream *xdr, const struct knfsd_fh *fh) | ||
217 | { | 150 | { |
218 | __be32 * p; | 151 | u32 length = fh->fh_size; |
152 | __be32 *p; | ||
219 | 153 | ||
220 | RESERVE_SPACE(16); | 154 | BUG_ON(length > NFS4_FHSIZE); |
221 | WRITE32(0); /* tag length is always 0 */ | 155 | p = xdr_reserve_space(xdr, 4 + length); |
222 | WRITE32(hdr->minorversion); | 156 | xdr_encode_opaque(p, &fh->fh_base, length); |
223 | WRITE32(hdr->ident); | ||
224 | hdr->nops_p = p; | ||
225 | WRITE32(hdr->nops); | ||
226 | } | 157 | } |
227 | 158 | ||
228 | static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr) | 159 | /* |
160 | * stateid4 | ||
161 | * | ||
162 | * struct stateid4 { | ||
163 | * uint32_t seqid; | ||
164 | * opaque other[12]; | ||
165 | * }; | ||
166 | */ | ||
167 | static void encode_stateid4(struct xdr_stream *xdr, const stateid_t *sid) | ||
229 | { | 168 | { |
230 | *hdr->nops_p = htonl(hdr->nops); | 169 | __be32 *p; |
170 | |||
171 | p = xdr_reserve_space(xdr, NFS4_STATEID_SIZE); | ||
172 | *p++ = cpu_to_be32(sid->si_generation); | ||
173 | xdr_encode_opaque_fixed(p, &sid->si_opaque, NFS4_STATEID_OTHER_SIZE); | ||
231 | } | 174 | } |
232 | 175 | ||
233 | static void | 176 | /* |
234 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, | 177 | * sessionid4 |
235 | struct nfs4_cb_compound_hdr *hdr) | 178 | * |
179 | * typedef opaque sessionid4[NFS4_SESSIONID_SIZE]; | ||
180 | */ | ||
181 | static void encode_sessionid4(struct xdr_stream *xdr, | ||
182 | const struct nfsd4_session *session) | ||
236 | { | 183 | { |
237 | __be32 *p; | 184 | __be32 *p; |
238 | int len = dp->dl_fh.fh_size; | 185 | |
239 | 186 | p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN); | |
240 | RESERVE_SPACE(4); | 187 | xdr_encode_opaque_fixed(p, session->se_sessionid.data, |
241 | WRITE32(OP_CB_RECALL); | 188 | NFS4_MAX_SESSIONID_LEN); |
242 | encode_stateid(xdr, &dp->dl_stateid); | ||
243 | RESERVE_SPACE(8 + (XDR_QUADLEN(len) << 2)); | ||
244 | WRITE32(0); /* truncate optimization not implemented */ | ||
245 | WRITE32(len); | ||
246 | WRITEMEM(&dp->dl_fh.fh_base, len); | ||
247 | hdr->nops++; | ||
248 | } | 189 | } |
249 | 190 | ||
250 | static void | 191 | /* |
251 | encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *args, | 192 | * nfsstat4 |
252 | struct nfs4_cb_compound_hdr *hdr) | 193 | */ |
253 | { | 194 | static const struct { |
254 | __be32 *p; | 195 | int stat; |
196 | int errno; | ||
197 | } nfs_cb_errtbl[] = { | ||
198 | { NFS4_OK, 0 }, | ||
199 | { NFS4ERR_PERM, -EPERM }, | ||
200 | { NFS4ERR_NOENT, -ENOENT }, | ||
201 | { NFS4ERR_IO, -EIO }, | ||
202 | { NFS4ERR_NXIO, -ENXIO }, | ||
203 | { NFS4ERR_ACCESS, -EACCES }, | ||
204 | { NFS4ERR_EXIST, -EEXIST }, | ||
205 | { NFS4ERR_XDEV, -EXDEV }, | ||
206 | { NFS4ERR_NOTDIR, -ENOTDIR }, | ||
207 | { NFS4ERR_ISDIR, -EISDIR }, | ||
208 | { NFS4ERR_INVAL, -EINVAL }, | ||
209 | { NFS4ERR_FBIG, -EFBIG }, | ||
210 | { NFS4ERR_NOSPC, -ENOSPC }, | ||
211 | { NFS4ERR_ROFS, -EROFS }, | ||
212 | { NFS4ERR_MLINK, -EMLINK }, | ||
213 | { NFS4ERR_NAMETOOLONG, -ENAMETOOLONG }, | ||
214 | { NFS4ERR_NOTEMPTY, -ENOTEMPTY }, | ||
215 | { NFS4ERR_DQUOT, -EDQUOT }, | ||
216 | { NFS4ERR_STALE, -ESTALE }, | ||
217 | { NFS4ERR_BADHANDLE, -EBADHANDLE }, | ||
218 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, | ||
219 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, | ||
220 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, | ||
221 | { NFS4ERR_SERVERFAULT, -ESERVERFAULT }, | ||
222 | { NFS4ERR_BADTYPE, -EBADTYPE }, | ||
223 | { NFS4ERR_LOCKED, -EAGAIN }, | ||
224 | { NFS4ERR_RESOURCE, -EREMOTEIO }, | ||
225 | { NFS4ERR_SYMLINK, -ELOOP }, | ||
226 | { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, | ||
227 | { NFS4ERR_DEADLOCK, -EDEADLK }, | ||
228 | { -1, -EIO } | ||
229 | }; | ||
255 | 230 | ||
256 | if (hdr->minorversion == 0) | 231 | /* |
257 | return; | 232 | * If we cannot translate the error, the recovery routines should |
233 | * handle it. | ||
234 | * | ||
235 | * Note: remaining NFSv4 error codes have values > 10000, so should | ||
236 | * not conflict with native Linux error codes. | ||
237 | */ | ||
238 | static int nfs_cb_stat_to_errno(int status) | ||
239 | { | ||
240 | int i; | ||
258 | 241 | ||
259 | RESERVE_SPACE(1 + NFS4_MAX_SESSIONID_LEN + 20); | 242 | for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) { |
243 | if (nfs_cb_errtbl[i].stat == status) | ||
244 | return nfs_cb_errtbl[i].errno; | ||
245 | } | ||
260 | 246 | ||
261 | WRITE32(OP_CB_SEQUENCE); | 247 | dprintk("NFSD: Unrecognized NFS CB status value: %u\n", status); |
262 | WRITEMEM(args->cbs_clp->cl_sessionid.data, NFS4_MAX_SESSIONID_LEN); | 248 | return -status; |
263 | WRITE32(args->cbs_clp->cl_cb_seq_nr); | ||
264 | WRITE32(0); /* slotid, always 0 */ | ||
265 | WRITE32(0); /* highest slotid always 0 */ | ||
266 | WRITE32(0); /* cachethis always 0 */ | ||
267 | WRITE32(0); /* FIXME: support referring_call_lists */ | ||
268 | hdr->nops++; | ||
269 | } | 249 | } |
270 | 250 | ||
271 | static int | 251 | static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, |
272 | nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | 252 | enum nfsstat4 *status) |
273 | { | 253 | { |
274 | struct xdr_stream xdrs, *xdr = &xdrs; | 254 | __be32 *p; |
255 | u32 op; | ||
275 | 256 | ||
276 | xdr_init_encode(&xdrs, &req->rq_snd_buf, p); | 257 | p = xdr_inline_decode(xdr, 4 + 4); |
277 | RESERVE_SPACE(0); | 258 | if (unlikely(p == NULL)) |
259 | goto out_overflow; | ||
260 | op = be32_to_cpup(p++); | ||
261 | if (unlikely(op != expected)) | ||
262 | goto out_unexpected; | ||
263 | *status = be32_to_cpup(p); | ||
278 | return 0; | 264 | return 0; |
265 | out_overflow: | ||
266 | print_overflow_msg(__func__, xdr); | ||
267 | return -EIO; | ||
268 | out_unexpected: | ||
269 | dprintk("NFSD: Callback server returned operation %d but " | ||
270 | "we issued a request for %d\n", op, expected); | ||
271 | return -EIO; | ||
279 | } | 272 | } |
280 | 273 | ||
281 | static int | 274 | /* |
282 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, | 275 | * CB_COMPOUND4args |
283 | struct nfs4_rpc_args *rpc_args) | 276 | * |
277 | * struct CB_COMPOUND4args { | ||
278 | * utf8str_cs tag; | ||
279 | * uint32_t minorversion; | ||
280 | * uint32_t callback_ident; | ||
281 | * nfs_cb_argop4 argarray<>; | ||
282 | * }; | ||
283 | */ | ||
284 | static void encode_cb_compound4args(struct xdr_stream *xdr, | ||
285 | struct nfs4_cb_compound_hdr *hdr) | ||
284 | { | 286 | { |
285 | struct xdr_stream xdr; | 287 | __be32 * p; |
286 | struct nfs4_delegation *args = rpc_args->args_op; | ||
287 | struct nfs4_cb_compound_hdr hdr = { | ||
288 | .ident = args->dl_ident, | ||
289 | .minorversion = rpc_args->args_seq.cbs_minorversion, | ||
290 | }; | ||
291 | 288 | ||
292 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 289 | p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4); |
293 | encode_cb_compound_hdr(&xdr, &hdr); | 290 | p = xdr_encode_empty_array(p); /* empty tag */ |
294 | encode_cb_sequence(&xdr, &rpc_args->args_seq, &hdr); | 291 | *p++ = cpu_to_be32(hdr->minorversion); |
295 | encode_cb_recall(&xdr, args, &hdr); | 292 | *p++ = cpu_to_be32(hdr->ident); |
296 | encode_cb_nops(&hdr); | 293 | |
294 | hdr->nops_p = p; | ||
295 | *p = cpu_to_be32(hdr->nops); /* argarray element count */ | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Update argarray element count | ||
300 | */ | ||
301 | static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr) | ||
302 | { | ||
303 | BUG_ON(hdr->nops > NFS4_MAX_BACK_CHANNEL_OPS); | ||
304 | *hdr->nops_p = cpu_to_be32(hdr->nops); | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * CB_COMPOUND4res | ||
309 | * | ||
310 | * struct CB_COMPOUND4res { | ||
311 | * nfsstat4 status; | ||
312 | * utf8str_cs tag; | ||
313 | * nfs_cb_resop4 resarray<>; | ||
314 | * }; | ||
315 | */ | ||
316 | static int decode_cb_compound4res(struct xdr_stream *xdr, | ||
317 | struct nfs4_cb_compound_hdr *hdr) | ||
318 | { | ||
319 | u32 length; | ||
320 | __be32 *p; | ||
321 | |||
322 | p = xdr_inline_decode(xdr, 4 + 4); | ||
323 | if (unlikely(p == NULL)) | ||
324 | goto out_overflow; | ||
325 | hdr->status = be32_to_cpup(p++); | ||
326 | /* Ignore the tag */ | ||
327 | length = be32_to_cpup(p++); | ||
328 | p = xdr_inline_decode(xdr, length + 4); | ||
329 | if (unlikely(p == NULL)) | ||
330 | goto out_overflow; | ||
331 | hdr->nops = be32_to_cpup(p); | ||
297 | return 0; | 332 | return 0; |
333 | out_overflow: | ||
334 | print_overflow_msg(__func__, xdr); | ||
335 | return -EIO; | ||
298 | } | 336 | } |
299 | 337 | ||
338 | /* | ||
339 | * CB_RECALL4args | ||
340 | * | ||
341 | * struct CB_RECALL4args { | ||
342 | * stateid4 stateid; | ||
343 | * bool truncate; | ||
344 | * nfs_fh4 fh; | ||
345 | * }; | ||
346 | */ | ||
347 | static void encode_cb_recall4args(struct xdr_stream *xdr, | ||
348 | const struct nfs4_delegation *dp, | ||
349 | struct nfs4_cb_compound_hdr *hdr) | ||
350 | { | ||
351 | __be32 *p; | ||
352 | |||
353 | encode_nfs_cb_opnum4(xdr, OP_CB_RECALL); | ||
354 | encode_stateid4(xdr, &dp->dl_stateid); | ||
300 | 355 | ||
301 | static int | 356 | p = xdr_reserve_space(xdr, 4); |
302 | decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ | 357 | *p++ = xdr_zero; /* truncate */ |
303 | __be32 *p; | ||
304 | u32 taglen; | ||
305 | 358 | ||
306 | READ_BUF(8); | 359 | encode_nfs_fh4(xdr, &dp->dl_fh); |
307 | READ32(hdr->status); | 360 | |
308 | /* We've got no use for the tag; ignore it: */ | 361 | hdr->nops++; |
309 | READ32(taglen); | ||
310 | READ_BUF(taglen + 4); | ||
311 | p += XDR_QUADLEN(taglen); | ||
312 | READ32(hdr->nops); | ||
313 | return 0; | ||
314 | } | 362 | } |
315 | 363 | ||
316 | static int | 364 | /* |
317 | decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | 365 | * CB_SEQUENCE4args |
366 | * | ||
367 | * struct CB_SEQUENCE4args { | ||
368 | * sessionid4 csa_sessionid; | ||
369 | * sequenceid4 csa_sequenceid; | ||
370 | * slotid4 csa_slotid; | ||
371 | * slotid4 csa_highest_slotid; | ||
372 | * bool csa_cachethis; | ||
373 | * referring_call_list4 csa_referring_call_lists<>; | ||
374 | * }; | ||
375 | */ | ||
376 | static void encode_cb_sequence4args(struct xdr_stream *xdr, | ||
377 | const struct nfsd4_callback *cb, | ||
378 | struct nfs4_cb_compound_hdr *hdr) | ||
318 | { | 379 | { |
380 | struct nfsd4_session *session = cb->cb_clp->cl_cb_session; | ||
319 | __be32 *p; | 381 | __be32 *p; |
320 | u32 op; | 382 | |
321 | int32_t nfserr; | 383 | if (hdr->minorversion == 0) |
322 | 384 | return; | |
323 | READ_BUF(8); | 385 | |
324 | READ32(op); | 386 | encode_nfs_cb_opnum4(xdr, OP_CB_SEQUENCE); |
325 | if (op != expected) { | 387 | encode_sessionid4(xdr, session); |
326 | dprintk("NFSD: decode_cb_op_hdr: Callback server returned " | 388 | |
327 | " operation %d but we issued a request for %d\n", | 389 | p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4 + 4); |
328 | op, expected); | 390 | *p++ = cpu_to_be32(session->se_cb_seq_nr); /* csa_sequenceid */ |
329 | return -EIO; | 391 | *p++ = xdr_zero; /* csa_slotid */ |
330 | } | 392 | *p++ = xdr_zero; /* csa_highest_slotid */ |
331 | READ32(nfserr); | 393 | *p++ = xdr_zero; /* csa_cachethis */ |
332 | if (nfserr != NFS_OK) | 394 | xdr_encode_empty_array(p); /* csa_referring_call_lists */ |
333 | return -nfs_cb_stat_to_errno(nfserr); | 395 | |
334 | return 0; | 396 | hdr->nops++; |
335 | } | 397 | } |
336 | 398 | ||
337 | /* | 399 | /* |
400 | * CB_SEQUENCE4resok | ||
401 | * | ||
402 | * struct CB_SEQUENCE4resok { | ||
403 | * sessionid4 csr_sessionid; | ||
404 | * sequenceid4 csr_sequenceid; | ||
405 | * slotid4 csr_slotid; | ||
406 | * slotid4 csr_highest_slotid; | ||
407 | * slotid4 csr_target_highest_slotid; | ||
408 | * }; | ||
409 | * | ||
410 | * union CB_SEQUENCE4res switch (nfsstat4 csr_status) { | ||
411 | * case NFS4_OK: | ||
412 | * CB_SEQUENCE4resok csr_resok4; | ||
413 | * default: | ||
414 | * void; | ||
415 | * }; | ||
416 | * | ||
338 | * Our current back channel implmentation supports a single backchannel | 417 | * Our current back channel implmentation supports a single backchannel |
339 | * with a single slot. | 418 | * with a single slot. |
340 | */ | 419 | */ |
341 | static int | 420 | static int decode_cb_sequence4resok(struct xdr_stream *xdr, |
342 | decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *res, | 421 | struct nfsd4_callback *cb) |
343 | struct rpc_rqst *rqstp) | ||
344 | { | 422 | { |
423 | struct nfsd4_session *session = cb->cb_clp->cl_cb_session; | ||
345 | struct nfs4_sessionid id; | 424 | struct nfs4_sessionid id; |
346 | int status; | 425 | int status; |
347 | u32 dummy; | ||
348 | __be32 *p; | 426 | __be32 *p; |
427 | u32 dummy; | ||
349 | 428 | ||
350 | if (res->cbs_minorversion == 0) | 429 | status = -ESERVERFAULT; |
351 | return 0; | ||
352 | |||
353 | status = decode_cb_op_hdr(xdr, OP_CB_SEQUENCE); | ||
354 | if (status) | ||
355 | return status; | ||
356 | 430 | ||
357 | /* | 431 | /* |
358 | * If the server returns different values for sessionID, slotID or | 432 | * If the server returns different values for sessionID, slotID or |
359 | * sequence number, the server is looney tunes. | 433 | * sequence number, the server is looney tunes. |
360 | */ | 434 | */ |
361 | status = -ESERVERFAULT; | 435 | p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4 + 4 + 4); |
362 | 436 | if (unlikely(p == NULL)) | |
363 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); | 437 | goto out_overflow; |
364 | memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN); | 438 | memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN); |
365 | p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN); | 439 | if (memcmp(id.data, session->se_sessionid.data, |
366 | if (memcmp(id.data, res->cbs_clp->cl_sessionid.data, | 440 | NFS4_MAX_SESSIONID_LEN) != 0) { |
367 | NFS4_MAX_SESSIONID_LEN)) { | 441 | dprintk("NFS: %s Invalid session id\n", __func__); |
368 | dprintk("%s Invalid session id\n", __func__); | ||
369 | goto out; | 442 | goto out; |
370 | } | 443 | } |
371 | READ32(dummy); | 444 | p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN); |
372 | if (dummy != res->cbs_clp->cl_cb_seq_nr) { | 445 | |
373 | dprintk("%s Invalid sequence number\n", __func__); | 446 | dummy = be32_to_cpup(p++); |
447 | if (dummy != session->se_cb_seq_nr) { | ||
448 | dprintk("NFS: %s Invalid sequence number\n", __func__); | ||
374 | goto out; | 449 | goto out; |
375 | } | 450 | } |
376 | READ32(dummy); /* slotid must be 0 */ | 451 | |
452 | dummy = be32_to_cpup(p++); | ||
377 | if (dummy != 0) { | 453 | if (dummy != 0) { |
378 | dprintk("%s Invalid slotid\n", __func__); | 454 | dprintk("NFS: %s Invalid slotid\n", __func__); |
379 | goto out; | 455 | goto out; |
380 | } | 456 | } |
381 | /* FIXME: process highest slotid and target highest slotid */ | 457 | |
458 | /* | ||
459 | * FIXME: process highest slotid and target highest slotid | ||
460 | */ | ||
382 | status = 0; | 461 | status = 0; |
383 | out: | 462 | out: |
384 | return status; | 463 | return status; |
464 | out_overflow: | ||
465 | print_overflow_msg(__func__, xdr); | ||
466 | return -EIO; | ||
467 | } | ||
468 | |||
469 | static int decode_cb_sequence4res(struct xdr_stream *xdr, | ||
470 | struct nfsd4_callback *cb) | ||
471 | { | ||
472 | enum nfsstat4 nfserr; | ||
473 | int status; | ||
474 | |||
475 | if (cb->cb_minorversion == 0) | ||
476 | return 0; | ||
477 | |||
478 | status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr); | ||
479 | if (unlikely(status)) | ||
480 | goto out; | ||
481 | if (unlikely(nfserr != NFS4_OK)) | ||
482 | goto out_default; | ||
483 | status = decode_cb_sequence4resok(xdr, cb); | ||
484 | out: | ||
485 | return status; | ||
486 | out_default: | ||
487 | return nfs_cb_stat_to_errno(nfserr); | ||
488 | } | ||
489 | |||
490 | /* | ||
491 | * NFSv4.0 and NFSv4.1 XDR encode functions | ||
492 | * | ||
493 | * NFSv4.0 callback argument types are defined in section 15 of RFC | ||
494 | * 3530: "Network File System (NFS) version 4 Protocol" and section 20 | ||
495 | * of RFC 5661: "Network File System (NFS) Version 4 Minor Version 1 | ||
496 | * Protocol". | ||
497 | */ | ||
498 | |||
499 | /* | ||
500 | * NB: Without this zero space reservation, callbacks over krb5p fail | ||
501 | */ | ||
502 | static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr, | ||
503 | void *__unused) | ||
504 | { | ||
505 | xdr_reserve_space(xdr, 0); | ||
506 | } | ||
507 | |||
508 | /* | ||
509 | * 20.2. Operation 4: CB_RECALL - Recall a Delegation | ||
510 | */ | ||
511 | static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr, | ||
512 | const struct nfsd4_callback *cb) | ||
513 | { | ||
514 | const struct nfs4_delegation *args = cb->cb_op; | ||
515 | struct nfs4_cb_compound_hdr hdr = { | ||
516 | .ident = cb->cb_clp->cl_cb_ident, | ||
517 | .minorversion = cb->cb_minorversion, | ||
518 | }; | ||
519 | |||
520 | encode_cb_compound4args(xdr, &hdr); | ||
521 | encode_cb_sequence4args(xdr, cb, &hdr); | ||
522 | encode_cb_recall4args(xdr, args, &hdr); | ||
523 | encode_cb_nops(&hdr); | ||
385 | } | 524 | } |
386 | 525 | ||
387 | 526 | ||
388 | static int | 527 | /* |
389 | nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) | 528 | * NFSv4.0 and NFSv4.1 XDR decode functions |
529 | * | ||
530 | * NFSv4.0 callback result types are defined in section 15 of RFC | ||
531 | * 3530: "Network File System (NFS) version 4 Protocol" and section 20 | ||
532 | * of RFC 5661: "Network File System (NFS) Version 4 Minor Version 1 | ||
533 | * Protocol". | ||
534 | */ | ||
535 | |||
536 | static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr, | ||
537 | void *__unused) | ||
390 | { | 538 | { |
391 | return 0; | 539 | return 0; |
392 | } | 540 | } |
393 | 541 | ||
394 | static int | 542 | /* |
395 | nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p, | 543 | * 20.2. Operation 4: CB_RECALL - Recall a Delegation |
396 | struct nfsd4_cb_sequence *seq) | 544 | */ |
545 | static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, | ||
546 | struct xdr_stream *xdr, | ||
547 | struct nfsd4_callback *cb) | ||
397 | { | 548 | { |
398 | struct xdr_stream xdr; | ||
399 | struct nfs4_cb_compound_hdr hdr; | 549 | struct nfs4_cb_compound_hdr hdr; |
550 | enum nfsstat4 nfserr; | ||
400 | int status; | 551 | int status; |
401 | 552 | ||
402 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 553 | status = decode_cb_compound4res(xdr, &hdr); |
403 | status = decode_cb_compound_hdr(&xdr, &hdr); | 554 | if (unlikely(status)) |
404 | if (status) | ||
405 | goto out; | 555 | goto out; |
406 | if (seq) { | 556 | |
407 | status = decode_cb_sequence(&xdr, seq, rqstp); | 557 | if (cb != NULL) { |
408 | if (status) | 558 | status = decode_cb_sequence4res(xdr, cb); |
559 | if (unlikely(status)) | ||
409 | goto out; | 560 | goto out; |
410 | } | 561 | } |
411 | status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); | 562 | |
563 | status = decode_cb_op_status(xdr, OP_CB_RECALL, &nfserr); | ||
564 | if (unlikely(status)) | ||
565 | goto out; | ||
566 | if (unlikely(nfserr != NFS4_OK)) | ||
567 | status = nfs_cb_stat_to_errno(nfserr); | ||
412 | out: | 568 | out: |
413 | return status; | 569 | return status; |
414 | } | 570 | } |
@@ -416,23 +572,23 @@ out: | |||
416 | /* | 572 | /* |
417 | * RPC procedure tables | 573 | * RPC procedure tables |
418 | */ | 574 | */ |
419 | #define PROC(proc, call, argtype, restype) \ | 575 | #define PROC(proc, call, argtype, restype) \ |
420 | [NFSPROC4_CLNT_##proc] = { \ | 576 | [NFSPROC4_CLNT_##proc] = { \ |
421 | .p_proc = NFSPROC4_CB_##call, \ | 577 | .p_proc = NFSPROC4_CB_##call, \ |
422 | .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \ | 578 | .p_encode = (kxdreproc_t)nfs4_xdr_enc_##argtype, \ |
423 | .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \ | 579 | .p_decode = (kxdrdproc_t)nfs4_xdr_dec_##restype, \ |
424 | .p_arglen = NFS4_##argtype##_sz, \ | 580 | .p_arglen = NFS4_enc_##argtype##_sz, \ |
425 | .p_replen = NFS4_##restype##_sz, \ | 581 | .p_replen = NFS4_dec_##restype##_sz, \ |
426 | .p_statidx = NFSPROC4_CB_##call, \ | 582 | .p_statidx = NFSPROC4_CB_##call, \ |
427 | .p_name = #proc, \ | 583 | .p_name = #proc, \ |
428 | } | 584 | } |
429 | 585 | ||
430 | static struct rpc_procinfo nfs4_cb_procedures[] = { | 586 | static struct rpc_procinfo nfs4_cb_procedures[] = { |
431 | PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null), | 587 | PROC(CB_NULL, NULL, cb_null, cb_null), |
432 | PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall), | 588 | PROC(CB_RECALL, COMPOUND, cb_recall, cb_recall), |
433 | }; | 589 | }; |
434 | 590 | ||
435 | static struct rpc_version nfs_cb_version4 = { | 591 | static struct rpc_version nfs_cb_version4 = { |
436 | /* | 592 | /* |
437 | * Note on the callback rpc program version number: despite language in rfc | 593 | * Note on the callback rpc program version number: despite language in rfc |
438 | * 5661 section 18.36.3 requiring servers to use 4 in this field, the | 594 | * 5661 section 18.36.3 requiring servers to use 4 in this field, the |
@@ -440,29 +596,29 @@ static struct rpc_version nfs_cb_version4 = { | |||
440 | * in practice that appears to be what implementations use. The section | 596 | * in practice that appears to be what implementations use. The section |
441 | * 18.36.3 language is expected to be fixed in an erratum. | 597 | * 18.36.3 language is expected to be fixed in an erratum. |
442 | */ | 598 | */ |
443 | .number = 1, | 599 | .number = 1, |
444 | .nrprocs = ARRAY_SIZE(nfs4_cb_procedures), | 600 | .nrprocs = ARRAY_SIZE(nfs4_cb_procedures), |
445 | .procs = nfs4_cb_procedures | 601 | .procs = nfs4_cb_procedures |
446 | }; | 602 | }; |
447 | 603 | ||
448 | static struct rpc_version * nfs_cb_version[] = { | 604 | static struct rpc_version *nfs_cb_version[] = { |
449 | &nfs_cb_version4, | 605 | &nfs_cb_version4, |
450 | }; | 606 | }; |
451 | 607 | ||
452 | static struct rpc_program cb_program; | 608 | static struct rpc_program cb_program; |
453 | 609 | ||
454 | static struct rpc_stat cb_stats = { | 610 | static struct rpc_stat cb_stats = { |
455 | .program = &cb_program | 611 | .program = &cb_program |
456 | }; | 612 | }; |
457 | 613 | ||
458 | #define NFS4_CALLBACK 0x40000000 | 614 | #define NFS4_CALLBACK 0x40000000 |
459 | static struct rpc_program cb_program = { | 615 | static struct rpc_program cb_program = { |
460 | .name = "nfs4_cb", | 616 | .name = "nfs4_cb", |
461 | .number = NFS4_CALLBACK, | 617 | .number = NFS4_CALLBACK, |
462 | .nrvers = ARRAY_SIZE(nfs_cb_version), | 618 | .nrvers = ARRAY_SIZE(nfs_cb_version), |
463 | .version = nfs_cb_version, | 619 | .version = nfs_cb_version, |
464 | .stats = &cb_stats, | 620 | .stats = &cb_stats, |
465 | .pipe_dir_name = "/nfsd4_cb", | 621 | .pipe_dir_name = "/nfsd4_cb", |
466 | }; | 622 | }; |
467 | 623 | ||
468 | static int max_cb_time(void) | 624 | static int max_cb_time(void) |
@@ -470,33 +626,40 @@ static int max_cb_time(void) | |||
470 | return max(nfsd4_lease/10, (time_t)1) * HZ; | 626 | return max(nfsd4_lease/10, (time_t)1) * HZ; |
471 | } | 627 | } |
472 | 628 | ||
473 | /* Reference counting, callback cleanup, etc., all look racy as heck. | ||
474 | * And why is cl_cb_set an atomic? */ | ||
475 | 629 | ||
476 | int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb) | 630 | static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) |
477 | { | 631 | { |
478 | struct rpc_timeout timeparms = { | 632 | struct rpc_timeout timeparms = { |
479 | .to_initval = max_cb_time(), | 633 | .to_initval = max_cb_time(), |
480 | .to_retries = 0, | 634 | .to_retries = 0, |
481 | }; | 635 | }; |
482 | struct rpc_create_args args = { | 636 | struct rpc_create_args args = { |
483 | .protocol = XPRT_TRANSPORT_TCP, | 637 | .net = &init_net, |
484 | .address = (struct sockaddr *) &cb->cb_addr, | 638 | .address = (struct sockaddr *) &conn->cb_addr, |
485 | .addrsize = cb->cb_addrlen, | 639 | .addrsize = conn->cb_addrlen, |
640 | .saddress = (struct sockaddr *) &conn->cb_saddr, | ||
486 | .timeout = &timeparms, | 641 | .timeout = &timeparms, |
487 | .program = &cb_program, | 642 | .program = &cb_program, |
488 | .prognumber = cb->cb_prog, | ||
489 | .version = 0, | 643 | .version = 0, |
490 | .authflavor = clp->cl_flavor, | 644 | .authflavor = clp->cl_flavor, |
491 | .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), | 645 | .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), |
492 | .client_name = clp->cl_principal, | ||
493 | }; | 646 | }; |
494 | struct rpc_clnt *client; | 647 | struct rpc_clnt *client; |
495 | 648 | ||
496 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 649 | if (clp->cl_minorversion == 0) { |
497 | return -EINVAL; | 650 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) |
498 | if (cb->cb_minorversion) { | 651 | return -EINVAL; |
499 | args.bc_xprt = cb->cb_xprt; | 652 | args.client_name = clp->cl_principal; |
653 | args.prognumber = conn->cb_prog, | ||
654 | args.protocol = XPRT_TRANSPORT_TCP; | ||
655 | clp->cl_cb_ident = conn->cb_ident; | ||
656 | } else { | ||
657 | if (!conn->cb_xprt) | ||
658 | return -EINVAL; | ||
659 | clp->cl_cb_conn.cb_xprt = conn->cb_xprt; | ||
660 | clp->cl_cb_session = ses; | ||
661 | args.bc_xprt = conn->cb_xprt; | ||
662 | args.prognumber = clp->cl_cb_session->se_cb_prog; | ||
500 | args.protocol = XPRT_TRANSPORT_BC_TCP; | 663 | args.protocol = XPRT_TRANSPORT_BC_TCP; |
501 | } | 664 | } |
502 | /* Create RPC client */ | 665 | /* Create RPC client */ |
@@ -506,7 +669,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb) | |||
506 | PTR_ERR(client)); | 669 | PTR_ERR(client)); |
507 | return PTR_ERR(client); | 670 | return PTR_ERR(client); |
508 | } | 671 | } |
509 | nfsd4_set_callback_client(clp, client); | 672 | clp->cl_cb_client = client; |
510 | return 0; | 673 | return 0; |
511 | 674 | ||
512 | } | 675 | } |
@@ -517,17 +680,25 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason) | |||
517 | (int)clp->cl_name.len, clp->cl_name.data, reason); | 680 | (int)clp->cl_name.len, clp->cl_name.data, reason); |
518 | } | 681 | } |
519 | 682 | ||
683 | static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) | ||
684 | { | ||
685 | clp->cl_cb_state = NFSD4_CB_DOWN; | ||
686 | warn_no_callback_path(clp, reason); | ||
687 | } | ||
688 | |||
520 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) | 689 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) |
521 | { | 690 | { |
522 | struct nfs4_client *clp = calldata; | 691 | struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); |
523 | 692 | ||
524 | if (task->tk_status) | 693 | if (task->tk_status) |
525 | warn_no_callback_path(clp, task->tk_status); | 694 | nfsd4_mark_cb_down(clp, task->tk_status); |
526 | else | 695 | else |
527 | atomic_set(&clp->cl_cb_set, 1); | 696 | clp->cl_cb_state = NFSD4_CB_UP; |
528 | } | 697 | } |
529 | 698 | ||
530 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { | 699 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { |
700 | /* XXX: release method to ensure we set the cb channel down if | ||
701 | * necessary on early failure? */ | ||
531 | .rpc_call_done = nfsd4_cb_probe_done, | 702 | .rpc_call_done = nfsd4_cb_probe_done, |
532 | }; | 703 | }; |
533 | 704 | ||
@@ -543,38 +714,54 @@ int set_callback_cred(void) | |||
543 | return 0; | 714 | return 0; |
544 | } | 715 | } |
545 | 716 | ||
717 | static struct workqueue_struct *callback_wq; | ||
546 | 718 | ||
547 | void do_probe_callback(struct nfs4_client *clp) | 719 | static void run_nfsd4_cb(struct nfsd4_callback *cb) |
548 | { | 720 | { |
549 | struct rpc_message msg = { | 721 | queue_work(callback_wq, &cb->cb_work); |
550 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 722 | } |
551 | .rpc_argp = clp, | 723 | |
552 | .rpc_cred = callback_cred | 724 | static void do_probe_callback(struct nfs4_client *clp) |
553 | }; | 725 | { |
554 | int status; | 726 | struct nfsd4_callback *cb = &clp->cl_cb_null; |
727 | |||
728 | cb->cb_op = NULL; | ||
729 | cb->cb_clp = clp; | ||
730 | |||
731 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; | ||
732 | cb->cb_msg.rpc_argp = NULL; | ||
733 | cb->cb_msg.rpc_resp = NULL; | ||
734 | cb->cb_msg.rpc_cred = callback_cred; | ||
555 | 735 | ||
556 | status = rpc_call_async(clp->cl_cb_client, &msg, | 736 | cb->cb_ops = &nfsd4_cb_probe_ops; |
557 | RPC_TASK_SOFT | RPC_TASK_SOFTCONN, | 737 | |
558 | &nfsd4_cb_probe_ops, (void *)clp); | 738 | run_nfsd4_cb(cb); |
559 | if (status) | ||
560 | warn_no_callback_path(clp, status); | ||
561 | } | 739 | } |
562 | 740 | ||
563 | /* | 741 | /* |
564 | * Set up the callback client and put a NFSPROC4_CB_NULL on the wire... | 742 | * Poke the callback thread to process any updates to the callback |
743 | * parameters, and send a null probe. | ||
565 | */ | 744 | */ |
566 | void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb) | 745 | void nfsd4_probe_callback(struct nfs4_client *clp) |
567 | { | 746 | { |
568 | int status; | 747 | /* XXX: atomicity? Also, should we be using cl_cb_flags? */ |
748 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; | ||
749 | set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); | ||
750 | do_probe_callback(clp); | ||
751 | } | ||
569 | 752 | ||
570 | BUG_ON(atomic_read(&clp->cl_cb_set)); | 753 | void nfsd4_probe_callback_sync(struct nfs4_client *clp) |
754 | { | ||
755 | nfsd4_probe_callback(clp); | ||
756 | flush_workqueue(callback_wq); | ||
757 | } | ||
571 | 758 | ||
572 | status = setup_callback_client(clp, cb); | 759 | void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) |
573 | if (status) { | 760 | { |
574 | warn_no_callback_path(clp, status); | 761 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
575 | return; | 762 | spin_lock(&clp->cl_lock); |
576 | } | 763 | memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); |
577 | do_probe_callback(clp); | 764 | spin_unlock(&clp->cl_lock); |
578 | } | 765 | } |
579 | 766 | ||
580 | /* | 767 | /* |
@@ -582,33 +769,14 @@ void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb) | |||
582 | * If the slot is available, then mark it busy. Otherwise, set the | 769 | * If the slot is available, then mark it busy. Otherwise, set the |
583 | * thread for sleeping on the callback RPC wait queue. | 770 | * thread for sleeping on the callback RPC wait queue. |
584 | */ | 771 | */ |
585 | static int nfsd41_cb_setup_sequence(struct nfs4_client *clp, | 772 | static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task) |
586 | struct rpc_task *task) | ||
587 | { | 773 | { |
588 | struct nfs4_rpc_args *args = task->tk_msg.rpc_argp; | ||
589 | u32 *ptr = (u32 *)clp->cl_sessionid.data; | ||
590 | int status = 0; | ||
591 | |||
592 | dprintk("%s: %u:%u:%u:%u\n", __func__, | ||
593 | ptr[0], ptr[1], ptr[2], ptr[3]); | ||
594 | |||
595 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { | 774 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { |
596 | rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); | 775 | rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); |
597 | dprintk("%s slot is busy\n", __func__); | 776 | dprintk("%s slot is busy\n", __func__); |
598 | status = -EAGAIN; | 777 | return false; |
599 | goto out; | ||
600 | } | 778 | } |
601 | 779 | return true; | |
602 | /* | ||
603 | * We'll need the clp during XDR encoding and decoding, | ||
604 | * and the sequence during decoding to verify the reply | ||
605 | */ | ||
606 | args->args_seq.cbs_clp = clp; | ||
607 | task->tk_msg.rpc_resp = &args->args_seq; | ||
608 | |||
609 | out: | ||
610 | dprintk("%s status=%d\n", __func__, status); | ||
611 | return status; | ||
612 | } | 780 | } |
613 | 781 | ||
614 | /* | 782 | /* |
@@ -617,42 +785,42 @@ out: | |||
617 | */ | 785 | */ |
618 | static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | 786 | static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) |
619 | { | 787 | { |
620 | struct nfs4_delegation *dp = calldata; | 788 | struct nfsd4_callback *cb = calldata; |
789 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | ||
621 | struct nfs4_client *clp = dp->dl_client; | 790 | struct nfs4_client *clp = dp->dl_client; |
622 | struct nfs4_rpc_args *args = task->tk_msg.rpc_argp; | 791 | u32 minorversion = clp->cl_minorversion; |
623 | u32 minorversion = clp->cl_cb_conn.cb_minorversion; | ||
624 | int status = 0; | ||
625 | 792 | ||
626 | args->args_seq.cbs_minorversion = minorversion; | 793 | cb->cb_minorversion = minorversion; |
627 | if (minorversion) { | 794 | if (minorversion) { |
628 | status = nfsd41_cb_setup_sequence(clp, task); | 795 | if (!nfsd41_cb_get_slot(clp, task)) |
629 | if (status) { | ||
630 | if (status != -EAGAIN) { | ||
631 | /* terminate rpc task */ | ||
632 | task->tk_status = status; | ||
633 | task->tk_action = NULL; | ||
634 | } | ||
635 | return; | 796 | return; |
636 | } | ||
637 | } | 797 | } |
798 | spin_lock(&clp->cl_lock); | ||
799 | if (list_empty(&cb->cb_per_client)) { | ||
800 | /* This is the first call, not a restart */ | ||
801 | cb->cb_done = false; | ||
802 | list_add(&cb->cb_per_client, &clp->cl_callbacks); | ||
803 | } | ||
804 | spin_unlock(&clp->cl_lock); | ||
638 | rpc_call_start(task); | 805 | rpc_call_start(task); |
639 | } | 806 | } |
640 | 807 | ||
641 | static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | 808 | static void nfsd4_cb_done(struct rpc_task *task, void *calldata) |
642 | { | 809 | { |
643 | struct nfs4_delegation *dp = calldata; | 810 | struct nfsd4_callback *cb = calldata; |
811 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | ||
644 | struct nfs4_client *clp = dp->dl_client; | 812 | struct nfs4_client *clp = dp->dl_client; |
645 | 813 | ||
646 | dprintk("%s: minorversion=%d\n", __func__, | 814 | dprintk("%s: minorversion=%d\n", __func__, |
647 | clp->cl_cb_conn.cb_minorversion); | 815 | clp->cl_minorversion); |
648 | 816 | ||
649 | if (clp->cl_cb_conn.cb_minorversion) { | 817 | if (clp->cl_minorversion) { |
650 | /* No need for lock, access serialized in nfsd4_cb_prepare */ | 818 | /* No need for lock, access serialized in nfsd4_cb_prepare */ |
651 | ++clp->cl_cb_seq_nr; | 819 | ++clp->cl_cb_session->se_cb_seq_nr; |
652 | clear_bit(0, &clp->cl_cb_slot_busy); | 820 | clear_bit(0, &clp->cl_cb_slot_busy); |
653 | rpc_wake_up_next(&clp->cl_cb_waitq); | 821 | rpc_wake_up_next(&clp->cl_cb_waitq); |
654 | dprintk("%s: freed slot, new seqid=%d\n", __func__, | 822 | dprintk("%s: freed slot, new seqid=%d\n", __func__, |
655 | clp->cl_cb_seq_nr); | 823 | clp->cl_cb_session->se_cb_seq_nr); |
656 | 824 | ||
657 | /* We're done looking into the sequence information */ | 825 | /* We're done looking into the sequence information */ |
658 | task->tk_msg.rpc_resp = NULL; | 826 | task->tk_msg.rpc_resp = NULL; |
@@ -662,21 +830,25 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | |||
662 | 830 | ||
663 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | 831 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) |
664 | { | 832 | { |
665 | struct nfs4_delegation *dp = calldata; | 833 | struct nfsd4_callback *cb = calldata; |
834 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); | ||
666 | struct nfs4_client *clp = dp->dl_client; | 835 | struct nfs4_client *clp = dp->dl_client; |
667 | struct rpc_clnt *current_rpc_client = clp->cl_cb_client; | 836 | struct rpc_clnt *current_rpc_client = clp->cl_cb_client; |
668 | 837 | ||
669 | nfsd4_cb_done(task, calldata); | 838 | nfsd4_cb_done(task, calldata); |
670 | 839 | ||
671 | if (current_rpc_client == NULL) { | 840 | if (current_rpc_client != task->tk_client) { |
672 | /* We're shutting down; give up. */ | 841 | /* We're shutting down or changing cl_cb_client; leave |
673 | /* XXX: err, or is it ok just to fall through | 842 | * it to nfsd4_process_cb_update to restart the call if |
674 | * and rpc_restart_call? */ | 843 | * necessary. */ |
675 | return; | 844 | return; |
676 | } | 845 | } |
677 | 846 | ||
847 | if (cb->cb_done) | ||
848 | return; | ||
678 | switch (task->tk_status) { | 849 | switch (task->tk_status) { |
679 | case 0: | 850 | case 0: |
851 | cb->cb_done = true; | ||
680 | return; | 852 | return; |
681 | case -EBADHANDLE: | 853 | case -EBADHANDLE: |
682 | case -NFS4ERR_BAD_STATEID: | 854 | case -NFS4ERR_BAD_STATEID: |
@@ -685,31 +857,30 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
685 | break; | 857 | break; |
686 | default: | 858 | default: |
687 | /* Network partition? */ | 859 | /* Network partition? */ |
688 | atomic_set(&clp->cl_cb_set, 0); | 860 | nfsd4_mark_cb_down(clp, task->tk_status); |
689 | warn_no_callback_path(clp, task->tk_status); | ||
690 | if (current_rpc_client != task->tk_client) { | ||
691 | /* queue a callback on the new connection: */ | ||
692 | atomic_inc(&dp->dl_count); | ||
693 | nfsd4_cb_recall(dp); | ||
694 | return; | ||
695 | } | ||
696 | } | 861 | } |
697 | if (dp->dl_retries--) { | 862 | if (dp->dl_retries--) { |
698 | rpc_delay(task, 2*HZ); | 863 | rpc_delay(task, 2*HZ); |
699 | task->tk_status = 0; | 864 | task->tk_status = 0; |
700 | rpc_restart_call_prepare(task); | 865 | rpc_restart_call_prepare(task); |
701 | return; | 866 | return; |
702 | } else { | ||
703 | atomic_set(&clp->cl_cb_set, 0); | ||
704 | warn_no_callback_path(clp, task->tk_status); | ||
705 | } | 867 | } |
868 | nfsd4_mark_cb_down(clp, task->tk_status); | ||
869 | cb->cb_done = true; | ||
706 | } | 870 | } |
707 | 871 | ||
708 | static void nfsd4_cb_recall_release(void *calldata) | 872 | static void nfsd4_cb_recall_release(void *calldata) |
709 | { | 873 | { |
710 | struct nfs4_delegation *dp = calldata; | 874 | struct nfsd4_callback *cb = calldata; |
711 | 875 | struct nfs4_client *clp = cb->cb_clp; | |
712 | nfs4_put_delegation(dp); | 876 | struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); |
877 | |||
878 | if (cb->cb_done) { | ||
879 | spin_lock(&clp->cl_lock); | ||
880 | list_del(&cb->cb_per_client); | ||
881 | spin_unlock(&clp->cl_lock); | ||
882 | nfs4_put_delegation(dp); | ||
883 | } | ||
713 | } | 884 | } |
714 | 885 | ||
715 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | 886 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { |
@@ -718,8 +889,6 @@ static const struct rpc_call_ops nfsd4_cb_recall_ops = { | |||
718 | .rpc_release = nfsd4_cb_recall_release, | 889 | .rpc_release = nfsd4_cb_recall_release, |
719 | }; | 890 | }; |
720 | 891 | ||
721 | static struct workqueue_struct *callback_wq; | ||
722 | |||
723 | int nfsd4_create_callback_queue(void) | 892 | int nfsd4_create_callback_queue(void) |
724 | { | 893 | { |
725 | callback_wq = create_singlethread_workqueue("nfsd4_callbacks"); | 894 | callback_wq = create_singlethread_workqueue("nfsd4_callbacks"); |
@@ -734,57 +903,124 @@ void nfsd4_destroy_callback_queue(void) | |||
734 | } | 903 | } |
735 | 904 | ||
736 | /* must be called under the state lock */ | 905 | /* must be called under the state lock */ |
737 | void nfsd4_set_callback_client(struct nfs4_client *clp, struct rpc_clnt *new) | 906 | void nfsd4_shutdown_callback(struct nfs4_client *clp) |
738 | { | 907 | { |
739 | struct rpc_clnt *old = clp->cl_cb_client; | 908 | set_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags); |
740 | |||
741 | clp->cl_cb_client = new; | ||
742 | /* | 909 | /* |
743 | * After this, any work that saw the old value of cl_cb_client will | 910 | * Note this won't actually result in a null callback; |
744 | * be gone: | 911 | * instead, nfsd4_do_callback_rpc() will detect the killed |
912 | * client, destroy the rpc client, and stop: | ||
745 | */ | 913 | */ |
914 | do_probe_callback(clp); | ||
746 | flush_workqueue(callback_wq); | 915 | flush_workqueue(callback_wq); |
747 | /* So we can safely shut it down: */ | ||
748 | if (old) | ||
749 | rpc_shutdown_client(old); | ||
750 | } | 916 | } |
751 | 917 | ||
752 | /* | 918 | static void nfsd4_release_cb(struct nfsd4_callback *cb) |
753 | * called with dp->dl_count inc'ed. | ||
754 | */ | ||
755 | static void _nfsd4_cb_recall(struct nfs4_delegation *dp) | ||
756 | { | 919 | { |
757 | struct nfs4_client *clp = dp->dl_client; | 920 | if (cb->cb_ops->rpc_release) |
758 | struct rpc_clnt *clnt = clp->cl_cb_client; | 921 | cb->cb_ops->rpc_release(cb); |
759 | struct nfs4_rpc_args *args = &dp->dl_recall.cb_args; | 922 | } |
760 | struct rpc_message msg = { | ||
761 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | ||
762 | .rpc_cred = callback_cred | ||
763 | }; | ||
764 | 923 | ||
765 | if (clnt == NULL) { | 924 | /* requires cl_lock: */ |
766 | nfs4_put_delegation(dp); | 925 | static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp) |
767 | return; /* Client is shutting down; give up. */ | 926 | { |
927 | struct nfsd4_session *s; | ||
928 | struct nfsd4_conn *c; | ||
929 | |||
930 | list_for_each_entry(s, &clp->cl_sessions, se_perclnt) { | ||
931 | list_for_each_entry(c, &s->se_conns, cn_persession) { | ||
932 | if (c->cn_flags & NFS4_CDFC4_BACK) | ||
933 | return c; | ||
934 | } | ||
768 | } | 935 | } |
936 | return NULL; | ||
937 | } | ||
769 | 938 | ||
770 | args->args_op = dp; | 939 | static void nfsd4_process_cb_update(struct nfsd4_callback *cb) |
771 | msg.rpc_argp = args; | 940 | { |
772 | dp->dl_retries = 1; | 941 | struct nfs4_cb_conn conn; |
773 | rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp); | 942 | struct nfs4_client *clp = cb->cb_clp; |
943 | struct nfsd4_session *ses = NULL; | ||
944 | struct nfsd4_conn *c; | ||
945 | int err; | ||
946 | |||
947 | /* | ||
948 | * This is either an update, or the client dying; in either case, | ||
949 | * kill the old client: | ||
950 | */ | ||
951 | if (clp->cl_cb_client) { | ||
952 | rpc_shutdown_client(clp->cl_cb_client); | ||
953 | clp->cl_cb_client = NULL; | ||
954 | } | ||
955 | if (clp->cl_cb_conn.cb_xprt) { | ||
956 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); | ||
957 | clp->cl_cb_conn.cb_xprt = NULL; | ||
958 | } | ||
959 | if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags)) | ||
960 | return; | ||
961 | spin_lock(&clp->cl_lock); | ||
962 | /* | ||
963 | * Only serialized callback code is allowed to clear these | ||
964 | * flags; main nfsd code can only set them: | ||
965 | */ | ||
966 | BUG_ON(!clp->cl_cb_flags); | ||
967 | clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); | ||
968 | memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn)); | ||
969 | c = __nfsd4_find_backchannel(clp); | ||
970 | if (c) { | ||
971 | svc_xprt_get(c->cn_xprt); | ||
972 | conn.cb_xprt = c->cn_xprt; | ||
973 | ses = c->cn_session; | ||
974 | } | ||
975 | spin_unlock(&clp->cl_lock); | ||
976 | |||
977 | err = setup_callback_client(clp, &conn, ses); | ||
978 | if (err) { | ||
979 | warn_no_callback_path(clp, err); | ||
980 | return; | ||
981 | } | ||
982 | /* Yay, the callback channel's back! Restart any callbacks: */ | ||
983 | list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client) | ||
984 | run_nfsd4_cb(cb); | ||
774 | } | 985 | } |
775 | 986 | ||
776 | void nfsd4_do_callback_rpc(struct work_struct *w) | 987 | void nfsd4_do_callback_rpc(struct work_struct *w) |
777 | { | 988 | { |
778 | /* XXX: for now, just send off delegation recall. */ | 989 | struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); |
779 | /* In future, generalize to handle any sort of callback. */ | 990 | struct nfs4_client *clp = cb->cb_clp; |
780 | struct nfsd4_callback *c = container_of(w, struct nfsd4_callback, cb_work); | 991 | struct rpc_clnt *clnt; |
781 | struct nfs4_delegation *dp = container_of(c, struct nfs4_delegation, dl_recall); | ||
782 | 992 | ||
783 | _nfsd4_cb_recall(dp); | 993 | if (clp->cl_cb_flags) |
784 | } | 994 | nfsd4_process_cb_update(cb); |
785 | 995 | ||
996 | clnt = clp->cl_cb_client; | ||
997 | if (!clnt) { | ||
998 | /* Callback channel broken, or client killed; give up: */ | ||
999 | nfsd4_release_cb(cb); | ||
1000 | return; | ||
1001 | } | ||
1002 | rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, | ||
1003 | cb->cb_ops, cb); | ||
1004 | } | ||
786 | 1005 | ||
787 | void nfsd4_cb_recall(struct nfs4_delegation *dp) | 1006 | void nfsd4_cb_recall(struct nfs4_delegation *dp) |
788 | { | 1007 | { |
789 | queue_work(callback_wq, &dp->dl_recall.cb_work); | 1008 | struct nfsd4_callback *cb = &dp->dl_recall; |
1009 | struct nfs4_client *clp = dp->dl_client; | ||
1010 | |||
1011 | dp->dl_retries = 1; | ||
1012 | cb->cb_op = dp; | ||
1013 | cb->cb_clp = clp; | ||
1014 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; | ||
1015 | cb->cb_msg.rpc_argp = cb; | ||
1016 | cb->cb_msg.rpc_resp = cb; | ||
1017 | cb->cb_msg.rpc_cred = callback_cred; | ||
1018 | |||
1019 | cb->cb_ops = &nfsd4_cb_recall_ops; | ||
1020 | dp->dl_retries = 1; | ||
1021 | |||
1022 | INIT_LIST_HEAD(&cb->cb_per_client); | ||
1023 | cb->cb_done = true; | ||
1024 | |||
1025 | run_nfsd4_cb(&dp->dl_recall); | ||
790 | } | 1026 | } |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index c78dbf493424..55780a22fdbd 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 |
@@ -62,7 +63,6 @@ struct ent { | |||
62 | 63 | ||
63 | #define ENT_HASHBITS 8 | 64 | #define ENT_HASHBITS 8 |
64 | #define ENT_HASHMAX (1 << ENT_HASHBITS) | 65 | #define ENT_HASHMAX (1 << ENT_HASHBITS) |
65 | #define ENT_HASHMASK (ENT_HASHMAX - 1) | ||
66 | 66 | ||
67 | static void | 67 | static void |
68 | ent_init(struct cache_head *cnew, struct cache_head *citm) | 68 | ent_init(struct cache_head *cnew, struct cache_head *citm) |
@@ -482,109 +482,26 @@ nfsd_idmap_shutdown(void) | |||
482 | cache_unregister(&nametoid_cache); | 482 | cache_unregister(&nametoid_cache); |
483 | } | 483 | } |
484 | 484 | ||
485 | /* | ||
486 | * Deferred request handling | ||
487 | */ | ||
488 | |||
489 | struct idmap_defer_req { | ||
490 | struct cache_req req; | ||
491 | struct cache_deferred_req deferred_req; | ||
492 | wait_queue_head_t waitq; | ||
493 | atomic_t count; | ||
494 | }; | ||
495 | |||
496 | static inline void | ||
497 | put_mdr(struct idmap_defer_req *mdr) | ||
498 | { | ||
499 | if (atomic_dec_and_test(&mdr->count)) | ||
500 | kfree(mdr); | ||
501 | } | ||
502 | |||
503 | static inline void | ||
504 | get_mdr(struct idmap_defer_req *mdr) | ||
505 | { | ||
506 | atomic_inc(&mdr->count); | ||
507 | } | ||
508 | |||
509 | static void | ||
510 | idmap_revisit(struct cache_deferred_req *dreq, int toomany) | ||
511 | { | ||
512 | struct idmap_defer_req *mdr = | ||
513 | container_of(dreq, struct idmap_defer_req, deferred_req); | ||
514 | |||
515 | wake_up(&mdr->waitq); | ||
516 | put_mdr(mdr); | ||
517 | } | ||
518 | |||
519 | static struct cache_deferred_req * | ||
520 | idmap_defer(struct cache_req *req) | ||
521 | { | ||
522 | struct idmap_defer_req *mdr = | ||
523 | container_of(req, struct idmap_defer_req, req); | ||
524 | |||
525 | mdr->deferred_req.revisit = idmap_revisit; | ||
526 | get_mdr(mdr); | ||
527 | return (&mdr->deferred_req); | ||
528 | } | ||
529 | |||
530 | static inline int | ||
531 | do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key, | ||
532 | struct cache_detail *detail, struct ent **item, | ||
533 | struct idmap_defer_req *mdr) | ||
534 | { | ||
535 | *item = lookup_fn(key); | ||
536 | if (!*item) | ||
537 | return -ENOMEM; | ||
538 | return cache_check(detail, &(*item)->h, &mdr->req); | ||
539 | } | ||
540 | |||
541 | static inline int | ||
542 | do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *), | ||
543 | struct ent *key, struct cache_detail *detail, | ||
544 | struct ent **item) | ||
545 | { | ||
546 | int ret = -ENOMEM; | ||
547 | |||
548 | *item = lookup_fn(key); | ||
549 | if (!*item) | ||
550 | goto out_err; | ||
551 | ret = -ETIMEDOUT; | ||
552 | if (!test_bit(CACHE_VALID, &(*item)->h.flags) | ||
553 | || (*item)->h.expiry_time < get_seconds() | ||
554 | || detail->flush_time > (*item)->h.last_refresh) | ||
555 | goto out_put; | ||
556 | ret = -ENOENT; | ||
557 | if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) | ||
558 | goto out_put; | ||
559 | return 0; | ||
560 | out_put: | ||
561 | cache_put(&(*item)->h, detail); | ||
562 | out_err: | ||
563 | *item = NULL; | ||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | static int | 485 | static int |
568 | idmap_lookup(struct svc_rqst *rqstp, | 486 | idmap_lookup(struct svc_rqst *rqstp, |
569 | struct ent *(*lookup_fn)(struct ent *), struct ent *key, | 487 | struct ent *(*lookup_fn)(struct ent *), struct ent *key, |
570 | struct cache_detail *detail, struct ent **item) | 488 | struct cache_detail *detail, struct ent **item) |
571 | { | 489 | { |
572 | struct idmap_defer_req *mdr; | ||
573 | int ret; | 490 | int ret; |
574 | 491 | ||
575 | mdr = kzalloc(sizeof(*mdr), GFP_KERNEL); | 492 | *item = lookup_fn(key); |
576 | if (!mdr) | 493 | if (!*item) |
577 | return -ENOMEM; | 494 | return -ENOMEM; |
578 | atomic_set(&mdr->count, 1); | 495 | retry: |
579 | init_waitqueue_head(&mdr->waitq); | 496 | ret = cache_check(detail, &(*item)->h, &rqstp->rq_chandle); |
580 | mdr->req.defer = idmap_defer; | 497 | |
581 | ret = do_idmap_lookup(lookup_fn, key, detail, item, mdr); | 498 | if (ret == -ETIMEDOUT) { |
582 | if (ret == -EAGAIN) { | 499 | struct ent *prev_item = *item; |
583 | wait_event_interruptible_timeout(mdr->waitq, | 500 | *item = lookup_fn(key); |
584 | test_bit(CACHE_VALID, &(*item)->h.flags), 1 * HZ); | 501 | if (*item != prev_item) |
585 | ret = do_idmap_lookup_nowait(lookup_fn, key, detail, item); | 502 | goto retry; |
503 | cache_put(&(*item)->h, detail); | ||
586 | } | 504 | } |
587 | put_mdr(mdr); | ||
588 | return ret; | 505 | return ret; |
589 | } | 506 | } |
590 | 507 | ||
@@ -597,7 +514,7 @@ rqst_authname(struct svc_rqst *rqstp) | |||
597 | return clp->name; | 514 | return clp->name; |
598 | } | 515 | } |
599 | 516 | ||
600 | static int | 517 | static __be32 |
601 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, | 518 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, |
602 | uid_t *id) | 519 | uid_t *id) |
603 | { | 520 | { |
@@ -607,15 +524,15 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen | |||
607 | int ret; | 524 | int ret; |
608 | 525 | ||
609 | if (namelen + 1 > sizeof(key.name)) | 526 | if (namelen + 1 > sizeof(key.name)) |
610 | return -EINVAL; | 527 | return nfserr_badowner; |
611 | memcpy(key.name, name, namelen); | 528 | memcpy(key.name, name, namelen); |
612 | key.name[namelen] = '\0'; | 529 | key.name[namelen] = '\0'; |
613 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); | 530 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); |
614 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); | 531 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); |
615 | if (ret == -ENOENT) | 532 | if (ret == -ENOENT) |
616 | ret = -ESRCH; /* nfserr_badname */ | 533 | return nfserr_badowner; |
617 | if (ret) | 534 | if (ret) |
618 | return ret; | 535 | return nfserrno(ret); |
619 | *id = item->id; | 536 | *id = item->id; |
620 | cache_put(&item->h, &nametoid_cache); | 537 | cache_put(&item->h, &nametoid_cache); |
621 | return 0; | 538 | return 0; |
@@ -643,14 +560,14 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | |||
643 | return ret; | 560 | return ret; |
644 | } | 561 | } |
645 | 562 | ||
646 | int | 563 | __be32 |
647 | nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, | 564 | nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, |
648 | __u32 *id) | 565 | __u32 *id) |
649 | { | 566 | { |
650 | return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); | 567 | return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); |
651 | } | 568 | } |
652 | 569 | ||
653 | int | 570 | __be32 |
654 | nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, | 571 | nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, |
655 | __u32 *id) | 572 | __u32 *id) |
656 | { | 573 | { |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 59ec449b0c7f..3a6dbd70b34b 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -196,9 +196,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
196 | 196 | ||
197 | /* | 197 | /* |
198 | * Note: create modes (UNCHECKED,GUARDED...) are the same | 198 | * Note: create modes (UNCHECKED,GUARDED...) are the same |
199 | * in NFSv4 as in v3. | 199 | * in NFSv4 as in v3 except EXCLUSIVE4_1. |
200 | */ | 200 | */ |
201 | status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, | 201 | status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, |
202 | open->op_fname.len, &open->op_iattr, | 202 | open->op_fname.len, &open->op_iattr, |
203 | &resfh, open->op_createmode, | 203 | &resfh, open->op_createmode, |
204 | (u32 *)open->op_verf.data, | 204 | (u32 *)open->op_verf.data, |
@@ -403,7 +403,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
403 | cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; | 403 | cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; |
404 | memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, | 404 | memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, |
405 | putfh->pf_fhlen); | 405 | putfh->pf_fhlen); |
406 | return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); | 406 | return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS); |
407 | } | 407 | } |
408 | 408 | ||
409 | static __be32 | 409 | static __be32 |
@@ -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 |
@@ -758,6 +762,9 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
758 | __be32 err; | 762 | __be32 err; |
759 | 763 | ||
760 | fh_init(&resfh, NFS4_FHSIZE); | 764 | fh_init(&resfh, NFS4_FHSIZE); |
765 | err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC); | ||
766 | if (err) | ||
767 | return err; | ||
761 | err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, | 768 | err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, |
762 | secinfo->si_name, secinfo->si_namelen, | 769 | secinfo->si_name, secinfo->si_namelen, |
763 | &exp, &dentry); | 770 | &exp, &dentry); |
@@ -769,10 +776,36 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
769 | } else | 776 | } else |
770 | secinfo->si_exp = exp; | 777 | secinfo->si_exp = exp; |
771 | dput(dentry); | 778 | dput(dentry); |
779 | if (cstate->minorversion) | ||
780 | /* See rfc 5661 section 2.6.3.1.1.8 */ | ||
781 | fh_put(&cstate->current_fh); | ||
772 | return err; | 782 | return err; |
773 | } | 783 | } |
774 | 784 | ||
775 | static __be32 | 785 | static __be32 |
786 | nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
787 | struct nfsd4_secinfo_no_name *sin) | ||
788 | { | ||
789 | __be32 err; | ||
790 | |||
791 | switch (sin->sin_style) { | ||
792 | case NFS4_SECINFO_STYLE4_CURRENT_FH: | ||
793 | break; | ||
794 | case NFS4_SECINFO_STYLE4_PARENT: | ||
795 | err = nfsd4_do_lookupp(rqstp, &cstate->current_fh); | ||
796 | if (err) | ||
797 | return err; | ||
798 | break; | ||
799 | default: | ||
800 | return nfserr_inval; | ||
801 | } | ||
802 | exp_get(cstate->current_fh.fh_export); | ||
803 | sin->sin_exp = cstate->current_fh.fh_export; | ||
804 | fh_put(&cstate->current_fh); | ||
805 | return nfs_ok; | ||
806 | } | ||
807 | |||
808 | static __be32 | ||
776 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 809 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
777 | struct nfsd4_setattr *setattr) | 810 | struct nfsd4_setattr *setattr) |
778 | { | 811 | { |
@@ -954,8 +987,11 @@ typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | |||
954 | void *); | 987 | void *); |
955 | enum nfsd4_op_flags { | 988 | enum nfsd4_op_flags { |
956 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ | 989 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ |
957 | ALLOWED_ON_ABSENT_FS = 2 << 0, /* ops processed on absent fs */ | 990 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ |
958 | ALLOWED_AS_FIRST_OP = 3 << 0, /* ops reqired first in compound */ | 991 | ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */ |
992 | /* For rfc 5661 section 2.6.3.1.1: */ | ||
993 | OP_HANDLES_WRONGSEC = 1 << 3, | ||
994 | OP_IS_PUTFH_LIKE = 1 << 4, | ||
959 | }; | 995 | }; |
960 | 996 | ||
961 | struct nfsd4_operation { | 997 | struct nfsd4_operation { |
@@ -974,8 +1010,8 @@ static const char *nfsd4_op_name(unsigned opnum); | |||
974 | * Also note, enforced elsewhere: | 1010 | * Also note, enforced elsewhere: |
975 | * - SEQUENCE other than as first op results in | 1011 | * - SEQUENCE other than as first op results in |
976 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) | 1012 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) |
977 | * - BIND_CONN_TO_SESSION must be the only op in its compound | 1013 | * - BIND_CONN_TO_SESSION must be the only op in its compound. |
978 | * (Will be enforced in nfsd4_bind_conn_to_session().) | 1014 | * (Enforced in nfsd4_bind_conn_to_session().) |
979 | * - DESTROY_SESSION must be the final operation in a compound, if | 1015 | * - DESTROY_SESSION must be the final operation in a compound, if |
980 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. | 1016 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. |
981 | * (Enforced in nfsd4_destroy_session().) | 1017 | * (Enforced in nfsd4_destroy_session().) |
@@ -1001,6 +1037,44 @@ static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args) | |||
1001 | return nfs_ok; | 1037 | return nfs_ok; |
1002 | } | 1038 | } |
1003 | 1039 | ||
1040 | static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op) | ||
1041 | { | ||
1042 | return &nfsd4_ops[op->opnum]; | ||
1043 | } | ||
1044 | |||
1045 | static bool need_wrongsec_check(struct svc_rqst *rqstp) | ||
1046 | { | ||
1047 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1048 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
1049 | struct nfsd4_op *this = &argp->ops[resp->opcnt - 1]; | ||
1050 | struct nfsd4_op *next = &argp->ops[resp->opcnt]; | ||
1051 | struct nfsd4_operation *thisd; | ||
1052 | struct nfsd4_operation *nextd; | ||
1053 | |||
1054 | thisd = OPDESC(this); | ||
1055 | /* | ||
1056 | * Most ops check wronsec on our own; only the putfh-like ops | ||
1057 | * have special rules. | ||
1058 | */ | ||
1059 | if (!(thisd->op_flags & OP_IS_PUTFH_LIKE)) | ||
1060 | return false; | ||
1061 | /* | ||
1062 | * rfc 5661 2.6.3.1.1.6: don't bother erroring out a | ||
1063 | * put-filehandle operation if we're not going to use the | ||
1064 | * result: | ||
1065 | */ | ||
1066 | if (argp->opcnt == resp->opcnt) | ||
1067 | return false; | ||
1068 | |||
1069 | nextd = OPDESC(next); | ||
1070 | /* | ||
1071 | * Rest of 2.6.3.1.1: certain operations will return WRONGSEC | ||
1072 | * errors themselves as necessary; others should check for them | ||
1073 | * now: | ||
1074 | */ | ||
1075 | return !(nextd->op_flags & OP_HANDLES_WRONGSEC); | ||
1076 | } | ||
1077 | |||
1004 | /* | 1078 | /* |
1005 | * COMPOUND call. | 1079 | * COMPOUND call. |
1006 | */ | 1080 | */ |
@@ -1031,8 +1105,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1031 | resp->cstate.session = NULL; | 1105 | resp->cstate.session = NULL; |
1032 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); | 1106 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); |
1033 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); | 1107 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); |
1034 | /* Use the deferral mechanism only for NFSv4.0 compounds */ | 1108 | /* |
1035 | rqstp->rq_usedeferral = (args->minorversion == 0); | 1109 | * Don't use the deferral mechanism for NFSv4; compounds make it |
1110 | * too hard to avoid non-idempotency problems. | ||
1111 | */ | ||
1112 | rqstp->rq_usedeferral = 0; | ||
1036 | 1113 | ||
1037 | /* | 1114 | /* |
1038 | * According to RFC3010, this takes precedence over all other errors. | 1115 | * According to RFC3010, this takes precedence over all other errors. |
@@ -1075,7 +1152,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1075 | goto encode_op; | 1152 | goto encode_op; |
1076 | } | 1153 | } |
1077 | 1154 | ||
1078 | opdesc = &nfsd4_ops[op->opnum]; | 1155 | opdesc = OPDESC(op); |
1079 | 1156 | ||
1080 | if (!cstate->current_fh.fh_dentry) { | 1157 | if (!cstate->current_fh.fh_dentry) { |
1081 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { | 1158 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { |
@@ -1093,6 +1170,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1093 | else | 1170 | else |
1094 | BUG_ON(op->status == nfs_ok); | 1171 | BUG_ON(op->status == nfs_ok); |
1095 | 1172 | ||
1173 | if (!op->status && need_wrongsec_check(rqstp)) | ||
1174 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); | ||
1175 | |||
1096 | encode_op: | 1176 | encode_op: |
1097 | /* Only from SEQUENCE */ | 1177 | /* Only from SEQUENCE */ |
1098 | if (resp->cstate.status == nfserr_replay_cache) { | 1178 | if (resp->cstate.status == nfserr_replay_cache) { |
@@ -1123,10 +1203,6 @@ encode_op: | |||
1123 | 1203 | ||
1124 | nfsd4_increment_op_stats(op->opnum); | 1204 | nfsd4_increment_op_stats(op->opnum); |
1125 | } | 1205 | } |
1126 | if (!rqstp->rq_usedeferral && status == nfserr_dropit) { | ||
1127 | dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__); | ||
1128 | status = nfserr_jukebox; | ||
1129 | } | ||
1130 | 1206 | ||
1131 | resp->cstate.status = status; | 1207 | resp->cstate.status = status; |
1132 | fh_put(&resp->cstate.current_fh); | 1208 | fh_put(&resp->cstate.current_fh); |
@@ -1188,10 +1264,12 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1188 | }, | 1264 | }, |
1189 | [OP_LOOKUP] = { | 1265 | [OP_LOOKUP] = { |
1190 | .op_func = (nfsd4op_func)nfsd4_lookup, | 1266 | .op_func = (nfsd4op_func)nfsd4_lookup, |
1267 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1191 | .op_name = "OP_LOOKUP", | 1268 | .op_name = "OP_LOOKUP", |
1192 | }, | 1269 | }, |
1193 | [OP_LOOKUPP] = { | 1270 | [OP_LOOKUPP] = { |
1194 | .op_func = (nfsd4op_func)nfsd4_lookupp, | 1271 | .op_func = (nfsd4op_func)nfsd4_lookupp, |
1272 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1195 | .op_name = "OP_LOOKUPP", | 1273 | .op_name = "OP_LOOKUPP", |
1196 | }, | 1274 | }, |
1197 | [OP_NVERIFY] = { | 1275 | [OP_NVERIFY] = { |
@@ -1200,6 +1278,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1200 | }, | 1278 | }, |
1201 | [OP_OPEN] = { | 1279 | [OP_OPEN] = { |
1202 | .op_func = (nfsd4op_func)nfsd4_open, | 1280 | .op_func = (nfsd4op_func)nfsd4_open, |
1281 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1203 | .op_name = "OP_OPEN", | 1282 | .op_name = "OP_OPEN", |
1204 | }, | 1283 | }, |
1205 | [OP_OPEN_CONFIRM] = { | 1284 | [OP_OPEN_CONFIRM] = { |
@@ -1212,17 +1291,20 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1212 | }, | 1291 | }, |
1213 | [OP_PUTFH] = { | 1292 | [OP_PUTFH] = { |
1214 | .op_func = (nfsd4op_func)nfsd4_putfh, | 1293 | .op_func = (nfsd4op_func)nfsd4_putfh, |
1215 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1294 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1295 | | OP_IS_PUTFH_LIKE, | ||
1216 | .op_name = "OP_PUTFH", | 1296 | .op_name = "OP_PUTFH", |
1217 | }, | 1297 | }, |
1218 | [OP_PUTPUBFH] = { | 1298 | [OP_PUTPUBFH] = { |
1219 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1299 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1220 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1300 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1301 | | OP_IS_PUTFH_LIKE, | ||
1221 | .op_name = "OP_PUTPUBFH", | 1302 | .op_name = "OP_PUTPUBFH", |
1222 | }, | 1303 | }, |
1223 | [OP_PUTROOTFH] = { | 1304 | [OP_PUTROOTFH] = { |
1224 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1305 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1225 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1306 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1307 | | OP_IS_PUTFH_LIKE, | ||
1226 | .op_name = "OP_PUTROOTFH", | 1308 | .op_name = "OP_PUTROOTFH", |
1227 | }, | 1309 | }, |
1228 | [OP_READ] = { | 1310 | [OP_READ] = { |
@@ -1252,15 +1334,18 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1252 | }, | 1334 | }, |
1253 | [OP_RESTOREFH] = { | 1335 | [OP_RESTOREFH] = { |
1254 | .op_func = (nfsd4op_func)nfsd4_restorefh, | 1336 | .op_func = (nfsd4op_func)nfsd4_restorefh, |
1255 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, | 1337 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1338 | | OP_IS_PUTFH_LIKE, | ||
1256 | .op_name = "OP_RESTOREFH", | 1339 | .op_name = "OP_RESTOREFH", |
1257 | }, | 1340 | }, |
1258 | [OP_SAVEFH] = { | 1341 | [OP_SAVEFH] = { |
1259 | .op_func = (nfsd4op_func)nfsd4_savefh, | 1342 | .op_func = (nfsd4op_func)nfsd4_savefh, |
1343 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1260 | .op_name = "OP_SAVEFH", | 1344 | .op_name = "OP_SAVEFH", |
1261 | }, | 1345 | }, |
1262 | [OP_SECINFO] = { | 1346 | [OP_SECINFO] = { |
1263 | .op_func = (nfsd4op_func)nfsd4_secinfo, | 1347 | .op_func = (nfsd4op_func)nfsd4_secinfo, |
1348 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1264 | .op_name = "OP_SECINFO", | 1349 | .op_name = "OP_SECINFO", |
1265 | }, | 1350 | }, |
1266 | [OP_SETATTR] = { | 1351 | [OP_SETATTR] = { |
@@ -1297,6 +1382,11 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1297 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1382 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
1298 | .op_name = "OP_EXCHANGE_ID", | 1383 | .op_name = "OP_EXCHANGE_ID", |
1299 | }, | 1384 | }, |
1385 | [OP_BIND_CONN_TO_SESSION] = { | ||
1386 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | ||
1387 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | ||
1388 | .op_name = "OP_BIND_CONN_TO_SESSION", | ||
1389 | }, | ||
1300 | [OP_CREATE_SESSION] = { | 1390 | [OP_CREATE_SESSION] = { |
1301 | .op_func = (nfsd4op_func)nfsd4_create_session, | 1391 | .op_func = (nfsd4op_func)nfsd4_create_session, |
1302 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1392 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
@@ -1317,6 +1407,11 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1317 | .op_flags = ALLOWED_WITHOUT_FH, | 1407 | .op_flags = ALLOWED_WITHOUT_FH, |
1318 | .op_name = "OP_RECLAIM_COMPLETE", | 1408 | .op_name = "OP_RECLAIM_COMPLETE", |
1319 | }, | 1409 | }, |
1410 | [OP_SECINFO_NO_NAME] = { | ||
1411 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, | ||
1412 | .op_flags = OP_HANDLES_WRONGSEC, | ||
1413 | .op_name = "OP_SECINFO_NO_NAME", | ||
1414 | }, | ||
1320 | }; | 1415 | }; |
1321 | 1416 | ||
1322 | static const char *nfsd4_op_name(unsigned opnum) | 1417 | 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 cf0d2ffb3c84..e98f3c2e9492 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/file.h> | 35 | #include <linux/file.h> |
36 | #include <linux/smp_lock.h> | 36 | #include <linux/fs.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/namei.h> | 38 | #include <linux/namei.h> |
39 | #include <linux/swap.h> | 39 | #include <linux/swap.h> |
@@ -148,7 +148,7 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | |||
148 | /* hash table for nfs4_file */ | 148 | /* hash table for nfs4_file */ |
149 | #define FILE_HASH_BITS 8 | 149 | #define FILE_HASH_BITS 8 |
150 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | 150 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) |
151 | #define FILE_HASH_MASK (FILE_HASH_SIZE - 1) | 151 | |
152 | /* hash table for (open)nfs4_stateid */ | 152 | /* hash table for (open)nfs4_stateid */ |
153 | #define STATEID_HASH_BITS 10 | 153 | #define STATEID_HASH_BITS 10 |
154 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) | 154 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) |
@@ -207,7 +207,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
207 | { | 207 | { |
208 | struct nfs4_delegation *dp; | 208 | struct nfs4_delegation *dp; |
209 | struct nfs4_file *fp = stp->st_file; | 209 | struct nfs4_file *fp = stp->st_file; |
210 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; | ||
211 | 210 | ||
212 | dprintk("NFSD alloc_init_deleg\n"); | 211 | dprintk("NFSD alloc_init_deleg\n"); |
213 | /* | 212 | /* |
@@ -231,10 +230,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
231 | dp->dl_client = clp; | 230 | dp->dl_client = clp; |
232 | get_nfs4_file(fp); | 231 | get_nfs4_file(fp); |
233 | dp->dl_file = fp; | 232 | dp->dl_file = fp; |
234 | nfs4_file_get_access(fp, O_RDONLY); | ||
235 | dp->dl_flock = NULL; | ||
236 | dp->dl_type = type; | 233 | dp->dl_type = type; |
237 | dp->dl_ident = cb->cb_ident; | ||
238 | dp->dl_stateid.si_boot = boot_time; | 234 | dp->dl_stateid.si_boot = boot_time; |
239 | dp->dl_stateid.si_stateownerid = current_delegid++; | 235 | dp->dl_stateid.si_stateownerid = current_delegid++; |
240 | dp->dl_stateid.si_fileid = 0; | 236 | dp->dl_stateid.si_fileid = 0; |
@@ -242,8 +238,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
242 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 238 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
243 | dp->dl_time = 0; | 239 | dp->dl_time = 0; |
244 | atomic_set(&dp->dl_count, 1); | 240 | atomic_set(&dp->dl_count, 1); |
245 | list_add(&dp->dl_perfile, &fp->fi_delegations); | ||
246 | list_add(&dp->dl_perclnt, &clp->cl_delegations); | ||
247 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); | 241 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); |
248 | return dp; | 242 | return dp; |
249 | } | 243 | } |
@@ -259,32 +253,26 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
259 | } | 253 | } |
260 | } | 254 | } |
261 | 255 | ||
262 | /* Remove the associated file_lock first, then remove the delegation. | 256 | static void nfs4_put_deleg_lease(struct nfs4_file *fp) |
263 | * lease_modify() is called to remove the FS_LEASE file_lock from | ||
264 | * the i_flock list, eventually calling nfsd's lock_manager | ||
265 | * fl_release_callback. | ||
266 | */ | ||
267 | static void | ||
268 | nfs4_close_delegation(struct nfs4_delegation *dp) | ||
269 | { | 257 | { |
270 | struct file *filp = find_readable_file(dp->dl_file); | 258 | if (atomic_dec_and_test(&fp->fi_delegees)) { |
271 | 259 | vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); | |
272 | dprintk("NFSD: close_delegation dp %p\n",dp); | 260 | fp->fi_lease = NULL; |
273 | if (dp->dl_flock) | 261 | fput(fp->fi_deleg_file); |
274 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); | 262 | fp->fi_deleg_file = NULL; |
275 | nfs4_file_put_access(dp->dl_file, O_RDONLY); | 263 | } |
276 | } | 264 | } |
277 | 265 | ||
278 | /* Called under the state lock. */ | 266 | /* Called under the state lock. */ |
279 | static void | 267 | static void |
280 | unhash_delegation(struct nfs4_delegation *dp) | 268 | unhash_delegation(struct nfs4_delegation *dp) |
281 | { | 269 | { |
282 | list_del_init(&dp->dl_perfile); | ||
283 | list_del_init(&dp->dl_perclnt); | 270 | list_del_init(&dp->dl_perclnt); |
284 | spin_lock(&recall_lock); | 271 | spin_lock(&recall_lock); |
272 | list_del_init(&dp->dl_perfile); | ||
285 | list_del_init(&dp->dl_recall_lru); | 273 | list_del_init(&dp->dl_recall_lru); |
286 | spin_unlock(&recall_lock); | 274 | spin_unlock(&recall_lock); |
287 | nfs4_close_delegation(dp); | 275 | nfs4_put_deleg_lease(dp->dl_file); |
288 | nfs4_put_delegation(dp); | 276 | nfs4_put_delegation(dp); |
289 | } | 277 | } |
290 | 278 | ||
@@ -329,64 +317,6 @@ static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | |||
329 | static struct list_head client_lru; | 317 | static struct list_head client_lru; |
330 | static struct list_head close_lru; | 318 | static struct list_head close_lru; |
331 | 319 | ||
332 | static void unhash_generic_stateid(struct nfs4_stateid *stp) | ||
333 | { | ||
334 | list_del(&stp->st_hash); | ||
335 | list_del(&stp->st_perfile); | ||
336 | list_del(&stp->st_perstateowner); | ||
337 | } | ||
338 | |||
339 | static void free_generic_stateid(struct nfs4_stateid *stp) | ||
340 | { | ||
341 | put_nfs4_file(stp->st_file); | ||
342 | kmem_cache_free(stateid_slab, stp); | ||
343 | } | ||
344 | |||
345 | static void release_lock_stateid(struct nfs4_stateid *stp) | ||
346 | { | ||
347 | struct file *file; | ||
348 | |||
349 | unhash_generic_stateid(stp); | ||
350 | file = find_any_file(stp->st_file); | ||
351 | if (file) | ||
352 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
353 | free_generic_stateid(stp); | ||
354 | } | ||
355 | |||
356 | static void unhash_lockowner(struct nfs4_stateowner *sop) | ||
357 | { | ||
358 | struct nfs4_stateid *stp; | ||
359 | |||
360 | list_del(&sop->so_idhash); | ||
361 | list_del(&sop->so_strhash); | ||
362 | list_del(&sop->so_perstateid); | ||
363 | while (!list_empty(&sop->so_stateids)) { | ||
364 | stp = list_first_entry(&sop->so_stateids, | ||
365 | struct nfs4_stateid, st_perstateowner); | ||
366 | release_lock_stateid(stp); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | static void release_lockowner(struct nfs4_stateowner *sop) | ||
371 | { | ||
372 | unhash_lockowner(sop); | ||
373 | nfs4_put_stateowner(sop); | ||
374 | } | ||
375 | |||
376 | static void | ||
377 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | ||
378 | { | ||
379 | struct nfs4_stateowner *lock_sop; | ||
380 | |||
381 | while (!list_empty(&open_stp->st_lockowners)) { | ||
382 | lock_sop = list_entry(open_stp->st_lockowners.next, | ||
383 | struct nfs4_stateowner, so_perstateid); | ||
384 | /* list_del(&open_stp->st_lockowners); */ | ||
385 | BUG_ON(lock_sop->so_is_open_owner); | ||
386 | release_lockowner(lock_sop); | ||
387 | } | ||
388 | } | ||
389 | |||
390 | /* | 320 | /* |
391 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | 321 | * We store the NONE, READ, WRITE, and BOTH bits separately in the |
392 | * st_{access,deny}_bmap field of the stateid, in order to track not | 322 | * st_{access,deny}_bmap field of the stateid, in order to track not |
@@ -459,13 +389,74 @@ static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | |||
459 | return nfs4_access_to_omode(access); | 389 | return nfs4_access_to_omode(access); |
460 | } | 390 | } |
461 | 391 | ||
462 | static void release_open_stateid(struct nfs4_stateid *stp) | 392 | static void unhash_generic_stateid(struct nfs4_stateid *stp) |
393 | { | ||
394 | list_del(&stp->st_hash); | ||
395 | list_del(&stp->st_perfile); | ||
396 | list_del(&stp->st_perstateowner); | ||
397 | } | ||
398 | |||
399 | static void free_generic_stateid(struct nfs4_stateid *stp) | ||
463 | { | 400 | { |
464 | int oflag = nfs4_access_bmap_to_omode(stp); | 401 | int oflag; |
402 | |||
403 | if (stp->st_access_bmap) { | ||
404 | oflag = nfs4_access_bmap_to_omode(stp); | ||
405 | nfs4_file_put_access(stp->st_file, oflag); | ||
406 | } | ||
407 | put_nfs4_file(stp->st_file); | ||
408 | kmem_cache_free(stateid_slab, stp); | ||
409 | } | ||
410 | |||
411 | static void release_lock_stateid(struct nfs4_stateid *stp) | ||
412 | { | ||
413 | struct file *file; | ||
465 | 414 | ||
466 | unhash_generic_stateid(stp); | 415 | unhash_generic_stateid(stp); |
416 | file = find_any_file(stp->st_file); | ||
417 | if (file) | ||
418 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
419 | free_generic_stateid(stp); | ||
420 | } | ||
421 | |||
422 | static void unhash_lockowner(struct nfs4_stateowner *sop) | ||
423 | { | ||
424 | struct nfs4_stateid *stp; | ||
425 | |||
426 | list_del(&sop->so_idhash); | ||
427 | list_del(&sop->so_strhash); | ||
428 | list_del(&sop->so_perstateid); | ||
429 | while (!list_empty(&sop->so_stateids)) { | ||
430 | stp = list_first_entry(&sop->so_stateids, | ||
431 | struct nfs4_stateid, st_perstateowner); | ||
432 | release_lock_stateid(stp); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | static void release_lockowner(struct nfs4_stateowner *sop) | ||
437 | { | ||
438 | unhash_lockowner(sop); | ||
439 | nfs4_put_stateowner(sop); | ||
440 | } | ||
441 | |||
442 | static void | ||
443 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | ||
444 | { | ||
445 | struct nfs4_stateowner *lock_sop; | ||
446 | |||
447 | while (!list_empty(&open_stp->st_lockowners)) { | ||
448 | lock_sop = list_entry(open_stp->st_lockowners.next, | ||
449 | struct nfs4_stateowner, so_perstateid); | ||
450 | /* list_del(&open_stp->st_lockowners); */ | ||
451 | BUG_ON(lock_sop->so_is_open_owner); | ||
452 | release_lockowner(lock_sop); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static void release_open_stateid(struct nfs4_stateid *stp) | ||
457 | { | ||
458 | unhash_generic_stateid(stp); | ||
467 | release_stateid_lockowners(stp); | 459 | release_stateid_lockowners(stp); |
468 | nfs4_file_put_access(stp->st_file, oflag); | ||
469 | free_generic_stateid(stp); | 460 | free_generic_stateid(stp); |
470 | } | 461 | } |
471 | 462 | ||
@@ -535,171 +526,279 @@ gen_sessionid(struct nfsd4_session *ses) | |||
535 | */ | 526 | */ |
536 | #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) | 527 | #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) |
537 | 528 | ||
529 | static void | ||
530 | free_session_slots(struct nfsd4_session *ses) | ||
531 | { | ||
532 | int i; | ||
533 | |||
534 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) | ||
535 | kfree(ses->se_slots[i]); | ||
536 | } | ||
537 | |||
538 | /* | 538 | /* |
539 | * Give the client the number of ca_maxresponsesize_cached slots it | 539 | * We don't actually need to cache the rpc and session headers, so we |
540 | * requests, of size bounded by NFSD_SLOT_CACHE_SIZE, | 540 | * can allocate a little less for each slot: |
541 | * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more | 541 | */ |
542 | * than NFSD_MAX_SLOTS_PER_SESSION. | 542 | static inline int slot_bytes(struct nfsd4_channel_attrs *ca) |
543 | * | 543 | { |
544 | * If we run out of reserved DRC memory we should (up to a point) | 544 | return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; |
545 | } | ||
546 | |||
547 | static int nfsd4_sanitize_slot_size(u32 size) | ||
548 | { | ||
549 | size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */ | ||
550 | size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE); | ||
551 | |||
552 | return size; | ||
553 | } | ||
554 | |||
555 | /* | ||
556 | * XXX: If we run out of reserved DRC memory we could (up to a point) | ||
545 | * re-negotiate active sessions and reduce their slot usage to make | 557 | * re-negotiate active sessions and reduce their slot usage to make |
546 | * rooom for new connections. For now we just fail the create session. | 558 | * rooom for new connections. For now we just fail the create session. |
547 | */ | 559 | */ |
548 | static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) | 560 | static int nfsd4_get_drc_mem(int slotsize, u32 num) |
549 | { | 561 | { |
550 | int mem, size = fchan->maxresp_cached; | 562 | int avail; |
551 | 563 | ||
552 | if (fchan->maxreqs < 1) | 564 | num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION); |
553 | return nfserr_inval; | ||
554 | 565 | ||
555 | if (size < NFSD_MIN_HDR_SEQ_SZ) | 566 | spin_lock(&nfsd_drc_lock); |
556 | size = NFSD_MIN_HDR_SEQ_SZ; | 567 | avail = min_t(int, NFSD_MAX_MEM_PER_SESSION, |
557 | size -= NFSD_MIN_HDR_SEQ_SZ; | 568 | nfsd_drc_max_mem - nfsd_drc_mem_used); |
558 | if (size > NFSD_SLOT_CACHE_SIZE) | 569 | num = min_t(int, num, avail / slotsize); |
559 | size = NFSD_SLOT_CACHE_SIZE; | 570 | nfsd_drc_mem_used += num * slotsize; |
560 | 571 | spin_unlock(&nfsd_drc_lock); | |
561 | /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */ | 572 | |
562 | mem = fchan->maxreqs * size; | 573 | return num; |
563 | if (mem > NFSD_MAX_MEM_PER_SESSION) { | 574 | } |
564 | fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size; | ||
565 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
566 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
567 | mem = fchan->maxreqs * size; | ||
568 | } | ||
569 | 575 | ||
576 | static void nfsd4_put_drc_mem(int slotsize, int num) | ||
577 | { | ||
570 | spin_lock(&nfsd_drc_lock); | 578 | spin_lock(&nfsd_drc_lock); |
571 | /* bound the total session drc memory ussage */ | 579 | nfsd_drc_mem_used -= slotsize * num; |
572 | if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) { | ||
573 | fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size; | ||
574 | mem = fchan->maxreqs * size; | ||
575 | } | ||
576 | nfsd_drc_mem_used += mem; | ||
577 | spin_unlock(&nfsd_drc_lock); | 580 | spin_unlock(&nfsd_drc_lock); |
581 | } | ||
578 | 582 | ||
579 | if (fchan->maxreqs == 0) | 583 | static struct nfsd4_session *alloc_session(int slotsize, int numslots) |
580 | return nfserr_jukebox; | 584 | { |
585 | struct nfsd4_session *new; | ||
586 | int mem, i; | ||
581 | 587 | ||
582 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; | 588 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) |
583 | return 0; | 589 | + sizeof(struct nfsd4_session) > PAGE_SIZE); |
590 | mem = numslots * sizeof(struct nfsd4_slot *); | ||
591 | |||
592 | new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); | ||
593 | if (!new) | ||
594 | return NULL; | ||
595 | /* allocate each struct nfsd4_slot and data cache in one piece */ | ||
596 | for (i = 0; i < numslots; i++) { | ||
597 | mem = sizeof(struct nfsd4_slot) + slotsize; | ||
598 | new->se_slots[i] = kzalloc(mem, GFP_KERNEL); | ||
599 | if (!new->se_slots[i]) | ||
600 | goto out_free; | ||
601 | } | ||
602 | return new; | ||
603 | out_free: | ||
604 | while (i--) | ||
605 | kfree(new->se_slots[i]); | ||
606 | kfree(new); | ||
607 | return NULL; | ||
584 | } | 608 | } |
585 | 609 | ||
586 | /* | 610 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize) |
587 | * fchan holds the client values on input, and the server values on output | ||
588 | * sv_max_mesg is the maximum payload plus one page for overhead. | ||
589 | */ | ||
590 | static int init_forechannel_attrs(struct svc_rqst *rqstp, | ||
591 | struct nfsd4_channel_attrs *session_fchan, | ||
592 | struct nfsd4_channel_attrs *fchan) | ||
593 | { | 611 | { |
594 | int status = 0; | 612 | u32 maxrpc = nfsd_serv->sv_max_mesg; |
595 | __u32 maxcount = nfsd_serv->sv_max_mesg; | ||
596 | 613 | ||
597 | /* headerpadsz set to zero in encode routine */ | 614 | new->maxreqs = numslots; |
615 | new->maxresp_cached = min_t(u32, req->maxresp_cached, | ||
616 | slotsize + NFSD_MIN_HDR_SEQ_SZ); | ||
617 | new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); | ||
618 | new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); | ||
619 | new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); | ||
620 | } | ||
598 | 621 | ||
599 | /* Use the client's max request and max response size if possible */ | 622 | static void free_conn(struct nfsd4_conn *c) |
600 | if (fchan->maxreq_sz > maxcount) | 623 | { |
601 | fchan->maxreq_sz = maxcount; | 624 | svc_xprt_put(c->cn_xprt); |
602 | session_fchan->maxreq_sz = fchan->maxreq_sz; | 625 | kfree(c); |
626 | } | ||
603 | 627 | ||
604 | if (fchan->maxresp_sz > maxcount) | 628 | static void nfsd4_conn_lost(struct svc_xpt_user *u) |
605 | fchan->maxresp_sz = maxcount; | 629 | { |
606 | session_fchan->maxresp_sz = fchan->maxresp_sz; | 630 | struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); |
631 | struct nfs4_client *clp = c->cn_session->se_client; | ||
607 | 632 | ||
608 | /* Use the client's maxops if possible */ | 633 | spin_lock(&clp->cl_lock); |
609 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 634 | if (!list_empty(&c->cn_persession)) { |
610 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 635 | list_del(&c->cn_persession); |
611 | session_fchan->maxops = fchan->maxops; | 636 | free_conn(c); |
637 | } | ||
638 | spin_unlock(&clp->cl_lock); | ||
639 | nfsd4_probe_callback(clp); | ||
640 | } | ||
612 | 641 | ||
613 | /* FIXME: Error means no more DRC pages so the server should | 642 | static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) |
614 | * recover pages from existing sessions. For now fail session | 643 | { |
615 | * creation. | 644 | struct nfsd4_conn *conn; |
616 | */ | ||
617 | status = set_forechannel_drc_size(fchan); | ||
618 | 645 | ||
619 | session_fchan->maxresp_cached = fchan->maxresp_cached; | 646 | conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); |
620 | session_fchan->maxreqs = fchan->maxreqs; | 647 | if (!conn) |
648 | return NULL; | ||
649 | svc_xprt_get(rqstp->rq_xprt); | ||
650 | conn->cn_xprt = rqstp->rq_xprt; | ||
651 | conn->cn_flags = flags; | ||
652 | INIT_LIST_HEAD(&conn->cn_xpt_user.list); | ||
653 | return conn; | ||
654 | } | ||
621 | 655 | ||
622 | dprintk("%s status %d\n", __func__, status); | 656 | static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) |
623 | return status; | 657 | { |
658 | conn->cn_session = ses; | ||
659 | list_add(&conn->cn_persession, &ses->se_conns); | ||
624 | } | 660 | } |
625 | 661 | ||
626 | static void | 662 | static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) |
627 | free_session_slots(struct nfsd4_session *ses) | ||
628 | { | 663 | { |
629 | int i; | 664 | struct nfs4_client *clp = ses->se_client; |
630 | 665 | ||
631 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) | 666 | spin_lock(&clp->cl_lock); |
632 | kfree(ses->se_slots[i]); | 667 | __nfsd4_hash_conn(conn, ses); |
668 | spin_unlock(&clp->cl_lock); | ||
633 | } | 669 | } |
634 | 670 | ||
635 | /* | 671 | static int nfsd4_register_conn(struct nfsd4_conn *conn) |
636 | * We don't actually need to cache the rpc and session headers, so we | ||
637 | * can allocate a little less for each slot: | ||
638 | */ | ||
639 | static inline int slot_bytes(struct nfsd4_channel_attrs *ca) | ||
640 | { | 672 | { |
641 | return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; | 673 | conn->cn_xpt_user.callback = nfsd4_conn_lost; |
674 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); | ||
642 | } | 675 | } |
643 | 676 | ||
644 | static int | 677 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) |
645 | alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | ||
646 | struct nfsd4_create_session *cses) | ||
647 | { | 678 | { |
648 | struct nfsd4_session *new, tmp; | 679 | struct nfsd4_conn *conn; |
649 | struct nfsd4_slot *sp; | 680 | int ret; |
650 | int idx, slotsize, cachesize, i; | ||
651 | int status; | ||
652 | 681 | ||
653 | memset(&tmp, 0, sizeof(tmp)); | 682 | conn = alloc_conn(rqstp, dir); |
683 | if (!conn) | ||
684 | return nfserr_jukebox; | ||
685 | nfsd4_hash_conn(conn, ses); | ||
686 | ret = nfsd4_register_conn(conn); | ||
687 | if (ret) | ||
688 | /* oops; xprt is already down: */ | ||
689 | nfsd4_conn_lost(&conn->cn_xpt_user); | ||
690 | return nfs_ok; | ||
691 | } | ||
654 | 692 | ||
655 | /* FIXME: For now, we just accept the client back channel attributes. */ | 693 | static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) |
656 | tmp.se_bchannel = cses->back_channel; | 694 | { |
657 | status = init_forechannel_attrs(rqstp, &tmp.se_fchannel, | 695 | u32 dir = NFS4_CDFC4_FORE; |
658 | &cses->fore_channel); | ||
659 | if (status) | ||
660 | goto out; | ||
661 | 696 | ||
662 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) | 697 | if (ses->se_flags & SESSION4_BACK_CHAN) |
663 | + sizeof(struct nfsd4_session) > PAGE_SIZE); | 698 | dir |= NFS4_CDFC4_BACK; |
664 | 699 | ||
665 | status = nfserr_jukebox; | 700 | return nfsd4_new_conn(rqstp, ses, dir); |
666 | /* allocate struct nfsd4_session and slot table pointers in one piece */ | 701 | } |
667 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); | ||
668 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | ||
669 | if (!new) | ||
670 | goto out; | ||
671 | 702 | ||
672 | memcpy(new, &tmp, sizeof(*new)); | 703 | /* must be called under client_lock */ |
704 | static void nfsd4_del_conns(struct nfsd4_session *s) | ||
705 | { | ||
706 | struct nfs4_client *clp = s->se_client; | ||
707 | struct nfsd4_conn *c; | ||
673 | 708 | ||
674 | /* allocate each struct nfsd4_slot and data cache in one piece */ | 709 | spin_lock(&clp->cl_lock); |
675 | cachesize = slot_bytes(&new->se_fchannel); | 710 | while (!list_empty(&s->se_conns)) { |
676 | for (i = 0; i < new->se_fchannel.maxreqs; i++) { | 711 | c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); |
677 | sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL); | 712 | list_del_init(&c->cn_persession); |
678 | if (!sp) | 713 | spin_unlock(&clp->cl_lock); |
679 | goto out_free; | 714 | |
680 | new->se_slots[i] = sp; | 715 | unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); |
716 | free_conn(c); | ||
717 | |||
718 | spin_lock(&clp->cl_lock); | ||
719 | } | ||
720 | spin_unlock(&clp->cl_lock); | ||
721 | } | ||
722 | |||
723 | void free_session(struct kref *kref) | ||
724 | { | ||
725 | struct nfsd4_session *ses; | ||
726 | int mem; | ||
727 | |||
728 | ses = container_of(kref, struct nfsd4_session, se_ref); | ||
729 | nfsd4_del_conns(ses); | ||
730 | spin_lock(&nfsd_drc_lock); | ||
731 | mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); | ||
732 | nfsd_drc_mem_used -= mem; | ||
733 | spin_unlock(&nfsd_drc_lock); | ||
734 | free_session_slots(ses); | ||
735 | kfree(ses); | ||
736 | } | ||
737 | |||
738 | static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) | ||
739 | { | ||
740 | struct nfsd4_session *new; | ||
741 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; | ||
742 | int numslots, slotsize; | ||
743 | int status; | ||
744 | int idx; | ||
745 | |||
746 | /* | ||
747 | * Note decreasing slot size below client's request may | ||
748 | * make it difficult for client to function correctly, whereas | ||
749 | * decreasing the number of slots will (just?) affect | ||
750 | * performance. When short on memory we therefore prefer to | ||
751 | * decrease number of slots instead of their size. | ||
752 | */ | ||
753 | slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); | ||
754 | numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); | ||
755 | if (numslots < 1) | ||
756 | return NULL; | ||
757 | |||
758 | new = alloc_session(slotsize, numslots); | ||
759 | if (!new) { | ||
760 | nfsd4_put_drc_mem(slotsize, fchan->maxreqs); | ||
761 | return NULL; | ||
681 | } | 762 | } |
763 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); | ||
682 | 764 | ||
683 | new->se_client = clp; | 765 | new->se_client = clp; |
684 | gen_sessionid(new); | 766 | gen_sessionid(new); |
685 | idx = hash_sessionid(&new->se_sessionid); | ||
686 | memcpy(clp->cl_sessionid.data, new->se_sessionid.data, | ||
687 | NFS4_MAX_SESSIONID_LEN); | ||
688 | 767 | ||
768 | INIT_LIST_HEAD(&new->se_conns); | ||
769 | |||
770 | new->se_cb_seq_nr = 1; | ||
689 | new->se_flags = cses->flags; | 771 | new->se_flags = cses->flags; |
772 | new->se_cb_prog = cses->callback_prog; | ||
690 | kref_init(&new->se_ref); | 773 | kref_init(&new->se_ref); |
774 | idx = hash_sessionid(&new->se_sessionid); | ||
691 | spin_lock(&client_lock); | 775 | spin_lock(&client_lock); |
692 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | 776 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); |
777 | spin_lock(&clp->cl_lock); | ||
693 | list_add(&new->se_perclnt, &clp->cl_sessions); | 778 | list_add(&new->se_perclnt, &clp->cl_sessions); |
779 | spin_unlock(&clp->cl_lock); | ||
694 | spin_unlock(&client_lock); | 780 | spin_unlock(&client_lock); |
695 | 781 | ||
696 | status = nfs_ok; | 782 | status = nfsd4_new_conn_from_crses(rqstp, new); |
697 | out: | 783 | /* whoops: benny points out, status is ignored! (err, or bogus) */ |
698 | return status; | 784 | if (status) { |
699 | out_free: | 785 | free_session(&new->se_ref); |
700 | free_session_slots(new); | 786 | return NULL; |
701 | kfree(new); | 787 | } |
702 | goto out; | 788 | if (cses->flags & SESSION4_BACK_CHAN) { |
789 | struct sockaddr *sa = svc_addr(rqstp); | ||
790 | /* | ||
791 | * This is a little silly; with sessions there's no real | ||
792 | * use for the callback address. Use the peer address | ||
793 | * as a reasonable default for now, but consider fixing | ||
794 | * the rpc client not to require an address in the | ||
795 | * future: | ||
796 | */ | ||
797 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); | ||
798 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | ||
799 | } | ||
800 | nfsd4_probe_callback(clp); | ||
801 | return new; | ||
703 | } | 802 | } |
704 | 803 | ||
705 | /* caller must hold client_lock */ | 804 | /* caller must hold client_lock */ |
@@ -728,22 +827,9 @@ static void | |||
728 | unhash_session(struct nfsd4_session *ses) | 827 | unhash_session(struct nfsd4_session *ses) |
729 | { | 828 | { |
730 | list_del(&ses->se_hash); | 829 | list_del(&ses->se_hash); |
830 | spin_lock(&ses->se_client->cl_lock); | ||
731 | list_del(&ses->se_perclnt); | 831 | list_del(&ses->se_perclnt); |
732 | } | 832 | spin_unlock(&ses->se_client->cl_lock); |
733 | |||
734 | void | ||
735 | free_session(struct kref *kref) | ||
736 | { | ||
737 | struct nfsd4_session *ses; | ||
738 | int mem; | ||
739 | |||
740 | ses = container_of(kref, struct nfsd4_session, se_ref); | ||
741 | spin_lock(&nfsd_drc_lock); | ||
742 | mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); | ||
743 | nfsd_drc_mem_used -= mem; | ||
744 | spin_unlock(&nfsd_drc_lock); | ||
745 | free_session_slots(ses); | ||
746 | kfree(ses); | ||
747 | } | 833 | } |
748 | 834 | ||
749 | /* must be called under the client_lock */ | 835 | /* must be called under the client_lock */ |
@@ -812,6 +898,13 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
812 | static inline void | 898 | static inline void |
813 | free_client(struct nfs4_client *clp) | 899 | free_client(struct nfs4_client *clp) |
814 | { | 900 | { |
901 | while (!list_empty(&clp->cl_sessions)) { | ||
902 | struct nfsd4_session *ses; | ||
903 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | ||
904 | se_perclnt); | ||
905 | list_del(&ses->se_perclnt); | ||
906 | nfsd4_put_session(ses); | ||
907 | } | ||
815 | if (clp->cl_cred.cr_group_info) | 908 | if (clp->cl_cred.cr_group_info) |
816 | put_group_info(clp->cl_cred.cr_group_info); | 909 | put_group_info(clp->cl_cred.cr_group_info); |
817 | kfree(clp->cl_principal); | 910 | kfree(clp->cl_principal); |
@@ -838,15 +931,14 @@ release_session_client(struct nfsd4_session *session) | |||
838 | static inline void | 931 | static inline void |
839 | unhash_client_locked(struct nfs4_client *clp) | 932 | unhash_client_locked(struct nfs4_client *clp) |
840 | { | 933 | { |
934 | struct nfsd4_session *ses; | ||
935 | |||
841 | mark_client_expired(clp); | 936 | mark_client_expired(clp); |
842 | list_del(&clp->cl_lru); | 937 | list_del(&clp->cl_lru); |
843 | while (!list_empty(&clp->cl_sessions)) { | 938 | spin_lock(&clp->cl_lock); |
844 | struct nfsd4_session *ses; | 939 | list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) |
845 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 940 | list_del_init(&ses->se_hash); |
846 | se_perclnt); | 941 | spin_unlock(&clp->cl_lock); |
847 | unhash_session(ses); | ||
848 | nfsd4_put_session(ses); | ||
849 | } | ||
850 | } | 942 | } |
851 | 943 | ||
852 | static void | 944 | static void |
@@ -860,8 +952,6 @@ expire_client(struct nfs4_client *clp) | |||
860 | spin_lock(&recall_lock); | 952 | spin_lock(&recall_lock); |
861 | while (!list_empty(&clp->cl_delegations)) { | 953 | while (!list_empty(&clp->cl_delegations)) { |
862 | dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); | 954 | dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); |
863 | dprintk("NFSD: expire client. dp %p, fp %p\n", dp, | ||
864 | dp->dl_flock); | ||
865 | list_del_init(&dp->dl_perclnt); | 955 | list_del_init(&dp->dl_perclnt); |
866 | list_move(&dp->dl_recall_lru, &reaplist); | 956 | list_move(&dp->dl_recall_lru, &reaplist); |
867 | } | 957 | } |
@@ -875,7 +965,7 @@ expire_client(struct nfs4_client *clp) | |||
875 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); | 965 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); |
876 | release_openowner(sop); | 966 | release_openowner(sop); |
877 | } | 967 | } |
878 | nfsd4_set_callback_client(clp, NULL); | 968 | nfsd4_shutdown_callback(clp); |
879 | if (clp->cl_cb_conn.cb_xprt) | 969 | if (clp->cl_cb_conn.cb_xprt) |
880 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); | 970 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); |
881 | list_del(&clp->cl_idhash); | 971 | list_del(&clp->cl_idhash); |
@@ -960,6 +1050,8 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
960 | if (clp == NULL) | 1050 | if (clp == NULL) |
961 | return NULL; | 1051 | return NULL; |
962 | 1052 | ||
1053 | INIT_LIST_HEAD(&clp->cl_sessions); | ||
1054 | |||
963 | princ = svc_gss_principal(rqstp); | 1055 | princ = svc_gss_principal(rqstp); |
964 | if (princ) { | 1056 | if (princ) { |
965 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | 1057 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); |
@@ -971,13 +1063,15 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
971 | 1063 | ||
972 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 1064 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
973 | atomic_set(&clp->cl_refcount, 0); | 1065 | atomic_set(&clp->cl_refcount, 0); |
974 | atomic_set(&clp->cl_cb_set, 0); | 1066 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
975 | INIT_LIST_HEAD(&clp->cl_idhash); | 1067 | INIT_LIST_HEAD(&clp->cl_idhash); |
976 | INIT_LIST_HEAD(&clp->cl_strhash); | 1068 | INIT_LIST_HEAD(&clp->cl_strhash); |
977 | INIT_LIST_HEAD(&clp->cl_openowners); | 1069 | INIT_LIST_HEAD(&clp->cl_openowners); |
978 | INIT_LIST_HEAD(&clp->cl_delegations); | 1070 | INIT_LIST_HEAD(&clp->cl_delegations); |
979 | INIT_LIST_HEAD(&clp->cl_sessions); | ||
980 | INIT_LIST_HEAD(&clp->cl_lru); | 1071 | INIT_LIST_HEAD(&clp->cl_lru); |
1072 | INIT_LIST_HEAD(&clp->cl_callbacks); | ||
1073 | spin_lock_init(&clp->cl_lock); | ||
1074 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); | ||
981 | clp->cl_time = get_seconds(); | 1075 | clp->cl_time = get_seconds(); |
982 | clear_bit(0, &clp->cl_cb_slot_busy); | 1076 | clear_bit(0, &clp->cl_cb_slot_busy); |
983 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1077 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
@@ -986,7 +1080,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | |||
986 | clp->cl_flavor = rqstp->rq_flavor; | 1080 | clp->cl_flavor = rqstp->rq_flavor; |
987 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | 1081 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); |
988 | gen_confirm(clp); | 1082 | gen_confirm(clp); |
989 | 1083 | clp->cl_cb_session = NULL; | |
990 | return clp; | 1084 | return clp; |
991 | } | 1085 | } |
992 | 1086 | ||
@@ -1051,54 +1145,55 @@ find_unconfirmed_client(clientid_t *clid) | |||
1051 | return NULL; | 1145 | return NULL; |
1052 | } | 1146 | } |
1053 | 1147 | ||
1054 | /* | 1148 | static bool clp_used_exchangeid(struct nfs4_client *clp) |
1055 | * Return 1 iff clp's clientid establishment method matches the use_exchange_id | ||
1056 | * parameter. Matching is based on the fact the at least one of the | ||
1057 | * EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1 | ||
1058 | * | ||
1059 | * FIXME: we need to unify the clientid namespaces for nfsv4.x | ||
1060 | * and correctly deal with client upgrade/downgrade in EXCHANGE_ID | ||
1061 | * and SET_CLIENTID{,_CONFIRM} | ||
1062 | */ | ||
1063 | static inline int | ||
1064 | match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id) | ||
1065 | { | 1149 | { |
1066 | bool has_exchange_flags = (clp->cl_exchange_flags != 0); | 1150 | return clp->cl_exchange_flags != 0; |
1067 | return use_exchange_id == has_exchange_flags; | 1151 | } |
1068 | } | ||
1069 | 1152 | ||
1070 | static struct nfs4_client * | 1153 | static struct nfs4_client * |
1071 | find_confirmed_client_by_str(const char *dname, unsigned int hashval, | 1154 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) |
1072 | bool use_exchange_id) | ||
1073 | { | 1155 | { |
1074 | struct nfs4_client *clp; | 1156 | struct nfs4_client *clp; |
1075 | 1157 | ||
1076 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | 1158 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { |
1077 | if (same_name(clp->cl_recdir, dname) && | 1159 | if (same_name(clp->cl_recdir, dname)) |
1078 | match_clientid_establishment(clp, use_exchange_id)) | ||
1079 | return clp; | 1160 | return clp; |
1080 | } | 1161 | } |
1081 | return NULL; | 1162 | return NULL; |
1082 | } | 1163 | } |
1083 | 1164 | ||
1084 | static struct nfs4_client * | 1165 | static struct nfs4_client * |
1085 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval, | 1166 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) |
1086 | bool use_exchange_id) | ||
1087 | { | 1167 | { |
1088 | struct nfs4_client *clp; | 1168 | struct nfs4_client *clp; |
1089 | 1169 | ||
1090 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | 1170 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { |
1091 | if (same_name(clp->cl_recdir, dname) && | 1171 | if (same_name(clp->cl_recdir, dname)) |
1092 | match_clientid_establishment(clp, use_exchange_id)) | ||
1093 | return clp; | 1172 | return clp; |
1094 | } | 1173 | } |
1095 | return NULL; | 1174 | return NULL; |
1096 | } | 1175 | } |
1097 | 1176 | ||
1177 | static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr) | ||
1178 | { | ||
1179 | switch (family) { | ||
1180 | case AF_INET: | ||
1181 | ((struct sockaddr_in *)sa)->sin_family = AF_INET; | ||
1182 | ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr; | ||
1183 | return; | ||
1184 | case AF_INET6: | ||
1185 | ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; | ||
1186 | ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6; | ||
1187 | return; | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1098 | static void | 1191 | static void |
1099 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) | 1192 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) |
1100 | { | 1193 | { |
1101 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; | 1194 | struct nfs4_cb_conn *conn = &clp->cl_cb_conn; |
1195 | struct sockaddr *sa = svc_addr(rqstp); | ||
1196 | u32 scopeid = rpc_get_scope_id(sa); | ||
1102 | unsigned short expected_family; | 1197 | unsigned short expected_family; |
1103 | 1198 | ||
1104 | /* Currently, we only support tcp and tcp6 for the callback channel */ | 1199 | /* Currently, we only support tcp and tcp6 for the callback channel */ |
@@ -1111,24 +1206,24 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) | |||
1111 | else | 1206 | else |
1112 | goto out_err; | 1207 | goto out_err; |
1113 | 1208 | ||
1114 | cb->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, | 1209 | conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, |
1115 | se->se_callback_addr_len, | 1210 | se->se_callback_addr_len, |
1116 | (struct sockaddr *) &cb->cb_addr, | 1211 | (struct sockaddr *)&conn->cb_addr, |
1117 | sizeof(cb->cb_addr)); | 1212 | sizeof(conn->cb_addr)); |
1118 | 1213 | ||
1119 | if (!cb->cb_addrlen || cb->cb_addr.ss_family != expected_family) | 1214 | if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) |
1120 | goto out_err; | 1215 | goto out_err; |
1121 | 1216 | ||
1122 | if (cb->cb_addr.ss_family == AF_INET6) | 1217 | if (conn->cb_addr.ss_family == AF_INET6) |
1123 | ((struct sockaddr_in6 *) &cb->cb_addr)->sin6_scope_id = scopeid; | 1218 | ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; |
1124 | 1219 | ||
1125 | cb->cb_minorversion = 0; | 1220 | conn->cb_prog = se->se_callback_prog; |
1126 | cb->cb_prog = se->se_callback_prog; | 1221 | conn->cb_ident = se->se_callback_ident; |
1127 | cb->cb_ident = se->se_callback_ident; | 1222 | rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr); |
1128 | return; | 1223 | return; |
1129 | out_err: | 1224 | out_err: |
1130 | cb->cb_addr.ss_family = AF_UNSPEC; | 1225 | conn->cb_addr.ss_family = AF_UNSPEC; |
1131 | cb->cb_addrlen = 0; | 1226 | conn->cb_addrlen = 0; |
1132 | dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " | 1227 | dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " |
1133 | "will not receive delegations\n", | 1228 | "will not receive delegations\n", |
1134 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 1229 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); |
@@ -1264,7 +1359,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1264 | case SP4_NONE: | 1359 | case SP4_NONE: |
1265 | break; | 1360 | break; |
1266 | case SP4_SSV: | 1361 | case SP4_SSV: |
1267 | return nfserr_encr_alg_unsupp; | 1362 | return nfserr_serverfault; |
1268 | default: | 1363 | default: |
1269 | BUG(); /* checked by xdr code */ | 1364 | BUG(); /* checked by xdr code */ |
1270 | case SP4_MACH_CRED: | 1365 | case SP4_MACH_CRED: |
@@ -1281,8 +1376,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1281 | nfs4_lock_state(); | 1376 | nfs4_lock_state(); |
1282 | status = nfs_ok; | 1377 | status = nfs_ok; |
1283 | 1378 | ||
1284 | conf = find_confirmed_client_by_str(dname, strhashval, true); | 1379 | conf = find_confirmed_client_by_str(dname, strhashval); |
1285 | if (conf) { | 1380 | if (conf) { |
1381 | if (!clp_used_exchangeid(conf)) { | ||
1382 | status = nfserr_clid_inuse; /* XXX: ? */ | ||
1383 | goto out; | ||
1384 | } | ||
1286 | if (!same_verf(&verf, &conf->cl_verifier)) { | 1385 | if (!same_verf(&verf, &conf->cl_verifier)) { |
1287 | /* 18.35.4 case 8 */ | 1386 | /* 18.35.4 case 8 */ |
1288 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1387 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
@@ -1323,7 +1422,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1323 | goto out; | 1422 | goto out; |
1324 | } | 1423 | } |
1325 | 1424 | ||
1326 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1425 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1327 | if (unconf) { | 1426 | if (unconf) { |
1328 | /* | 1427 | /* |
1329 | * Possible retry or client restart. Per 18.35.4 case 4, | 1428 | * Possible retry or client restart. Per 18.35.4 case 4, |
@@ -1415,9 +1514,14 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1415 | { | 1514 | { |
1416 | struct sockaddr *sa = svc_addr(rqstp); | 1515 | struct sockaddr *sa = svc_addr(rqstp); |
1417 | struct nfs4_client *conf, *unconf; | 1516 | struct nfs4_client *conf, *unconf; |
1517 | struct nfsd4_session *new; | ||
1418 | struct nfsd4_clid_slot *cs_slot = NULL; | 1518 | struct nfsd4_clid_slot *cs_slot = NULL; |
1519 | bool confirm_me = false; | ||
1419 | int status = 0; | 1520 | int status = 0; |
1420 | 1521 | ||
1522 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | ||
1523 | return nfserr_inval; | ||
1524 | |||
1421 | nfs4_lock_state(); | 1525 | nfs4_lock_state(); |
1422 | unconf = find_unconfirmed_client(&cr_ses->clientid); | 1526 | unconf = find_unconfirmed_client(&cr_ses->clientid); |
1423 | conf = find_confirmed_client(&cr_ses->clientid); | 1527 | conf = find_confirmed_client(&cr_ses->clientid); |
@@ -1438,7 +1542,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1438 | cs_slot->sl_seqid, cr_ses->seqid); | 1542 | cs_slot->sl_seqid, cr_ses->seqid); |
1439 | goto out; | 1543 | goto out; |
1440 | } | 1544 | } |
1441 | cs_slot->sl_seqid++; | ||
1442 | } else if (unconf) { | 1545 | } else if (unconf) { |
1443 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || | 1546 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || |
1444 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { | 1547 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { |
@@ -1451,25 +1554,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1451 | if (status) { | 1554 | if (status) { |
1452 | /* an unconfirmed replay returns misordered */ | 1555 | /* an unconfirmed replay returns misordered */ |
1453 | status = nfserr_seq_misordered; | 1556 | status = nfserr_seq_misordered; |
1454 | goto out_cache; | 1557 | goto out; |
1455 | } | 1558 | } |
1456 | 1559 | ||
1457 | cs_slot->sl_seqid++; /* from 0 to 1 */ | 1560 | confirm_me = true; |
1458 | move_to_confirmed(unconf); | ||
1459 | |||
1460 | if (cr_ses->flags & SESSION4_BACK_CHAN) { | ||
1461 | unconf->cl_cb_conn.cb_xprt = rqstp->rq_xprt; | ||
1462 | svc_xprt_get(rqstp->rq_xprt); | ||
1463 | rpc_copy_addr( | ||
1464 | (struct sockaddr *)&unconf->cl_cb_conn.cb_addr, | ||
1465 | sa); | ||
1466 | unconf->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | ||
1467 | unconf->cl_cb_conn.cb_minorversion = | ||
1468 | cstate->minorversion; | ||
1469 | unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; | ||
1470 | unconf->cl_cb_seq_nr = 1; | ||
1471 | nfsd4_probe_callback(unconf, &unconf->cl_cb_conn); | ||
1472 | } | ||
1473 | conf = unconf; | 1561 | conf = unconf; |
1474 | } else { | 1562 | } else { |
1475 | status = nfserr_stale_clientid; | 1563 | status = nfserr_stale_clientid; |
@@ -1477,22 +1565,32 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1477 | } | 1565 | } |
1478 | 1566 | ||
1479 | /* | 1567 | /* |
1568 | * XXX: we should probably set this at creation time, and check | ||
1569 | * for consistent minorversion use throughout: | ||
1570 | */ | ||
1571 | conf->cl_minorversion = 1; | ||
1572 | /* | ||
1480 | * We do not support RDMA or persistent sessions | 1573 | * We do not support RDMA or persistent sessions |
1481 | */ | 1574 | */ |
1482 | cr_ses->flags &= ~SESSION4_PERSIST; | 1575 | cr_ses->flags &= ~SESSION4_PERSIST; |
1483 | cr_ses->flags &= ~SESSION4_RDMA; | 1576 | cr_ses->flags &= ~SESSION4_RDMA; |
1484 | 1577 | ||
1485 | status = alloc_init_session(rqstp, conf, cr_ses); | 1578 | status = nfserr_jukebox; |
1486 | if (status) | 1579 | new = alloc_init_session(rqstp, conf, cr_ses); |
1580 | if (!new) | ||
1487 | goto out; | 1581 | goto out; |
1488 | 1582 | status = nfs_ok; | |
1489 | memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data, | 1583 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, |
1490 | NFS4_MAX_SESSIONID_LEN); | 1584 | NFS4_MAX_SESSIONID_LEN); |
1585 | memcpy(&cr_ses->fore_channel, &new->se_fchannel, | ||
1586 | sizeof(struct nfsd4_channel_attrs)); | ||
1587 | cs_slot->sl_seqid++; | ||
1491 | cr_ses->seqid = cs_slot->sl_seqid; | 1588 | cr_ses->seqid = cs_slot->sl_seqid; |
1492 | 1589 | ||
1493 | out_cache: | ||
1494 | /* cache solo and embedded create sessions under the state lock */ | 1590 | /* cache solo and embedded create sessions under the state lock */ |
1495 | nfsd4_cache_create_session(cr_ses, cs_slot, status); | 1591 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
1592 | if (confirm_me) | ||
1593 | move_to_confirmed(conf); | ||
1496 | out: | 1594 | out: |
1497 | nfs4_unlock_state(); | 1595 | nfs4_unlock_state(); |
1498 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1596 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -1507,6 +1605,46 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) | |||
1507 | return argp->opcnt == resp->opcnt; | 1605 | return argp->opcnt == resp->opcnt; |
1508 | } | 1606 | } |
1509 | 1607 | ||
1608 | static __be32 nfsd4_map_bcts_dir(u32 *dir) | ||
1609 | { | ||
1610 | switch (*dir) { | ||
1611 | case NFS4_CDFC4_FORE: | ||
1612 | case NFS4_CDFC4_BACK: | ||
1613 | return nfs_ok; | ||
1614 | case NFS4_CDFC4_FORE_OR_BOTH: | ||
1615 | case NFS4_CDFC4_BACK_OR_BOTH: | ||
1616 | *dir = NFS4_CDFC4_BOTH; | ||
1617 | return nfs_ok; | ||
1618 | }; | ||
1619 | return nfserr_inval; | ||
1620 | } | ||
1621 | |||
1622 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | ||
1623 | struct nfsd4_compound_state *cstate, | ||
1624 | struct nfsd4_bind_conn_to_session *bcts) | ||
1625 | { | ||
1626 | __be32 status; | ||
1627 | |||
1628 | if (!nfsd4_last_compound_op(rqstp)) | ||
1629 | return nfserr_not_only_op; | ||
1630 | spin_lock(&client_lock); | ||
1631 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); | ||
1632 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires | ||
1633 | * client_lock iself: */ | ||
1634 | if (cstate->session) { | ||
1635 | nfsd4_get_session(cstate->session); | ||
1636 | atomic_inc(&cstate->session->se_client->cl_refcount); | ||
1637 | } | ||
1638 | spin_unlock(&client_lock); | ||
1639 | if (!cstate->session) | ||
1640 | return nfserr_badsession; | ||
1641 | |||
1642 | status = nfsd4_map_bcts_dir(&bcts->dir); | ||
1643 | if (!status) | ||
1644 | nfsd4_new_conn(rqstp, cstate->session, bcts->dir); | ||
1645 | return status; | ||
1646 | } | ||
1647 | |||
1510 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) | 1648 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) |
1511 | { | 1649 | { |
1512 | if (!session) | 1650 | if (!session) |
@@ -1545,9 +1683,11 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1545 | spin_unlock(&client_lock); | 1683 | spin_unlock(&client_lock); |
1546 | 1684 | ||
1547 | nfs4_lock_state(); | 1685 | nfs4_lock_state(); |
1548 | /* wait for callbacks */ | 1686 | nfsd4_probe_callback_sync(ses->se_client); |
1549 | nfsd4_set_callback_client(ses->se_client, NULL); | ||
1550 | nfs4_unlock_state(); | 1687 | nfs4_unlock_state(); |
1688 | |||
1689 | nfsd4_del_conns(ses); | ||
1690 | |||
1551 | nfsd4_put_session(ses); | 1691 | nfsd4_put_session(ses); |
1552 | status = nfs_ok; | 1692 | status = nfs_ok; |
1553 | out: | 1693 | out: |
@@ -1555,6 +1695,47 @@ out: | |||
1555 | return status; | 1695 | return status; |
1556 | } | 1696 | } |
1557 | 1697 | ||
1698 | static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) | ||
1699 | { | ||
1700 | struct nfsd4_conn *c; | ||
1701 | |||
1702 | list_for_each_entry(c, &s->se_conns, cn_persession) { | ||
1703 | if (c->cn_xprt == xpt) { | ||
1704 | return c; | ||
1705 | } | ||
1706 | } | ||
1707 | return NULL; | ||
1708 | } | ||
1709 | |||
1710 | static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) | ||
1711 | { | ||
1712 | struct nfs4_client *clp = ses->se_client; | ||
1713 | struct nfsd4_conn *c; | ||
1714 | int ret; | ||
1715 | |||
1716 | spin_lock(&clp->cl_lock); | ||
1717 | c = __nfsd4_find_conn(new->cn_xprt, ses); | ||
1718 | if (c) { | ||
1719 | spin_unlock(&clp->cl_lock); | ||
1720 | free_conn(new); | ||
1721 | return; | ||
1722 | } | ||
1723 | __nfsd4_hash_conn(new, ses); | ||
1724 | spin_unlock(&clp->cl_lock); | ||
1725 | ret = nfsd4_register_conn(new); | ||
1726 | if (ret) | ||
1727 | /* oops; xprt is already down: */ | ||
1728 | nfsd4_conn_lost(&new->cn_xpt_user); | ||
1729 | return; | ||
1730 | } | ||
1731 | |||
1732 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) | ||
1733 | { | ||
1734 | struct nfsd4_compoundargs *args = rqstp->rq_argp; | ||
1735 | |||
1736 | return args->opcnt > session->se_fchannel.maxops; | ||
1737 | } | ||
1738 | |||
1558 | __be32 | 1739 | __be32 |
1559 | nfsd4_sequence(struct svc_rqst *rqstp, | 1740 | nfsd4_sequence(struct svc_rqst *rqstp, |
1560 | struct nfsd4_compound_state *cstate, | 1741 | struct nfsd4_compound_state *cstate, |
@@ -1563,17 +1744,30 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1563 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 1744 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
1564 | struct nfsd4_session *session; | 1745 | struct nfsd4_session *session; |
1565 | struct nfsd4_slot *slot; | 1746 | struct nfsd4_slot *slot; |
1747 | struct nfsd4_conn *conn; | ||
1566 | int status; | 1748 | int status; |
1567 | 1749 | ||
1568 | if (resp->opcnt != 1) | 1750 | if (resp->opcnt != 1) |
1569 | return nfserr_sequence_pos; | 1751 | return nfserr_sequence_pos; |
1570 | 1752 | ||
1753 | /* | ||
1754 | * Will be either used or freed by nfsd4_sequence_check_conn | ||
1755 | * below. | ||
1756 | */ | ||
1757 | conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); | ||
1758 | if (!conn) | ||
1759 | return nfserr_jukebox; | ||
1760 | |||
1571 | spin_lock(&client_lock); | 1761 | spin_lock(&client_lock); |
1572 | status = nfserr_badsession; | 1762 | status = nfserr_badsession; |
1573 | session = find_in_sessionid_hashtbl(&seq->sessionid); | 1763 | session = find_in_sessionid_hashtbl(&seq->sessionid); |
1574 | if (!session) | 1764 | if (!session) |
1575 | goto out; | 1765 | goto out; |
1576 | 1766 | ||
1767 | status = nfserr_too_many_ops; | ||
1768 | if (nfsd4_session_too_many_ops(rqstp, session)) | ||
1769 | goto out; | ||
1770 | |||
1577 | status = nfserr_badslot; | 1771 | status = nfserr_badslot; |
1578 | if (seq->slotid >= session->se_fchannel.maxreqs) | 1772 | if (seq->slotid >= session->se_fchannel.maxreqs) |
1579 | goto out; | 1773 | goto out; |
@@ -1599,6 +1793,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1599 | if (status) | 1793 | if (status) |
1600 | goto out; | 1794 | goto out; |
1601 | 1795 | ||
1796 | nfsd4_sequence_check_conn(conn, session); | ||
1797 | conn = NULL; | ||
1798 | |||
1602 | /* Success! bump slot seqid */ | 1799 | /* Success! bump slot seqid */ |
1603 | slot->sl_inuse = true; | 1800 | slot->sl_inuse = true; |
1604 | slot->sl_seqid = seq->seqid; | 1801 | slot->sl_seqid = seq->seqid; |
@@ -1610,9 +1807,14 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1610 | out: | 1807 | out: |
1611 | /* Hold a session reference until done processing the compound. */ | 1808 | /* Hold a session reference until done processing the compound. */ |
1612 | if (cstate->session) { | 1809 | if (cstate->session) { |
1810 | struct nfs4_client *clp = session->se_client; | ||
1811 | |||
1613 | nfsd4_get_session(cstate->session); | 1812 | nfsd4_get_session(cstate->session); |
1614 | atomic_inc(&session->se_client->cl_refcount); | 1813 | atomic_inc(&clp->cl_refcount); |
1814 | if (clp->cl_cb_state == NFSD4_CB_DOWN) | ||
1815 | seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN; | ||
1615 | } | 1816 | } |
1817 | kfree(conn); | ||
1616 | spin_unlock(&client_lock); | 1818 | spin_unlock(&client_lock); |
1617 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 1819 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
1618 | return status; | 1820 | return status; |
@@ -1621,6 +1823,8 @@ out: | |||
1621 | __be32 | 1823 | __be32 |
1622 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | 1824 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) |
1623 | { | 1825 | { |
1826 | int status = 0; | ||
1827 | |||
1624 | if (rc->rca_one_fs) { | 1828 | if (rc->rca_one_fs) { |
1625 | if (!cstate->current_fh.fh_dentry) | 1829 | if (!cstate->current_fh.fh_dentry) |
1626 | return nfserr_nofilehandle; | 1830 | return nfserr_nofilehandle; |
@@ -1630,9 +1834,14 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
1630 | */ | 1834 | */ |
1631 | return nfs_ok; | 1835 | return nfs_ok; |
1632 | } | 1836 | } |
1837 | |||
1633 | nfs4_lock_state(); | 1838 | nfs4_lock_state(); |
1634 | if (is_client_expired(cstate->session->se_client)) { | 1839 | status = nfserr_complete_already; |
1635 | nfs4_unlock_state(); | 1840 | if (cstate->session->se_client->cl_firststate) |
1841 | goto out; | ||
1842 | |||
1843 | status = nfserr_stale_clientid; | ||
1844 | if (is_client_expired(cstate->session->se_client)) | ||
1636 | /* | 1845 | /* |
1637 | * The following error isn't really legal. | 1846 | * The following error isn't really legal. |
1638 | * But we only get here if the client just explicitly | 1847 | * But we only get here if the client just explicitly |
@@ -1640,18 +1849,19 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
1640 | * error it gets back on an operation for the dead | 1849 | * error it gets back on an operation for the dead |
1641 | * client. | 1850 | * client. |
1642 | */ | 1851 | */ |
1643 | return nfserr_stale_clientid; | 1852 | goto out; |
1644 | } | 1853 | |
1854 | status = nfs_ok; | ||
1645 | nfsd4_create_clid_dir(cstate->session->se_client); | 1855 | nfsd4_create_clid_dir(cstate->session->se_client); |
1856 | out: | ||
1646 | nfs4_unlock_state(); | 1857 | nfs4_unlock_state(); |
1647 | return nfs_ok; | 1858 | return status; |
1648 | } | 1859 | } |
1649 | 1860 | ||
1650 | __be32 | 1861 | __be32 |
1651 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1862 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1652 | struct nfsd4_setclientid *setclid) | 1863 | struct nfsd4_setclientid *setclid) |
1653 | { | 1864 | { |
1654 | struct sockaddr *sa = svc_addr(rqstp); | ||
1655 | struct xdr_netobj clname = { | 1865 | struct xdr_netobj clname = { |
1656 | .len = setclid->se_namelen, | 1866 | .len = setclid->se_namelen, |
1657 | .data = setclid->se_name, | 1867 | .data = setclid->se_name, |
@@ -1677,10 +1887,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1677 | strhashval = clientstr_hashval(dname); | 1887 | strhashval = clientstr_hashval(dname); |
1678 | 1888 | ||
1679 | nfs4_lock_state(); | 1889 | nfs4_lock_state(); |
1680 | conf = find_confirmed_client_by_str(dname, strhashval, false); | 1890 | conf = find_confirmed_client_by_str(dname, strhashval); |
1681 | if (conf) { | 1891 | if (conf) { |
1682 | /* RFC 3530 14.2.33 CASE 0: */ | 1892 | /* RFC 3530 14.2.33 CASE 0: */ |
1683 | status = nfserr_clid_inuse; | 1893 | status = nfserr_clid_inuse; |
1894 | if (clp_used_exchangeid(conf)) | ||
1895 | goto out; | ||
1684 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1896 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
1685 | char addr_str[INET6_ADDRSTRLEN]; | 1897 | char addr_str[INET6_ADDRSTRLEN]; |
1686 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, | 1898 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, |
@@ -1695,7 +1907,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1695 | * has a description of SETCLIENTID request processing consisting | 1907 | * has a description of SETCLIENTID request processing consisting |
1696 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | 1908 | * of 5 bullet points, labeled as CASE0 - CASE4 below. |
1697 | */ | 1909 | */ |
1698 | unconf = find_unconfirmed_client_by_str(dname, strhashval, false); | 1910 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1699 | status = nfserr_resource; | 1911 | status = nfserr_resource; |
1700 | if (!conf) { | 1912 | if (!conf) { |
1701 | /* | 1913 | /* |
@@ -1747,7 +1959,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1747 | goto out; | 1959 | goto out; |
1748 | gen_clid(new); | 1960 | gen_clid(new); |
1749 | } | 1961 | } |
1750 | gen_callback(new, setclid, rpc_get_scope_id(sa)); | 1962 | /* |
1963 | * XXX: we should probably set this at creation time, and check | ||
1964 | * for consistent minorversion use throughout: | ||
1965 | */ | ||
1966 | new->cl_minorversion = 0; | ||
1967 | gen_callback(new, setclid, rqstp); | ||
1751 | add_to_unconfirmed(new, strhashval); | 1968 | add_to_unconfirmed(new, strhashval); |
1752 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 1969 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
1753 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 1970 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
@@ -1806,8 +2023,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1806 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | 2023 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) |
1807 | status = nfserr_clid_inuse; | 2024 | status = nfserr_clid_inuse; |
1808 | else { | 2025 | else { |
1809 | atomic_set(&conf->cl_cb_set, 0); | 2026 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); |
1810 | nfsd4_probe_callback(conf, &unconf->cl_cb_conn); | 2027 | nfsd4_probe_callback(conf); |
1811 | expire_client(unconf); | 2028 | expire_client(unconf); |
1812 | status = nfs_ok; | 2029 | status = nfs_ok; |
1813 | 2030 | ||
@@ -1834,14 +2051,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1834 | unsigned int hash = | 2051 | unsigned int hash = |
1835 | clientstr_hashval(unconf->cl_recdir); | 2052 | clientstr_hashval(unconf->cl_recdir); |
1836 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | 2053 | conf = find_confirmed_client_by_str(unconf->cl_recdir, |
1837 | hash, false); | 2054 | hash); |
1838 | if (conf) { | 2055 | if (conf) { |
1839 | nfsd4_remove_clid_dir(conf); | 2056 | nfsd4_remove_clid_dir(conf); |
1840 | expire_client(conf); | 2057 | expire_client(conf); |
1841 | } | 2058 | } |
1842 | move_to_confirmed(unconf); | 2059 | move_to_confirmed(unconf); |
1843 | conf = unconf; | 2060 | conf = unconf; |
1844 | nfsd4_probe_callback(conf, &conf->cl_cb_conn); | 2061 | nfsd4_probe_callback(conf); |
1845 | status = nfs_ok; | 2062 | status = nfs_ok; |
1846 | } | 2063 | } |
1847 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | 2064 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) |
@@ -1877,6 +2094,7 @@ alloc_init_file(struct inode *ino) | |||
1877 | fp->fi_inode = igrab(ino); | 2094 | fp->fi_inode = igrab(ino); |
1878 | fp->fi_id = current_fileid++; | 2095 | fp->fi_id = current_fileid++; |
1879 | fp->fi_had_conflict = false; | 2096 | fp->fi_had_conflict = false; |
2097 | fp->fi_lease = NULL; | ||
1880 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | 2098 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); |
1881 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | 2099 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); |
1882 | spin_lock(&recall_lock); | 2100 | spin_lock(&recall_lock); |
@@ -2128,23 +2346,8 @@ nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) | |||
2128 | nfs4_file_put_access(fp, O_RDONLY); | 2346 | nfs4_file_put_access(fp, O_RDONLY); |
2129 | } | 2347 | } |
2130 | 2348 | ||
2131 | /* | 2349 | static void nfsd_break_one_deleg(struct nfs4_delegation *dp) |
2132 | * Spawn a thread to perform a recall on the delegation represented | ||
2133 | * by the lease (file_lock) | ||
2134 | * | ||
2135 | * Called from break_lease() with lock_kernel() held. | ||
2136 | * Note: we assume break_lease will only call this *once* for any given | ||
2137 | * lease. | ||
2138 | */ | ||
2139 | static | ||
2140 | void nfsd_break_deleg_cb(struct file_lock *fl) | ||
2141 | { | 2350 | { |
2142 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; | ||
2143 | |||
2144 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); | ||
2145 | if (!dp) | ||
2146 | return; | ||
2147 | |||
2148 | /* We're assuming the state code never drops its reference | 2351 | /* We're assuming the state code never drops its reference |
2149 | * without first removing the lease. Since we're in this lease | 2352 | * without first removing the lease. Since we're in this lease |
2150 | * callback (and since the lease code is serialized by the kernel | 2353 | * callback (and since the lease code is serialized by the kernel |
@@ -2152,75 +2355,37 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2152 | * it's safe to take a reference: */ | 2355 | * it's safe to take a reference: */ |
2153 | atomic_inc(&dp->dl_count); | 2356 | atomic_inc(&dp->dl_count); |
2154 | 2357 | ||
2155 | spin_lock(&recall_lock); | ||
2156 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); | 2358 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); |
2157 | spin_unlock(&recall_lock); | ||
2158 | 2359 | ||
2159 | /* only place dl_time is set. protected by lock_kernel*/ | 2360 | /* only place dl_time is set. protected by lock_flocks*/ |
2160 | dp->dl_time = get_seconds(); | 2361 | dp->dl_time = get_seconds(); |
2161 | 2362 | ||
2162 | /* | ||
2163 | * We don't want the locks code to timeout the lease for us; | ||
2164 | * we'll remove it ourself if the delegation isn't returned | ||
2165 | * in time. | ||
2166 | */ | ||
2167 | fl->fl_break_time = 0; | ||
2168 | |||
2169 | dp->dl_file->fi_had_conflict = true; | ||
2170 | nfsd4_cb_recall(dp); | 2363 | nfsd4_cb_recall(dp); |
2171 | } | 2364 | } |
2172 | 2365 | ||
2173 | /* | 2366 | /* Called from break_lease() with lock_flocks() held. */ |
2174 | * The file_lock is being reapd. | 2367 | static void nfsd_break_deleg_cb(struct file_lock *fl) |
2175 | * | ||
2176 | * Called by locks_free_lock() with lock_kernel() held. | ||
2177 | */ | ||
2178 | static | ||
2179 | void nfsd_release_deleg_cb(struct file_lock *fl) | ||
2180 | { | ||
2181 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; | ||
2182 | |||
2183 | dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count)); | ||
2184 | |||
2185 | if (!(fl->fl_flags & FL_LEASE) || !dp) | ||
2186 | return; | ||
2187 | dp->dl_flock = NULL; | ||
2188 | } | ||
2189 | |||
2190 | /* | ||
2191 | * Set the delegation file_lock back pointer. | ||
2192 | * | ||
2193 | * Called from setlease() with lock_kernel() held. | ||
2194 | */ | ||
2195 | static | ||
2196 | void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl) | ||
2197 | { | ||
2198 | struct nfs4_delegation *dp = (struct nfs4_delegation *)new->fl_owner; | ||
2199 | |||
2200 | dprintk("NFSD: nfsd_copy_lock_deleg_cb: new fl %p dp %p\n", new, dp); | ||
2201 | if (!dp) | ||
2202 | return; | ||
2203 | dp->dl_flock = new; | ||
2204 | } | ||
2205 | |||
2206 | /* | ||
2207 | * Called from setlease() with lock_kernel() held | ||
2208 | */ | ||
2209 | static | ||
2210 | int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try) | ||
2211 | { | 2368 | { |
2212 | struct nfs4_delegation *onlistd = | 2369 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; |
2213 | (struct nfs4_delegation *)onlist->fl_owner; | 2370 | struct nfs4_delegation *dp; |
2214 | struct nfs4_delegation *tryd = | ||
2215 | (struct nfs4_delegation *)try->fl_owner; | ||
2216 | 2371 | ||
2217 | if (onlist->fl_lmops != try->fl_lmops) | 2372 | BUG_ON(!fp); |
2218 | return 0; | 2373 | /* We assume break_lease is only called once per lease: */ |
2374 | BUG_ON(fp->fi_had_conflict); | ||
2375 | /* | ||
2376 | * We don't want the locks code to timeout the lease for us; | ||
2377 | * we'll remove it ourself if a delegation isn't returned | ||
2378 | * in time: | ||
2379 | */ | ||
2380 | fl->fl_break_time = 0; | ||
2219 | 2381 | ||
2220 | return onlistd->dl_client == tryd->dl_client; | 2382 | spin_lock(&recall_lock); |
2383 | fp->fi_had_conflict = true; | ||
2384 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) | ||
2385 | nfsd_break_one_deleg(dp); | ||
2386 | spin_unlock(&recall_lock); | ||
2221 | } | 2387 | } |
2222 | 2388 | ||
2223 | |||
2224 | static | 2389 | static |
2225 | int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | 2390 | int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) |
2226 | { | 2391 | { |
@@ -2232,9 +2397,6 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
2232 | 2397 | ||
2233 | static const struct lock_manager_operations nfsd_lease_mng_ops = { | 2398 | static const struct lock_manager_operations nfsd_lease_mng_ops = { |
2234 | .fl_break = nfsd_break_deleg_cb, | 2399 | .fl_break = nfsd_break_deleg_cb, |
2235 | .fl_release_private = nfsd_release_deleg_cb, | ||
2236 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, | ||
2237 | .fl_mylease = nfsd_same_client_deleg_cb, | ||
2238 | .fl_change = nfsd_change_deleg_cb, | 2400 | .fl_change = nfsd_change_deleg_cb, |
2239 | }; | 2401 | }; |
2240 | 2402 | ||
@@ -2314,14 +2476,17 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | |||
2314 | { | 2476 | { |
2315 | struct nfs4_delegation *dp; | 2477 | struct nfs4_delegation *dp; |
2316 | 2478 | ||
2317 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) { | 2479 | spin_lock(&recall_lock); |
2318 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) | 2480 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) |
2481 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) { | ||
2482 | spin_unlock(&recall_lock); | ||
2319 | return dp; | 2483 | return dp; |
2320 | } | 2484 | } |
2485 | spin_unlock(&recall_lock); | ||
2321 | return NULL; | 2486 | return NULL; |
2322 | } | 2487 | } |
2323 | 2488 | ||
2324 | int share_access_to_flags(u32 share_access) | 2489 | static int share_access_to_flags(u32 share_access) |
2325 | { | 2490 | { |
2326 | share_access &= ~NFS4_SHARE_WANT_MASK; | 2491 | share_access &= ~NFS4_SHARE_WANT_MASK; |
2327 | 2492 | ||
@@ -2401,8 +2566,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | |||
2401 | if (!fp->fi_fds[oflag]) { | 2566 | if (!fp->fi_fds[oflag]) { |
2402 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | 2567 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, |
2403 | &fp->fi_fds[oflag]); | 2568 | &fp->fi_fds[oflag]); |
2404 | if (status == nfserr_dropit) | ||
2405 | status = nfserr_jukebox; | ||
2406 | if (status) | 2569 | if (status) |
2407 | return status; | 2570 | return status; |
2408 | } | 2571 | } |
@@ -2483,6 +2646,79 @@ nfs4_set_claim_prev(struct nfsd4_open *open) | |||
2483 | open->op_stateowner->so_client->cl_firststate = 1; | 2646 | open->op_stateowner->so_client->cl_firststate = 1; |
2484 | } | 2647 | } |
2485 | 2648 | ||
2649 | /* Should we give out recallable state?: */ | ||
2650 | static bool nfsd4_cb_channel_good(struct nfs4_client *clp) | ||
2651 | { | ||
2652 | if (clp->cl_cb_state == NFSD4_CB_UP) | ||
2653 | return true; | ||
2654 | /* | ||
2655 | * In the sessions case, since we don't have to establish a | ||
2656 | * separate connection for callbacks, we assume it's OK | ||
2657 | * until we hear otherwise: | ||
2658 | */ | ||
2659 | return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; | ||
2660 | } | ||
2661 | |||
2662 | static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag) | ||
2663 | { | ||
2664 | struct file_lock *fl; | ||
2665 | |||
2666 | fl = locks_alloc_lock(); | ||
2667 | if (!fl) | ||
2668 | return NULL; | ||
2669 | locks_init_lock(fl); | ||
2670 | fl->fl_lmops = &nfsd_lease_mng_ops; | ||
2671 | fl->fl_flags = FL_LEASE; | ||
2672 | fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | ||
2673 | fl->fl_end = OFFSET_MAX; | ||
2674 | fl->fl_owner = (fl_owner_t)(dp->dl_file); | ||
2675 | fl->fl_pid = current->tgid; | ||
2676 | return fl; | ||
2677 | } | ||
2678 | |||
2679 | static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | ||
2680 | { | ||
2681 | struct nfs4_file *fp = dp->dl_file; | ||
2682 | struct file_lock *fl; | ||
2683 | int status; | ||
2684 | |||
2685 | fl = nfs4_alloc_init_lease(dp, flag); | ||
2686 | if (!fl) | ||
2687 | return -ENOMEM; | ||
2688 | fl->fl_file = find_readable_file(fp); | ||
2689 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); | ||
2690 | status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); | ||
2691 | if (status) { | ||
2692 | list_del_init(&dp->dl_perclnt); | ||
2693 | locks_free_lock(fl); | ||
2694 | return -ENOMEM; | ||
2695 | } | ||
2696 | fp->fi_lease = fl; | ||
2697 | fp->fi_deleg_file = fl->fl_file; | ||
2698 | get_file(fp->fi_deleg_file); | ||
2699 | atomic_set(&fp->fi_delegees, 1); | ||
2700 | list_add(&dp->dl_perfile, &fp->fi_delegations); | ||
2701 | return 0; | ||
2702 | } | ||
2703 | |||
2704 | static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | ||
2705 | { | ||
2706 | struct nfs4_file *fp = dp->dl_file; | ||
2707 | |||
2708 | if (!fp->fi_lease) | ||
2709 | return nfs4_setlease(dp, flag); | ||
2710 | spin_lock(&recall_lock); | ||
2711 | if (fp->fi_had_conflict) { | ||
2712 | spin_unlock(&recall_lock); | ||
2713 | return -EAGAIN; | ||
2714 | } | ||
2715 | atomic_inc(&fp->fi_delegees); | ||
2716 | list_add(&dp->dl_perfile, &fp->fi_delegations); | ||
2717 | spin_unlock(&recall_lock); | ||
2718 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); | ||
2719 | return 0; | ||
2720 | } | ||
2721 | |||
2486 | /* | 2722 | /* |
2487 | * Attempt to hand out a delegation. | 2723 | * Attempt to hand out a delegation. |
2488 | */ | 2724 | */ |
@@ -2491,10 +2727,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2491 | { | 2727 | { |
2492 | struct nfs4_delegation *dp; | 2728 | struct nfs4_delegation *dp; |
2493 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2729 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2494 | int cb_up = atomic_read(&sop->so_client->cl_cb_set); | 2730 | int cb_up; |
2495 | struct file_lock fl, *flp = &fl; | ||
2496 | int status, flag = 0; | 2731 | int status, flag = 0; |
2497 | 2732 | ||
2733 | cb_up = nfsd4_cb_channel_good(sop->so_client); | ||
2498 | flag = NFS4_OPEN_DELEGATE_NONE; | 2734 | flag = NFS4_OPEN_DELEGATE_NONE; |
2499 | open->op_recall = 0; | 2735 | open->op_recall = 0; |
2500 | switch (open->op_claim_type) { | 2736 | switch (open->op_claim_type) { |
@@ -2522,29 +2758,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2522 | } | 2758 | } |
2523 | 2759 | ||
2524 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); | 2760 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); |
2525 | if (dp == NULL) { | 2761 | if (dp == NULL) |
2526 | flag = NFS4_OPEN_DELEGATE_NONE; | 2762 | goto out_no_deleg; |
2527 | goto out; | 2763 | status = nfs4_set_delegation(dp, flag); |
2528 | } | 2764 | if (status) |
2529 | locks_init_lock(&fl); | 2765 | goto out_free; |
2530 | fl.fl_lmops = &nfsd_lease_mng_ops; | ||
2531 | fl.fl_flags = FL_LEASE; | ||
2532 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | ||
2533 | fl.fl_end = OFFSET_MAX; | ||
2534 | fl.fl_owner = (fl_owner_t)dp; | ||
2535 | fl.fl_file = find_readable_file(stp->st_file); | ||
2536 | BUG_ON(!fl.fl_file); | ||
2537 | fl.fl_pid = current->tgid; | ||
2538 | |||
2539 | /* vfs_setlease checks to see if delegation should be handed out. | ||
2540 | * the lock_manager callbacks fl_mylease and fl_change are used | ||
2541 | */ | ||
2542 | if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) { | ||
2543 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | ||
2544 | unhash_delegation(dp); | ||
2545 | flag = NFS4_OPEN_DELEGATE_NONE; | ||
2546 | goto out; | ||
2547 | } | ||
2548 | 2766 | ||
2549 | memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); | 2767 | memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); |
2550 | 2768 | ||
@@ -2556,6 +2774,12 @@ out: | |||
2556 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | 2774 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) |
2557 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | 2775 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); |
2558 | open->op_delegate_type = flag; | 2776 | open->op_delegate_type = flag; |
2777 | return; | ||
2778 | out_free: | ||
2779 | nfs4_put_delegation(dp); | ||
2780 | out_no_deleg: | ||
2781 | flag = NFS4_OPEN_DELEGATE_NONE; | ||
2782 | goto out; | ||
2559 | } | 2783 | } |
2560 | 2784 | ||
2561 | /* | 2785 | /* |
@@ -2674,7 +2898,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2674 | renew_client(clp); | 2898 | renew_client(clp); |
2675 | status = nfserr_cb_path_down; | 2899 | status = nfserr_cb_path_down; |
2676 | if (!list_empty(&clp->cl_delegations) | 2900 | if (!list_empty(&clp->cl_delegations) |
2677 | && !atomic_read(&clp->cl_cb_set)) | 2901 | && clp->cl_cb_state != NFSD4_CB_UP) |
2678 | goto out; | 2902 | goto out; |
2679 | status = nfs_ok; | 2903 | status = nfs_ok; |
2680 | out: | 2904 | out: |
@@ -2682,7 +2906,7 @@ out: | |||
2682 | return status; | 2906 | return status; |
2683 | } | 2907 | } |
2684 | 2908 | ||
2685 | struct lock_manager nfsd4_manager = { | 2909 | static struct lock_manager nfsd4_manager = { |
2686 | }; | 2910 | }; |
2687 | 2911 | ||
2688 | static void | 2912 | static void |
@@ -2750,8 +2974,6 @@ nfs4_laundromat(void) | |||
2750 | test_val = u; | 2974 | test_val = u; |
2751 | break; | 2975 | break; |
2752 | } | 2976 | } |
2753 | dprintk("NFSD: purging unused delegation dp %p, fp %p\n", | ||
2754 | dp, dp->dl_flock); | ||
2755 | list_move(&dp->dl_recall_lru, &reaplist); | 2977 | list_move(&dp->dl_recall_lru, &reaplist); |
2756 | } | 2978 | } |
2757 | spin_unlock(&recall_lock); | 2979 | spin_unlock(&recall_lock); |
@@ -2861,7 +3083,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | |||
2861 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) | 3083 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) |
2862 | return nfs_ok; | 3084 | return nfs_ok; |
2863 | else if (locks_in_grace()) { | 3085 | else if (locks_in_grace()) { |
2864 | /* Answer in remaining cases depends on existance of | 3086 | /* Answer in remaining cases depends on existence of |
2865 | * conflicting state; so we must wait out the grace period. */ | 3087 | * conflicting state; so we must wait out the grace period. */ |
2866 | return nfserr_grace; | 3088 | return nfserr_grace; |
2867 | } else if (flags & WR_STATE) | 3089 | } else if (flags & WR_STATE) |
@@ -2944,7 +3166,11 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2944 | if (STALE_STATEID(stateid)) | 3166 | if (STALE_STATEID(stateid)) |
2945 | goto out; | 3167 | goto out; |
2946 | 3168 | ||
2947 | status = nfserr_bad_stateid; | 3169 | /* |
3170 | * We assume that any stateid that has the current boot time, | ||
3171 | * but that we can't find, is expired: | ||
3172 | */ | ||
3173 | status = nfserr_expired; | ||
2948 | if (is_delegation_stateid(stateid)) { | 3174 | if (is_delegation_stateid(stateid)) { |
2949 | dp = find_delegation_stateid(ino, stateid); | 3175 | dp = find_delegation_stateid(ino, stateid); |
2950 | if (!dp) | 3176 | if (!dp) |
@@ -2957,13 +3183,15 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2957 | if (status) | 3183 | if (status) |
2958 | goto out; | 3184 | goto out; |
2959 | renew_client(dp->dl_client); | 3185 | renew_client(dp->dl_client); |
2960 | if (filpp) | 3186 | if (filpp) { |
2961 | *filpp = find_readable_file(dp->dl_file); | 3187 | *filpp = dp->dl_file->fi_deleg_file; |
2962 | BUG_ON(!*filpp); | 3188 | BUG_ON(!*filpp); |
3189 | } | ||
2963 | } else { /* open or lock stateid */ | 3190 | } else { /* open or lock stateid */ |
2964 | stp = find_stateid(stateid, flags); | 3191 | stp = find_stateid(stateid, flags); |
2965 | if (!stp) | 3192 | if (!stp) |
2966 | goto out; | 3193 | goto out; |
3194 | status = nfserr_bad_stateid; | ||
2967 | if (nfs4_check_fh(current_fh, stp)) | 3195 | if (nfs4_check_fh(current_fh, stp)) |
2968 | goto out; | 3196 | goto out; |
2969 | if (!stp->st_stateowner->so_confirmed) | 3197 | if (!stp->st_stateowner->so_confirmed) |
@@ -3038,8 +3266,9 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
3038 | * a replayed close: | 3266 | * a replayed close: |
3039 | */ | 3267 | */ |
3040 | sop = search_close_lru(stateid->si_stateownerid, flags); | 3268 | sop = search_close_lru(stateid->si_stateownerid, flags); |
3269 | /* It's not stale; let's assume it's expired: */ | ||
3041 | if (sop == NULL) | 3270 | if (sop == NULL) |
3042 | return nfserr_bad_stateid; | 3271 | return nfserr_expired; |
3043 | *sopp = sop; | 3272 | *sopp = sop; |
3044 | goto check_replay; | 3273 | goto check_replay; |
3045 | } | 3274 | } |
@@ -3304,6 +3533,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3304 | status = nfserr_bad_stateid; | 3533 | status = nfserr_bad_stateid; |
3305 | if (!is_delegation_stateid(stateid)) | 3534 | if (!is_delegation_stateid(stateid)) |
3306 | goto out; | 3535 | goto out; |
3536 | status = nfserr_expired; | ||
3307 | dp = find_delegation_stateid(inode, stateid); | 3537 | dp = find_delegation_stateid(inode, stateid); |
3308 | if (!dp) | 3538 | if (!dp) |
3309 | goto out; | 3539 | goto out; |
@@ -3473,7 +3703,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, | |||
3473 | /* | 3703 | /* |
3474 | * Alloc a lock owner structure. | 3704 | * Alloc a lock owner structure. |
3475 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has | 3705 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has |
3476 | * occured. | 3706 | * occurred. |
3477 | * | 3707 | * |
3478 | * strhashval = lock_ownerstr_hashval | 3708 | * strhashval = lock_ownerstr_hashval |
3479 | */ | 3709 | */ |
@@ -3534,6 +3764,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3534 | stp->st_stateid.si_stateownerid = sop->so_id; | 3764 | stp->st_stateid.si_stateownerid = sop->so_id; |
3535 | stp->st_stateid.si_fileid = fp->fi_id; | 3765 | stp->st_stateid.si_fileid = fp->fi_id; |
3536 | stp->st_stateid.si_generation = 0; | 3766 | stp->st_stateid.si_generation = 0; |
3767 | stp->st_access_bmap = 0; | ||
3537 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3768 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3538 | stp->st_openstp = open_stp; | 3769 | stp->st_openstp = open_stp; |
3539 | 3770 | ||
@@ -3548,6 +3779,17 @@ check_lock_length(u64 offset, u64 length) | |||
3548 | LOFF_OVERFLOW(offset, length))); | 3779 | LOFF_OVERFLOW(offset, length))); |
3549 | } | 3780 | } |
3550 | 3781 | ||
3782 | static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access) | ||
3783 | { | ||
3784 | struct nfs4_file *fp = lock_stp->st_file; | ||
3785 | int oflag = nfs4_access_to_omode(access); | ||
3786 | |||
3787 | if (test_bit(access, &lock_stp->st_access_bmap)) | ||
3788 | return; | ||
3789 | nfs4_file_get_access(fp, oflag); | ||
3790 | __set_bit(access, &lock_stp->st_access_bmap); | ||
3791 | } | ||
3792 | |||
3551 | /* | 3793 | /* |
3552 | * LOCK operation | 3794 | * LOCK operation |
3553 | */ | 3795 | */ |
@@ -3564,7 +3806,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3564 | struct file_lock conflock; | 3806 | struct file_lock conflock; |
3565 | __be32 status = 0; | 3807 | __be32 status = 0; |
3566 | unsigned int strhashval; | 3808 | unsigned int strhashval; |
3567 | unsigned int cmd; | ||
3568 | int err; | 3809 | int err; |
3569 | 3810 | ||
3570 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 3811 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
@@ -3646,22 +3887,18 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3646 | switch (lock->lk_type) { | 3887 | switch (lock->lk_type) { |
3647 | case NFS4_READ_LT: | 3888 | case NFS4_READ_LT: |
3648 | case NFS4_READW_LT: | 3889 | case NFS4_READW_LT: |
3649 | if (find_readable_file(lock_stp->st_file)) { | 3890 | filp = find_readable_file(lock_stp->st_file); |
3650 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ); | 3891 | if (filp) |
3651 | filp = find_readable_file(lock_stp->st_file); | 3892 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); |
3652 | } | ||
3653 | file_lock.fl_type = F_RDLCK; | 3893 | file_lock.fl_type = F_RDLCK; |
3654 | cmd = F_SETLK; | 3894 | break; |
3655 | break; | ||
3656 | case NFS4_WRITE_LT: | 3895 | case NFS4_WRITE_LT: |
3657 | case NFS4_WRITEW_LT: | 3896 | case NFS4_WRITEW_LT: |
3658 | if (find_writeable_file(lock_stp->st_file)) { | 3897 | filp = find_writeable_file(lock_stp->st_file); |
3659 | nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE); | 3898 | if (filp) |
3660 | filp = find_writeable_file(lock_stp->st_file); | 3899 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); |
3661 | } | ||
3662 | file_lock.fl_type = F_WRLCK; | 3900 | file_lock.fl_type = F_WRLCK; |
3663 | cmd = F_SETLK; | 3901 | break; |
3664 | break; | ||
3665 | default: | 3902 | default: |
3666 | status = nfserr_inval; | 3903 | status = nfserr_inval; |
3667 | goto out; | 3904 | goto out; |
@@ -3685,7 +3922,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3685 | * Note: locks.c uses the BKL to protect the inode's lock list. | 3922 | * Note: locks.c uses the BKL to protect the inode's lock list. |
3686 | */ | 3923 | */ |
3687 | 3924 | ||
3688 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); | 3925 | err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); |
3689 | switch (-err) { | 3926 | switch (-err) { |
3690 | case 0: /* success! */ | 3927 | case 0: /* success! */ |
3691 | update_stateid(&lock_stp->st_stateid); | 3928 | update_stateid(&lock_stp->st_stateid); |
@@ -3895,7 +4132,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) | |||
3895 | struct inode *inode = filp->fi_inode; | 4132 | struct inode *inode = filp->fi_inode; |
3896 | int status = 0; | 4133 | int status = 0; |
3897 | 4134 | ||
3898 | lock_kernel(); | 4135 | lock_flocks(); |
3899 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { | 4136 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { |
3900 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) { | 4137 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) { |
3901 | status = 1; | 4138 | status = 1; |
@@ -3903,7 +4140,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) | |||
3903 | } | 4140 | } |
3904 | } | 4141 | } |
3905 | out: | 4142 | out: |
3906 | unlock_kernel(); | 4143 | unlock_flocks(); |
3907 | return status; | 4144 | return status; |
3908 | } | 4145 | } |
3909 | 4146 | ||
@@ -3980,7 +4217,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) | |||
3980 | unsigned int strhashval = clientstr_hashval(name); | 4217 | unsigned int strhashval = clientstr_hashval(name); |
3981 | struct nfs4_client *clp; | 4218 | struct nfs4_client *clp; |
3982 | 4219 | ||
3983 | clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id); | 4220 | clp = find_confirmed_client_by_str(name, strhashval); |
3984 | return clp ? 1 : 0; | 4221 | return clp ? 1 : 0; |
3985 | } | 4222 | } |
3986 | 4223 | ||
@@ -4209,7 +4446,7 @@ __nfs4_state_shutdown(void) | |||
4209 | void | 4446 | void |
4210 | nfs4_state_shutdown(void) | 4447 | nfs4_state_shutdown(void) |
4211 | { | 4448 | { |
4212 | cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work); | 4449 | cancel_delayed_work_sync(&laundromat_work); |
4213 | destroy_workqueue(laundry_wq); | 4450 | destroy_workqueue(laundry_wq); |
4214 | locks_end_grace(&nfsd4_manager); | 4451 | locks_end_grace(&nfsd4_manager); |
4215 | nfs4_lock_state(); | 4452 | nfs4_lock_state(); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1a468bbd330f..990181103214 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; |
@@ -316,8 +317,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
316 | READ_BUF(dummy32); | 317 | READ_BUF(dummy32); |
317 | len += (XDR_QUADLEN(dummy32) << 2); | 318 | len += (XDR_QUADLEN(dummy32) << 2); |
318 | READMEM(buf, dummy32); | 319 | READMEM(buf, dummy32); |
319 | if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) | 320 | if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) |
320 | goto out_nfserr; | 321 | return status; |
321 | iattr->ia_valid |= ATTR_UID; | 322 | iattr->ia_valid |= ATTR_UID; |
322 | } | 323 | } |
323 | if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { | 324 | if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { |
@@ -327,8 +328,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
327 | READ_BUF(dummy32); | 328 | READ_BUF(dummy32); |
328 | len += (XDR_QUADLEN(dummy32) << 2); | 329 | len += (XDR_QUADLEN(dummy32) << 2); |
329 | READMEM(buf, dummy32); | 330 | READMEM(buf, dummy32); |
330 | if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) | 331 | if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) |
331 | goto out_nfserr; | 332 | return status; |
332 | iattr->ia_valid |= ATTR_GID; | 333 | iattr->ia_valid |= ATTR_GID; |
333 | } | 334 | } |
334 | if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { | 335 | if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { |
@@ -420,6 +421,18 @@ 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 | |||
428 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 8); | ||
429 | COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); | ||
430 | READ32(bcts->dir); | ||
431 | /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker | ||
432 | * could help us figure out we should be using it. */ | ||
433 | DECODE_TAIL; | ||
434 | } | ||
435 | |||
423 | static __be32 | 436 | static __be32 |
424 | nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) | 437 | nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) |
425 | { | 438 | { |
@@ -572,8 +585,6 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) | |||
572 | READ_BUF(lockt->lt_owner.len); | 585 | READ_BUF(lockt->lt_owner.len); |
573 | READMEM(lockt->lt_owner.data, lockt->lt_owner.len); | 586 | READMEM(lockt->lt_owner.data, lockt->lt_owner.len); |
574 | 587 | ||
575 | if (argp->minorversion && !zero_clientid(&lockt->lt_clientid)) | ||
576 | return nfserr_inval; | ||
577 | DECODE_TAIL; | 588 | DECODE_TAIL; |
578 | } | 589 | } |
579 | 590 | ||
@@ -847,6 +858,17 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, | |||
847 | } | 858 | } |
848 | 859 | ||
849 | static __be32 | 860 | static __be32 |
861 | nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, | ||
862 | struct nfsd4_secinfo_no_name *sin) | ||
863 | { | ||
864 | DECODE_HEAD; | ||
865 | |||
866 | READ_BUF(4); | ||
867 | READ32(sin->sin_style); | ||
868 | DECODE_TAIL; | ||
869 | } | ||
870 | |||
871 | static __be32 | ||
850 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) | 872 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) |
851 | { | 873 | { |
852 | __be32 status; | 874 | __be32 status; |
@@ -1005,7 +1027,7 @@ static __be32 | |||
1005 | nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, | 1027 | nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, |
1006 | struct nfsd4_exchange_id *exid) | 1028 | struct nfsd4_exchange_id *exid) |
1007 | { | 1029 | { |
1008 | int dummy; | 1030 | int dummy, tmp; |
1009 | DECODE_HEAD; | 1031 | DECODE_HEAD; |
1010 | 1032 | ||
1011 | READ_BUF(NFS4_VERIFIER_SIZE); | 1033 | READ_BUF(NFS4_VERIFIER_SIZE); |
@@ -1053,15 +1075,23 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, | |||
1053 | 1075 | ||
1054 | /* ssp_hash_algs<> */ | 1076 | /* ssp_hash_algs<> */ |
1055 | READ_BUF(4); | 1077 | READ_BUF(4); |
1056 | READ32(dummy); | 1078 | READ32(tmp); |
1057 | READ_BUF(dummy); | 1079 | while (tmp--) { |
1058 | p += XDR_QUADLEN(dummy); | 1080 | READ_BUF(4); |
1081 | READ32(dummy); | ||
1082 | READ_BUF(dummy); | ||
1083 | p += XDR_QUADLEN(dummy); | ||
1084 | } | ||
1059 | 1085 | ||
1060 | /* ssp_encr_algs<> */ | 1086 | /* ssp_encr_algs<> */ |
1061 | READ_BUF(4); | 1087 | READ_BUF(4); |
1062 | READ32(dummy); | 1088 | READ32(tmp); |
1063 | READ_BUF(dummy); | 1089 | while (tmp--) { |
1064 | p += XDR_QUADLEN(dummy); | 1090 | READ_BUF(4); |
1091 | READ32(dummy); | ||
1092 | READ_BUF(dummy); | ||
1093 | p += XDR_QUADLEN(dummy); | ||
1094 | } | ||
1065 | 1095 | ||
1066 | /* ssp_window and ssp_num_gss_handles */ | 1096 | /* ssp_window and ssp_num_gss_handles */ |
1067 | READ_BUF(8); | 1097 | READ_BUF(8); |
@@ -1180,8 +1210,6 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, | |||
1180 | READ_BUF(4); | 1210 | READ_BUF(4); |
1181 | READ32(dummy); | 1211 | READ32(dummy); |
1182 | READ_BUF(dummy * 4); | 1212 | READ_BUF(dummy * 4); |
1183 | for (i = 0; i < dummy; ++i) | ||
1184 | READ32(dummy); | ||
1185 | break; | 1213 | break; |
1186 | case RPC_AUTH_GSS: | 1214 | case RPC_AUTH_GSS: |
1187 | dprintk("RPC_AUTH_GSS callback secflavor " | 1215 | dprintk("RPC_AUTH_GSS callback secflavor " |
@@ -1197,7 +1225,6 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, | |||
1197 | READ_BUF(4); | 1225 | READ_BUF(4); |
1198 | READ32(dummy); | 1226 | READ32(dummy); |
1199 | READ_BUF(dummy); | 1227 | READ_BUF(dummy); |
1200 | p += XDR_QUADLEN(dummy); | ||
1201 | break; | 1228 | break; |
1202 | default: | 1229 | default: |
1203 | dprintk("Illegal callback secflavor\n"); | 1230 | dprintk("Illegal callback secflavor\n"); |
@@ -1339,7 +1366,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
1339 | 1366 | ||
1340 | /* new operations for NFSv4.1 */ | 1367 | /* new operations for NFSv4.1 */ |
1341 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, | 1368 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, |
1342 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp, | 1369 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, |
1343 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, | 1370 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
1344 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, | 1371 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
1345 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, | 1372 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
@@ -1350,7 +1377,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
1350 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, | 1377 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, |
1351 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, | 1378 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, |
1352 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, | 1379 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, |
1353 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp, | 1380 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, |
1354 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, | 1381 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, |
1355 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, | 1382 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
1356 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, | 1383 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
@@ -1805,19 +1832,23 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1805 | goto out_nfserr; | 1832 | goto out_nfserr; |
1806 | } | 1833 | } |
1807 | } | 1834 | } |
1808 | if ((buflen -= 16) < 0) | ||
1809 | goto out_resource; | ||
1810 | 1835 | ||
1811 | if (unlikely(bmval2)) { | 1836 | if (bmval2) { |
1837 | if ((buflen -= 16) < 0) | ||
1838 | goto out_resource; | ||
1812 | WRITE32(3); | 1839 | WRITE32(3); |
1813 | WRITE32(bmval0); | 1840 | WRITE32(bmval0); |
1814 | WRITE32(bmval1); | 1841 | WRITE32(bmval1); |
1815 | WRITE32(bmval2); | 1842 | WRITE32(bmval2); |
1816 | } else if (likely(bmval1)) { | 1843 | } else if (bmval1) { |
1844 | if ((buflen -= 12) < 0) | ||
1845 | goto out_resource; | ||
1817 | WRITE32(2); | 1846 | WRITE32(2); |
1818 | WRITE32(bmval0); | 1847 | WRITE32(bmval0); |
1819 | WRITE32(bmval1); | 1848 | WRITE32(bmval1); |
1820 | } else { | 1849 | } else { |
1850 | if ((buflen -= 8) < 0) | ||
1851 | goto out_resource; | ||
1821 | WRITE32(1); | 1852 | WRITE32(1); |
1822 | WRITE32(bmval0); | 1853 | WRITE32(bmval0); |
1823 | } | 1854 | } |
@@ -1828,15 +1859,17 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1828 | u32 word1 = nfsd_suppattrs1(minorversion); | 1859 | u32 word1 = nfsd_suppattrs1(minorversion); |
1829 | u32 word2 = nfsd_suppattrs2(minorversion); | 1860 | u32 word2 = nfsd_suppattrs2(minorversion); |
1830 | 1861 | ||
1831 | if ((buflen -= 12) < 0) | ||
1832 | goto out_resource; | ||
1833 | if (!aclsupport) | 1862 | if (!aclsupport) |
1834 | word0 &= ~FATTR4_WORD0_ACL; | 1863 | word0 &= ~FATTR4_WORD0_ACL; |
1835 | if (!word2) { | 1864 | if (!word2) { |
1865 | if ((buflen -= 12) < 0) | ||
1866 | goto out_resource; | ||
1836 | WRITE32(2); | 1867 | WRITE32(2); |
1837 | WRITE32(word0); | 1868 | WRITE32(word0); |
1838 | WRITE32(word1); | 1869 | WRITE32(word1); |
1839 | } else { | 1870 | } else { |
1871 | if ((buflen -= 16) < 0) | ||
1872 | goto out_resource; | ||
1840 | WRITE32(3); | 1873 | WRITE32(3); |
1841 | WRITE32(word0); | 1874 | WRITE32(word0); |
1842 | WRITE32(word1); | 1875 | WRITE32(word1); |
@@ -2303,8 +2336,6 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, | |||
2303 | case nfserr_resource: | 2336 | case nfserr_resource: |
2304 | nfserr = nfserr_toosmall; | 2337 | nfserr = nfserr_toosmall; |
2305 | goto fail; | 2338 | goto fail; |
2306 | case nfserr_dropit: | ||
2307 | goto fail; | ||
2308 | case nfserr_noent: | 2339 | case nfserr_noent: |
2309 | goto skip_entry; | 2340 | goto skip_entry; |
2310 | default: | 2341 | default: |
@@ -2359,6 +2390,21 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2359 | return nfserr; | 2390 | return nfserr; |
2360 | } | 2391 | } |
2361 | 2392 | ||
2393 | static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) | ||
2394 | { | ||
2395 | __be32 *p; | ||
2396 | |||
2397 | if (!nfserr) { | ||
2398 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8); | ||
2399 | WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); | ||
2400 | WRITE32(bcts->dir); | ||
2401 | /* XXX: ? */ | ||
2402 | WRITE32(0); | ||
2403 | ADJUST_ARGS(); | ||
2404 | } | ||
2405 | return nfserr; | ||
2406 | } | ||
2407 | |||
2362 | static __be32 | 2408 | static __be32 |
2363 | nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) | 2409 | nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) |
2364 | { | 2410 | { |
@@ -2820,11 +2866,10 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2820 | } | 2866 | } |
2821 | 2867 | ||
2822 | static __be32 | 2868 | static __be32 |
2823 | nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | 2869 | nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp, |
2824 | struct nfsd4_secinfo *secinfo) | 2870 | __be32 nfserr,struct svc_export *exp) |
2825 | { | 2871 | { |
2826 | int i = 0; | 2872 | int i = 0; |
2827 | struct svc_export *exp = secinfo->si_exp; | ||
2828 | u32 nflavs; | 2873 | u32 nflavs; |
2829 | struct exp_flavor_info *flavs; | 2874 | struct exp_flavor_info *flavs; |
2830 | struct exp_flavor_info def_flavs[2]; | 2875 | struct exp_flavor_info def_flavs[2]; |
@@ -2886,6 +2931,20 @@ out: | |||
2886 | return nfserr; | 2931 | return nfserr; |
2887 | } | 2932 | } |
2888 | 2933 | ||
2934 | static __be32 | ||
2935 | nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
2936 | struct nfsd4_secinfo *secinfo) | ||
2937 | { | ||
2938 | return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp); | ||
2939 | } | ||
2940 | |||
2941 | static __be32 | ||
2942 | nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
2943 | struct nfsd4_secinfo_no_name *secinfo) | ||
2944 | { | ||
2945 | return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp); | ||
2946 | } | ||
2947 | |||
2889 | /* | 2948 | /* |
2890 | * The SETATTR encode routine is special -- it always encodes a bitmap, | 2949 | * The SETATTR encode routine is special -- it always encodes a bitmap, |
2891 | * regardless of the error status. | 2950 | * regardless of the error status. |
@@ -3056,7 +3115,7 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, | |||
3056 | return nfserr; | 3115 | return nfserr; |
3057 | } | 3116 | } |
3058 | 3117 | ||
3059 | __be32 | 3118 | static __be32 |
3060 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3119 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, |
3061 | struct nfsd4_sequence *seq) | 3120 | struct nfsd4_sequence *seq) |
3062 | { | 3121 | { |
@@ -3070,13 +3129,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | |||
3070 | WRITE32(seq->seqid); | 3129 | WRITE32(seq->seqid); |
3071 | WRITE32(seq->slotid); | 3130 | WRITE32(seq->slotid); |
3072 | WRITE32(seq->maxslots); | 3131 | WRITE32(seq->maxslots); |
3073 | /* | 3132 | /* For now: target_maxslots = maxslots */ |
3074 | * FIXME: for now: | ||
3075 | * target_maxslots = maxslots | ||
3076 | * status_flags = 0 | ||
3077 | */ | ||
3078 | WRITE32(seq->maxslots); | 3133 | WRITE32(seq->maxslots); |
3079 | WRITE32(0); | 3134 | WRITE32(seq->status_flags); |
3080 | 3135 | ||
3081 | ADJUST_ARGS(); | 3136 | ADJUST_ARGS(); |
3082 | resp->cstate.datap = p; /* DRC cache data pointer */ | 3137 | resp->cstate.datap = p; /* DRC cache data pointer */ |
@@ -3137,7 +3192,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3137 | 3192 | ||
3138 | /* NFSv4.1 operations */ | 3193 | /* NFSv4.1 operations */ |
3139 | [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, | 3194 | [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, |
3140 | [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop, | 3195 | [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session, |
3141 | [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, | 3196 | [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, |
3142 | [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, | 3197 | [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, |
3143 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, | 3198 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, |
@@ -3148,7 +3203,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
3148 | [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, | 3203 | [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, |
3149 | [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, | 3204 | [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, |
3150 | [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, | 3205 | [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, |
3151 | [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_noop, | 3206 | [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, |
3152 | [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, | 3207 | [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, |
3153 | [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, | 3208 | [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, |
3154 | [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop, | 3209 | [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop, |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index b53b1d042f1f..2b1449dd2f49 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -8,20 +8,23 @@ | |||
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> |
15 | #include <linux/sunrpc/gss_api.h> | ||
16 | #include <linux/sunrpc/gss_krb5_enctypes.h> | ||
16 | 17 | ||
18 | #include "idmap.h" | ||
17 | #include "nfsd.h" | 19 | #include "nfsd.h" |
18 | #include "cache.h" | 20 | #include "cache.h" |
19 | 21 | ||
20 | /* | 22 | /* |
21 | * We have a single directory with 9 nodes in it. | 23 | * We have a single directory with several nodes in it. |
22 | */ | 24 | */ |
23 | enum { | 25 | enum { |
24 | NFSD_Root = 1, | 26 | NFSD_Root = 1, |
27 | #ifdef CONFIG_NFSD_DEPRECATED | ||
25 | NFSD_Svc, | 28 | NFSD_Svc, |
26 | NFSD_Add, | 29 | NFSD_Add, |
27 | NFSD_Del, | 30 | NFSD_Del, |
@@ -29,6 +32,7 @@ enum { | |||
29 | NFSD_Unexport, | 32 | NFSD_Unexport, |
30 | NFSD_Getfd, | 33 | NFSD_Getfd, |
31 | NFSD_Getfs, | 34 | NFSD_Getfs, |
35 | #endif | ||
32 | NFSD_List, | 36 | NFSD_List, |
33 | NFSD_Export_features, | 37 | NFSD_Export_features, |
34 | NFSD_Fh, | 38 | NFSD_Fh, |
@@ -40,6 +44,7 @@ enum { | |||
40 | NFSD_Versions, | 44 | NFSD_Versions, |
41 | NFSD_Ports, | 45 | NFSD_Ports, |
42 | NFSD_MaxBlkSize, | 46 | NFSD_MaxBlkSize, |
47 | NFSD_SupportedEnctypes, | ||
43 | /* | 48 | /* |
44 | * The below MUST come last. Otherwise we leave a hole in nfsd_files[] | 49 | * The below MUST come last. Otherwise we leave a hole in nfsd_files[] |
45 | * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops | 50 | * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops |
@@ -54,6 +59,7 @@ enum { | |||
54 | /* | 59 | /* |
55 | * write() for these nodes. | 60 | * write() for these nodes. |
56 | */ | 61 | */ |
62 | #ifdef CONFIG_NFSD_DEPRECATED | ||
57 | static ssize_t write_svc(struct file *file, char *buf, size_t size); | 63 | static ssize_t write_svc(struct file *file, char *buf, size_t size); |
58 | static ssize_t write_add(struct file *file, char *buf, size_t size); | 64 | static ssize_t write_add(struct file *file, char *buf, size_t size); |
59 | static ssize_t write_del(struct file *file, char *buf, size_t size); | 65 | static ssize_t write_del(struct file *file, char *buf, size_t size); |
@@ -61,6 +67,7 @@ static ssize_t write_export(struct file *file, char *buf, size_t size); | |||
61 | static ssize_t write_unexport(struct file *file, char *buf, size_t size); | 67 | static ssize_t write_unexport(struct file *file, char *buf, size_t size); |
62 | static ssize_t write_getfd(struct file *file, char *buf, size_t size); | 68 | static ssize_t write_getfd(struct file *file, char *buf, size_t size); |
63 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); | 69 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); |
70 | #endif | ||
64 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); | 71 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); |
65 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size); | 72 | static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size); |
66 | static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size); | 73 | static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size); |
@@ -76,6 +83,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | |||
76 | #endif | 83 | #endif |
77 | 84 | ||
78 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 85 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { |
86 | #ifdef CONFIG_NFSD_DEPRECATED | ||
79 | [NFSD_Svc] = write_svc, | 87 | [NFSD_Svc] = write_svc, |
80 | [NFSD_Add] = write_add, | 88 | [NFSD_Add] = write_add, |
81 | [NFSD_Del] = write_del, | 89 | [NFSD_Del] = write_del, |
@@ -83,6 +91,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { | |||
83 | [NFSD_Unexport] = write_unexport, | 91 | [NFSD_Unexport] = write_unexport, |
84 | [NFSD_Getfd] = write_getfd, | 92 | [NFSD_Getfd] = write_getfd, |
85 | [NFSD_Getfs] = write_getfs, | 93 | [NFSD_Getfs] = write_getfs, |
94 | #endif | ||
86 | [NFSD_Fh] = write_filehandle, | 95 | [NFSD_Fh] = write_filehandle, |
87 | [NFSD_FO_UnlockIP] = write_unlock_ip, | 96 | [NFSD_FO_UnlockIP] = write_unlock_ip, |
88 | [NFSD_FO_UnlockFS] = write_unlock_fs, | 97 | [NFSD_FO_UnlockFS] = write_unlock_fs, |
@@ -121,6 +130,16 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu | |||
121 | 130 | ||
122 | static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) | 131 | static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) |
123 | { | 132 | { |
133 | #ifdef CONFIG_NFSD_DEPRECATED | ||
134 | static int warned; | ||
135 | if (file->f_dentry->d_name.name[0] == '.' && !warned) { | ||
136 | printk(KERN_INFO | ||
137 | "Warning: \"%s\" uses deprecated NFSD interface: %s." | ||
138 | " This will be removed in 2.6.40\n", | ||
139 | current->comm, file->f_dentry->d_name.name); | ||
140 | warned = 1; | ||
141 | } | ||
142 | #endif | ||
124 | if (! file->private_data) { | 143 | if (! file->private_data) { |
125 | /* An attempt to read a transaction file without writing | 144 | /* An attempt to read a transaction file without writing |
126 | * causes a 0-byte write so that the file can return | 145 | * causes a 0-byte write so that the file can return |
@@ -137,6 +156,7 @@ static const struct file_operations transaction_ops = { | |||
137 | .write = nfsctl_transaction_write, | 156 | .write = nfsctl_transaction_write, |
138 | .read = nfsctl_transaction_read, | 157 | .read = nfsctl_transaction_read, |
139 | .release = simple_transaction_release, | 158 | .release = simple_transaction_release, |
159 | .llseek = default_llseek, | ||
140 | }; | 160 | }; |
141 | 161 | ||
142 | static int exports_open(struct inode *inode, struct file *file) | 162 | static int exports_open(struct inode *inode, struct file *file) |
@@ -170,6 +190,26 @@ static struct file_operations export_features_operations = { | |||
170 | .release = single_release, | 190 | .release = single_release, |
171 | }; | 191 | }; |
172 | 192 | ||
193 | #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) | ||
194 | static int supported_enctypes_show(struct seq_file *m, void *v) | ||
195 | { | ||
196 | seq_printf(m, KRB5_SUPPORTED_ENCTYPES); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int supported_enctypes_open(struct inode *inode, struct file *file) | ||
201 | { | ||
202 | return single_open(file, supported_enctypes_show, NULL); | ||
203 | } | ||
204 | |||
205 | static struct file_operations supported_enctypes_ops = { | ||
206 | .open = supported_enctypes_open, | ||
207 | .read = seq_read, | ||
208 | .llseek = seq_lseek, | ||
209 | .release = single_release, | ||
210 | }; | ||
211 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ | ||
212 | |||
173 | extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); | 213 | extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); |
174 | extern int nfsd_pool_stats_release(struct inode *inode, struct file *file); | 214 | extern int nfsd_pool_stats_release(struct inode *inode, struct file *file); |
175 | 215 | ||
@@ -186,6 +226,7 @@ static const struct file_operations pool_stats_operations = { | |||
186 | * payload - write methods | 226 | * payload - write methods |
187 | */ | 227 | */ |
188 | 228 | ||
229 | #ifdef CONFIG_NFSD_DEPRECATED | ||
189 | /** | 230 | /** |
190 | * write_svc - Start kernel's NFSD server | 231 | * write_svc - Start kernel's NFSD server |
191 | * | 232 | * |
@@ -401,7 +442,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size) | |||
401 | 442 | ||
402 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); | 443 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); |
403 | 444 | ||
404 | clp = auth_unix_lookup(&in6); | 445 | clp = auth_unix_lookup(&init_net, &in6); |
405 | if (!clp) | 446 | if (!clp) |
406 | err = -EPERM; | 447 | err = -EPERM; |
407 | else { | 448 | else { |
@@ -464,7 +505,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
464 | 505 | ||
465 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); | 506 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); |
466 | 507 | ||
467 | clp = auth_unix_lookup(&in6); | 508 | clp = auth_unix_lookup(&init_net, &in6); |
468 | if (!clp) | 509 | if (!clp) |
469 | err = -EPERM; | 510 | err = -EPERM; |
470 | else { | 511 | else { |
@@ -481,6 +522,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
481 | out: | 522 | out: |
482 | return err; | 523 | return err; |
483 | } | 524 | } |
525 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
484 | 526 | ||
485 | /** | 527 | /** |
486 | * write_unlock_ip - Release all locks used by a client | 528 | * write_unlock_ip - Release all locks used by a client |
@@ -999,12 +1041,12 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
999 | if (err != 0) | 1041 | if (err != 0) |
1000 | return err; | 1042 | return err; |
1001 | 1043 | ||
1002 | err = svc_create_xprt(nfsd_serv, transport, | 1044 | err = svc_create_xprt(nfsd_serv, transport, &init_net, |
1003 | PF_INET, port, SVC_SOCK_ANONYMOUS); | 1045 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
1004 | if (err < 0) | 1046 | if (err < 0) |
1005 | goto out_err; | 1047 | goto out_err; |
1006 | 1048 | ||
1007 | err = svc_create_xprt(nfsd_serv, transport, | 1049 | err = svc_create_xprt(nfsd_serv, transport, &init_net, |
1008 | PF_INET6, port, SVC_SOCK_ANONYMOUS); | 1050 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
1009 | if (err < 0 && err != -EAFNOSUPPORT) | 1051 | if (err < 0 && err != -EAFNOSUPPORT) |
1010 | goto out_close; | 1052 | goto out_close; |
@@ -1355,6 +1397,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | |||
1355 | static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | 1397 | static int nfsd_fill_super(struct super_block * sb, void * data, int silent) |
1356 | { | 1398 | { |
1357 | static struct tree_descr nfsd_files[] = { | 1399 | static struct tree_descr nfsd_files[] = { |
1400 | #ifdef CONFIG_NFSD_DEPRECATED | ||
1358 | [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR}, | 1401 | [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR}, |
1359 | [NFSD_Add] = {".add", &transaction_ops, S_IWUSR}, | 1402 | [NFSD_Add] = {".add", &transaction_ops, S_IWUSR}, |
1360 | [NFSD_Del] = {".del", &transaction_ops, S_IWUSR}, | 1403 | [NFSD_Del] = {".del", &transaction_ops, S_IWUSR}, |
@@ -1362,6 +1405,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
1362 | [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR}, | 1405 | [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR}, |
1363 | [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, | 1406 | [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, |
1364 | [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, | 1407 | [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, |
1408 | #endif | ||
1365 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, | 1409 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, |
1366 | [NFSD_Export_features] = {"export_features", | 1410 | [NFSD_Export_features] = {"export_features", |
1367 | &export_features_operations, S_IRUGO}, | 1411 | &export_features_operations, S_IRUGO}, |
@@ -1376,6 +1420,9 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
1376 | [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, | 1420 | [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, |
1377 | [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, | 1421 | [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, |
1378 | [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, | 1422 | [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, |
1423 | #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) | ||
1424 | [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO}, | ||
1425 | #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ | ||
1379 | #ifdef CONFIG_NFSD_V4 | 1426 | #ifdef CONFIG_NFSD_V4 |
1380 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 1427 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
1381 | [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 1428 | [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
@@ -1386,16 +1433,16 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
1386 | return simple_fill_super(sb, 0x6e667364, nfsd_files); | 1433 | return simple_fill_super(sb, 0x6e667364, nfsd_files); |
1387 | } | 1434 | } |
1388 | 1435 | ||
1389 | static int nfsd_get_sb(struct file_system_type *fs_type, | 1436 | static struct dentry *nfsd_mount(struct file_system_type *fs_type, |
1390 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 1437 | int flags, const char *dev_name, void *data) |
1391 | { | 1438 | { |
1392 | return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt); | 1439 | return mount_single(fs_type, flags, data, nfsd_fill_super); |
1393 | } | 1440 | } |
1394 | 1441 | ||
1395 | static struct file_system_type nfsd_fs_type = { | 1442 | static struct file_system_type nfsd_fs_type = { |
1396 | .owner = THIS_MODULE, | 1443 | .owner = THIS_MODULE, |
1397 | .name = "nfsd", | 1444 | .name = "nfsd", |
1398 | .get_sb = nfsd_get_sb, | 1445 | .mount = nfsd_mount, |
1399 | .kill_sb = kill_litter_super, | 1446 | .kill_sb = kill_litter_super, |
1400 | }; | 1447 | }; |
1401 | 1448 | ||
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index b76ac3a82e39..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) |
@@ -249,7 +250,7 @@ extern time_t nfsd4_grace; | |||
249 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ | 250 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ |
250 | #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ | 251 | #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ |
251 | 252 | ||
252 | #define NFSD_LAUNDROMAT_MINTIMEOUT 10 /* seconds */ | 253 | #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ |
253 | 254 | ||
254 | /* | 255 | /* |
255 | * The following attributes are currently not supported by the NFSv4 server: | 256 | * The following attributes are currently not supported by the NFSv4 server: |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 55c8e63af0be..90c6aa6d5e0f 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -344,7 +344,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
344 | * which clients virtually always use auth_sys for, | 344 | * which clients virtually always use auth_sys for, |
345 | * even while using RPCSEC_GSS for NFS. | 345 | * even while using RPCSEC_GSS for NFS. |
346 | */ | 346 | */ |
347 | if (access & NFSD_MAY_LOCK) | 347 | if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS) |
348 | goto skip_pseudoflavor_check; | 348 | goto skip_pseudoflavor_check; |
349 | /* | 349 | /* |
350 | * Clients may expect to be able to use auth_sys during mount, | 350 | * Clients may expect to be able to use auth_sys during mount, |
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 e2c43464f237..18743c4d8bca 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/lockd/bind.h> | 16 | #include <linux/lockd/bind.h> |
17 | #include <linux/nfsacl.h> | 17 | #include <linux/nfsacl.h> |
18 | #include <linux/seq_file.h> | 18 | #include <linux/seq_file.h> |
19 | #include <net/net_namespace.h> | ||
19 | #include "nfsd.h" | 20 | #include "nfsd.h" |
20 | #include "cache.h" | 21 | #include "cache.h" |
21 | #include "vfs.h" | 22 | #include "vfs.h" |
@@ -186,12 +187,12 @@ static int nfsd_init_socks(int port) | |||
186 | if (!list_empty(&nfsd_serv->sv_permsocks)) | 187 | if (!list_empty(&nfsd_serv->sv_permsocks)) |
187 | return 0; | 188 | return 0; |
188 | 189 | ||
189 | error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port, | 190 | error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port, |
190 | SVC_SOCK_DEFAULTS); | 191 | SVC_SOCK_DEFAULTS); |
191 | if (error < 0) | 192 | if (error < 0) |
192 | return error; | 193 | return error; |
193 | 194 | ||
194 | error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port, | 195 | error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port, |
195 | SVC_SOCK_DEFAULTS); | 196 | SVC_SOCK_DEFAULTS); |
196 | if (error < 0) | 197 | if (error < 0) |
197 | return error; | 198 | return error; |
@@ -607,7 +608,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
607 | /* Now call the procedure handler, and encode NFS status. */ | 608 | /* Now call the procedure handler, and encode NFS status. */ |
608 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | 609 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); |
609 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); | 610 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); |
610 | if (nfserr == nfserr_dropit) { | 611 | if (nfserr == nfserr_dropit || rqstp->rq_dropme) { |
611 | dprintk("nfsd: Dropping request; may be revisited later\n"); | 612 | dprintk("nfsd: Dropping request; may be revisited later\n"); |
612 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); | 613 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
613 | return 0; | 614 | return 0; |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 4ce005dbf3e6..65ec595e2226 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -451,7 +451,7 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p, | |||
451 | *p++ = htonl(resp->count); | 451 | *p++ = htonl(resp->count); |
452 | xdr_ressize_check(rqstp, p); | 452 | xdr_ressize_check(rqstp, p); |
453 | 453 | ||
454 | /* now update rqstp->rq_res to reflect data aswell */ | 454 | /* now update rqstp->rq_res to reflect data as well */ |
455 | rqstp->rq_res.page_len = resp->count; | 455 | rqstp->rq_res.page_len = resp->count; |
456 | if (resp->count & 3) { | 456 | if (resp->count & 3) { |
457 | /* need to pad the tail */ | 457 | /* need to pad the tail */ |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 322518c88e4b..6bd2f3c21f2b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #ifndef _NFSD4_STATE_H | 35 | #ifndef _NFSD4_STATE_H |
36 | #define _NFSD4_STATE_H | 36 | #define _NFSD4_STATE_H |
37 | 37 | ||
38 | #include <linux/sunrpc/svc_xprt.h> | ||
38 | #include <linux/nfsd/nfsfh.h> | 39 | #include <linux/nfsd/nfsfh.h> |
39 | #include "nfsfh.h" | 40 | #include "nfsfh.h" |
40 | 41 | ||
@@ -64,20 +65,15 @@ typedef struct { | |||
64 | (s)->si_fileid, \ | 65 | (s)->si_fileid, \ |
65 | (s)->si_generation | 66 | (s)->si_generation |
66 | 67 | ||
67 | struct nfsd4_cb_sequence { | ||
68 | /* args/res */ | ||
69 | u32 cbs_minorversion; | ||
70 | struct nfs4_client *cbs_clp; | ||
71 | }; | ||
72 | |||
73 | struct nfs4_rpc_args { | ||
74 | void *args_op; | ||
75 | struct nfsd4_cb_sequence args_seq; | ||
76 | }; | ||
77 | |||
78 | struct nfsd4_callback { | 68 | struct nfsd4_callback { |
79 | struct nfs4_rpc_args cb_args; | 69 | void *cb_op; |
70 | struct nfs4_client *cb_clp; | ||
71 | struct list_head cb_per_client; | ||
72 | u32 cb_minorversion; | ||
73 | struct rpc_message cb_msg; | ||
74 | const struct rpc_call_ops *cb_ops; | ||
80 | struct work_struct cb_work; | 75 | struct work_struct cb_work; |
76 | bool cb_done; | ||
81 | }; | 77 | }; |
82 | 78 | ||
83 | struct nfs4_delegation { | 79 | struct nfs4_delegation { |
@@ -87,11 +83,9 @@ struct nfs4_delegation { | |||
87 | atomic_t dl_count; /* ref count */ | 83 | atomic_t dl_count; /* ref count */ |
88 | struct nfs4_client *dl_client; | 84 | struct nfs4_client *dl_client; |
89 | struct nfs4_file *dl_file; | 85 | struct nfs4_file *dl_file; |
90 | struct file_lock *dl_flock; | ||
91 | u32 dl_type; | 86 | u32 dl_type; |
92 | time_t dl_time; | 87 | time_t dl_time; |
93 | /* For recall: */ | 88 | /* For recall: */ |
94 | u32 dl_ident; | ||
95 | stateid_t dl_stateid; | 89 | stateid_t dl_stateid; |
96 | struct knfsd_fh dl_fh; | 90 | struct knfsd_fh dl_fh; |
97 | int dl_retries; | 91 | int dl_retries; |
@@ -102,9 +96,10 @@ struct nfs4_delegation { | |||
102 | struct nfs4_cb_conn { | 96 | struct nfs4_cb_conn { |
103 | /* SETCLIENTID info */ | 97 | /* SETCLIENTID info */ |
104 | struct sockaddr_storage cb_addr; | 98 | struct sockaddr_storage cb_addr; |
99 | struct sockaddr_storage cb_saddr; | ||
105 | size_t cb_addrlen; | 100 | size_t cb_addrlen; |
106 | u32 cb_prog; | 101 | u32 cb_prog; /* used only in 4.0 case; |
107 | u32 cb_minorversion; | 102 | per-session otherwise */ |
108 | u32 cb_ident; /* minorversion 0 only */ | 103 | u32 cb_ident; /* minorversion 0 only */ |
109 | struct svc_xprt *cb_xprt; /* minorversion 1 only */ | 104 | struct svc_xprt *cb_xprt; /* minorversion 1 only */ |
110 | }; | 105 | }; |
@@ -153,6 +148,11 @@ struct nfsd4_create_session { | |||
153 | u32 gid; | 148 | u32 gid; |
154 | }; | 149 | }; |
155 | 150 | ||
151 | struct nfsd4_bind_conn_to_session { | ||
152 | struct nfs4_sessionid sessionid; | ||
153 | u32 dir; | ||
154 | }; | ||
155 | |||
156 | /* The single slot clientid cache structure */ | 156 | /* The single slot clientid cache structure */ |
157 | struct nfsd4_clid_slot { | 157 | struct nfsd4_clid_slot { |
158 | u32 sl_seqid; | 158 | u32 sl_seqid; |
@@ -160,6 +160,15 @@ struct nfsd4_clid_slot { | |||
160 | struct nfsd4_create_session sl_cr_ses; | 160 | struct nfsd4_create_session sl_cr_ses; |
161 | }; | 161 | }; |
162 | 162 | ||
163 | struct nfsd4_conn { | ||
164 | struct list_head cn_persession; | ||
165 | struct svc_xprt *cn_xprt; | ||
166 | struct svc_xpt_user cn_xpt_user; | ||
167 | struct nfsd4_session *cn_session; | ||
168 | /* CDFC4_FORE, CDFC4_BACK: */ | ||
169 | unsigned char cn_flags; | ||
170 | }; | ||
171 | |||
163 | struct nfsd4_session { | 172 | struct nfsd4_session { |
164 | struct kref se_ref; | 173 | struct kref se_ref; |
165 | struct list_head se_hash; /* hash by sessionid */ | 174 | struct list_head se_hash; /* hash by sessionid */ |
@@ -169,6 +178,9 @@ struct nfsd4_session { | |||
169 | struct nfs4_sessionid se_sessionid; | 178 | struct nfs4_sessionid se_sessionid; |
170 | struct nfsd4_channel_attrs se_fchannel; | 179 | struct nfsd4_channel_attrs se_fchannel; |
171 | struct nfsd4_channel_attrs se_bchannel; | 180 | struct nfsd4_channel_attrs se_bchannel; |
181 | struct list_head se_conns; | ||
182 | u32 se_cb_prog; | ||
183 | u32 se_cb_seq_nr; | ||
172 | struct nfsd4_slot *se_slots[]; /* forward channel slots */ | 184 | struct nfsd4_slot *se_slots[]; /* forward channel slots */ |
173 | }; | 185 | }; |
174 | 186 | ||
@@ -221,24 +233,36 @@ struct nfs4_client { | |||
221 | clientid_t cl_clientid; /* generated by server */ | 233 | clientid_t cl_clientid; /* generated by server */ |
222 | nfs4_verifier cl_confirm; /* generated by server */ | 234 | nfs4_verifier cl_confirm; /* generated by server */ |
223 | u32 cl_firststate; /* recovery dir creation */ | 235 | u32 cl_firststate; /* recovery dir creation */ |
236 | u32 cl_minorversion; | ||
224 | 237 | ||
225 | /* for v4.0 and v4.1 callbacks: */ | 238 | /* for v4.0 and v4.1 callbacks: */ |
226 | struct nfs4_cb_conn cl_cb_conn; | 239 | struct nfs4_cb_conn cl_cb_conn; |
240 | #define NFSD4_CLIENT_CB_UPDATE 1 | ||
241 | #define NFSD4_CLIENT_KILL 2 | ||
242 | unsigned long cl_cb_flags; | ||
227 | struct rpc_clnt *cl_cb_client; | 243 | struct rpc_clnt *cl_cb_client; |
228 | atomic_t cl_cb_set; | 244 | u32 cl_cb_ident; |
245 | #define NFSD4_CB_UP 0 | ||
246 | #define NFSD4_CB_UNKNOWN 1 | ||
247 | #define NFSD4_CB_DOWN 2 | ||
248 | int cl_cb_state; | ||
249 | struct nfsd4_callback cl_cb_null; | ||
250 | struct nfsd4_session *cl_cb_session; | ||
251 | struct list_head cl_callbacks; /* list of in-progress callbacks */ | ||
252 | |||
253 | /* for all client information that callback code might need: */ | ||
254 | spinlock_t cl_lock; | ||
229 | 255 | ||
230 | /* for nfs41 */ | 256 | /* for nfs41 */ |
231 | struct list_head cl_sessions; | 257 | struct list_head cl_sessions; |
232 | struct nfsd4_clid_slot cl_cs_slot; /* create_session slot */ | 258 | struct nfsd4_clid_slot cl_cs_slot; /* create_session slot */ |
233 | u32 cl_exchange_flags; | 259 | u32 cl_exchange_flags; |
234 | struct nfs4_sessionid cl_sessionid; | ||
235 | /* number of rpc's in progress over an associated session: */ | 260 | /* number of rpc's in progress over an associated session: */ |
236 | atomic_t cl_refcount; | 261 | atomic_t cl_refcount; |
237 | 262 | ||
238 | /* for nfs41 callbacks */ | 263 | /* for nfs41 callbacks */ |
239 | /* We currently support a single back channel with a single slot */ | 264 | /* We currently support a single back channel with a single slot */ |
240 | unsigned long cl_cb_slot_busy; | 265 | unsigned long cl_cb_slot_busy; |
241 | u32 cl_cb_seq_nr; | ||
242 | struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */ | 266 | struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */ |
243 | /* wait here for slots */ | 267 | /* wait here for slots */ |
244 | }; | 268 | }; |
@@ -343,16 +367,15 @@ struct nfs4_file { | |||
343 | struct list_head fi_delegations; | 367 | struct list_head fi_delegations; |
344 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ | 368 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ |
345 | struct file * fi_fds[3]; | 369 | struct file * fi_fds[3]; |
346 | /* One each for O_RDONLY, O_WRONLY: */ | ||
347 | atomic_t fi_access[2]; | ||
348 | /* | 370 | /* |
349 | * Each open stateid contributes 1 to either fi_readers or | 371 | * Each open or lock stateid contributes 1 to either |
350 | * fi_writers, or both, depending on the open mode. A | 372 | * fi_access[O_RDONLY], fi_access[O_WRONLY], or both, depending |
351 | * delegation also takes an fi_readers reference. Lock | 373 | * on open or lock mode: |
352 | * stateid's take none. | ||
353 | */ | 374 | */ |
354 | atomic_t fi_readers; | 375 | atomic_t fi_access[2]; |
355 | atomic_t fi_writers; | 376 | struct file *fi_deleg_file; |
377 | struct file_lock *fi_lease; | ||
378 | atomic_t fi_delegees; | ||
356 | struct inode *fi_inode; | 379 | struct inode *fi_inode; |
357 | u32 fi_id; /* used with stateowner->so_id | 380 | u32 fi_id; /* used with stateowner->so_id |
358 | * for stateid_hashtbl hash */ | 381 | * for stateid_hashtbl hash */ |
@@ -440,12 +463,14 @@ extern int nfs4_in_grace(void); | |||
440 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid); | 463 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid); |
441 | extern void nfs4_free_stateowner(struct kref *kref); | 464 | extern void nfs4_free_stateowner(struct kref *kref); |
442 | extern int set_callback_cred(void); | 465 | extern int set_callback_cred(void); |
443 | extern void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); | 466 | extern void nfsd4_probe_callback(struct nfs4_client *clp); |
467 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); | ||
468 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); | ||
444 | extern void nfsd4_do_callback_rpc(struct work_struct *); | 469 | extern void nfsd4_do_callback_rpc(struct work_struct *); |
445 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); | 470 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); |
446 | extern int nfsd4_create_callback_queue(void); | 471 | extern int nfsd4_create_callback_queue(void); |
447 | extern void nfsd4_destroy_callback_queue(void); | 472 | extern void nfsd4_destroy_callback_queue(void); |
448 | extern void nfsd4_set_callback_client(struct nfs4_client *, struct rpc_clnt *); | 473 | extern void nfsd4_shutdown_callback(struct nfs4_client *); |
449 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); | 474 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); |
450 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); | 475 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); |
451 | extern void nfsd4_init_recdir(char *recdir_name); | 476 | extern void nfsd4_init_recdir(char *recdir_name); |
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c index 5232d3e8fb2f..a2e2402b2afb 100644 --- a/fs/nfsd/stats.c +++ b/fs/nfsd/stats.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * Statistsics for the reply cache | 8 | * Statistsics for the reply cache |
9 | * fh <stale> <total-lookups> <anonlookups> <dir-not-in-dcache> <nondir-not-in-dcache> | 9 | * fh <stale> <total-lookups> <anonlookups> <dir-not-in-dcache> <nondir-not-in-dcache> |
10 | * statistics for filehandle lookup | 10 | * statistics for filehandle lookup |
11 | * io <bytes-read> <bytes-writtten> | 11 | * io <bytes-read> <bytes-written> |
12 | * statistics for IO throughput | 12 | * statistics for IO throughput |
13 | * th <threads> <fullcnt> <10%-20%> <20%-30%> ... <90%-100%> <100%> | 13 | * th <threads> <fullcnt> <10%-20%> <20%-30%> ... <90%-100%> <100%> |
14 | * time (seconds) when nfsd thread usage above thresholds | 14 | * time (seconds) when nfsd thread usage above thresholds |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 661a6cf8e826..fd0acca5370a 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" |
@@ -88,8 +87,9 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
88 | .dentry = dget(dentry)}; | 87 | .dentry = dget(dentry)}; |
89 | int err = 0; | 88 | int err = 0; |
90 | 89 | ||
91 | while (d_mountpoint(path.dentry) && follow_down(&path)) | 90 | err = follow_down(&path); |
92 | ; | 91 | if (err < 0) |
92 | goto out; | ||
93 | 93 | ||
94 | exp2 = rqst_exp_get_by_name(rqstp, &path); | 94 | exp2 = rqst_exp_get_by_name(rqstp, &path); |
95 | if (IS_ERR(exp2)) { | 95 | if (IS_ERR(exp2)) { |
@@ -181,16 +181,10 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
181 | struct svc_export *exp; | 181 | struct svc_export *exp; |
182 | struct dentry *dparent; | 182 | struct dentry *dparent; |
183 | struct dentry *dentry; | 183 | struct dentry *dentry; |
184 | __be32 err; | ||
185 | int host_err; | 184 | int host_err; |
186 | 185 | ||
187 | dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); | 186 | dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); |
188 | 187 | ||
189 | /* Obtain dentry and export. */ | ||
190 | err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); | ||
191 | if (err) | ||
192 | return err; | ||
193 | |||
194 | dparent = fhp->fh_dentry; | 188 | dparent = fhp->fh_dentry; |
195 | exp = fhp->fh_export; | 189 | exp = fhp->fh_export; |
196 | exp_get(exp); | 190 | exp_get(exp); |
@@ -254,6 +248,9 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |||
254 | struct dentry *dentry; | 248 | struct dentry *dentry; |
255 | __be32 err; | 249 | __be32 err; |
256 | 250 | ||
251 | err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); | ||
252 | if (err) | ||
253 | return err; | ||
257 | err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry); | 254 | err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry); |
258 | if (err) | 255 | if (err) |
259 | return err; | 256 | return err; |
@@ -273,6 +270,13 @@ out: | |||
273 | return err; | 270 | return err; |
274 | } | 271 | } |
275 | 272 | ||
273 | static int nfsd_break_lease(struct inode *inode) | ||
274 | { | ||
275 | if (!S_ISREG(inode->i_mode)) | ||
276 | return 0; | ||
277 | return break_lease(inode, O_WRONLY | O_NONBLOCK); | ||
278 | } | ||
279 | |||
276 | /* | 280 | /* |
277 | * Commit metadata changes to stable storage. | 281 | * Commit metadata changes to stable storage. |
278 | */ | 282 | */ |
@@ -281,23 +285,13 @@ commit_metadata(struct svc_fh *fhp) | |||
281 | { | 285 | { |
282 | struct inode *inode = fhp->fh_dentry->d_inode; | 286 | struct inode *inode = fhp->fh_dentry->d_inode; |
283 | const struct export_operations *export_ops = inode->i_sb->s_export_op; | 287 | const struct export_operations *export_ops = inode->i_sb->s_export_op; |
284 | int error = 0; | ||
285 | 288 | ||
286 | if (!EX_ISSYNC(fhp->fh_export)) | 289 | if (!EX_ISSYNC(fhp->fh_export)) |
287 | return 0; | 290 | return 0; |
288 | 291 | ||
289 | if (export_ops->commit_metadata) { | 292 | if (export_ops->commit_metadata) |
290 | error = export_ops->commit_metadata(inode); | 293 | return export_ops->commit_metadata(inode); |
291 | } else { | 294 | return sync_inode_metadata(inode, 1); |
292 | struct writeback_control wbc = { | ||
293 | .sync_mode = WB_SYNC_ALL, | ||
294 | .nr_to_write = 0, /* metadata only */ | ||
295 | }; | ||
296 | |||
297 | error = sync_inode(inode, &wbc); | ||
298 | } | ||
299 | |||
300 | return error; | ||
301 | } | 295 | } |
302 | 296 | ||
303 | /* | 297 | /* |
@@ -385,16 +379,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
385 | goto out; | 379 | goto out; |
386 | } | 380 | } |
387 | 381 | ||
388 | /* | ||
389 | * If we are changing the size of the file, then | ||
390 | * we need to break all leases. | ||
391 | */ | ||
392 | host_err = break_lease(inode, O_WRONLY | O_NONBLOCK); | ||
393 | if (host_err == -EWOULDBLOCK) | ||
394 | host_err = -ETIMEDOUT; | ||
395 | if (host_err) /* ENOMEM or EWOULDBLOCK */ | ||
396 | goto out_nfserr; | ||
397 | |||
398 | host_err = get_write_access(inode); | 382 | host_err = get_write_access(inode); |
399 | if (host_err) | 383 | if (host_err) |
400 | goto out_nfserr; | 384 | goto out_nfserr; |
@@ -435,7 +419,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
435 | 419 | ||
436 | err = nfserr_notsync; | 420 | err = nfserr_notsync; |
437 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { | 421 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { |
422 | host_err = nfsd_break_lease(inode); | ||
423 | if (host_err) | ||
424 | goto out_nfserr; | ||
438 | fh_lock(fhp); | 425 | fh_lock(fhp); |
426 | |||
439 | host_err = notify_change(dentry, iap); | 427 | host_err = notify_change(dentry, iap); |
440 | err = nfserrno(host_err); | 428 | err = nfserrno(host_err); |
441 | fh_unlock(fhp); | 429 | fh_unlock(fhp); |
@@ -708,7 +696,15 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor | |||
708 | } | 696 | } |
709 | #endif /* CONFIG_NFSD_V3 */ | 697 | #endif /* CONFIG_NFSD_V3 */ |
710 | 698 | ||
699 | static int nfsd_open_break_lease(struct inode *inode, int access) | ||
700 | { | ||
701 | unsigned int mode; | ||
711 | 702 | ||
703 | if (access & NFSD_MAY_NOT_BREAK_LEASE) | ||
704 | return 0; | ||
705 | mode = (access & NFSD_MAY_WRITE) ? O_WRONLY : O_RDONLY; | ||
706 | return break_lease(inode, mode | O_NONBLOCK); | ||
707 | } | ||
712 | 708 | ||
713 | /* | 709 | /* |
714 | * Open an existing file or directory. | 710 | * Open an existing file or directory. |
@@ -756,14 +752,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
756 | if (!inode->i_fop) | 752 | if (!inode->i_fop) |
757 | goto out; | 753 | goto out; |
758 | 754 | ||
759 | /* | 755 | host_err = nfsd_open_break_lease(inode, access); |
760 | * Check to see if there are any leases on this file. | ||
761 | * This may block while leases are broken. | ||
762 | */ | ||
763 | if (!(access & NFSD_MAY_NOT_BREAK_LEASE)) | ||
764 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); | ||
765 | if (host_err == -EWOULDBLOCK) | ||
766 | host_err = -ETIMEDOUT; | ||
767 | if (host_err) /* NOMEM or WOULDBLOCK */ | 756 | if (host_err) /* NOMEM or WOULDBLOCK */ |
768 | goto out_nfserr; | 757 | goto out_nfserr; |
769 | 758 | ||
@@ -819,7 +808,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino) | |||
819 | if (ra->p_count == 0) | 808 | if (ra->p_count == 0) |
820 | frap = rap; | 809 | frap = rap; |
821 | } | 810 | } |
822 | depth = nfsdstats.ra_size*11/10; | 811 | depth = nfsdstats.ra_size; |
823 | if (!frap) { | 812 | if (!frap) { |
824 | spin_unlock(&rab->pb_lock); | 813 | spin_unlock(&rab->pb_lock); |
825 | return NULL; | 814 | return NULL; |
@@ -855,11 +844,6 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
855 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; | 844 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; |
856 | struct page *page = buf->page; | 845 | struct page *page = buf->page; |
857 | size_t size; | 846 | size_t size; |
858 | int ret; | ||
859 | |||
860 | ret = buf->ops->confirm(pipe, buf); | ||
861 | if (unlikely(ret)) | ||
862 | return ret; | ||
863 | 847 | ||
864 | size = sd->len; | 848 | size = sd->len; |
865 | 849 | ||
@@ -889,29 +873,15 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, | |||
889 | return __splice_from_pipe(pipe, sd, nfsd_splice_actor); | 873 | return __splice_from_pipe(pipe, sd, nfsd_splice_actor); |
890 | } | 874 | } |
891 | 875 | ||
892 | static inline int svc_msnfs(struct svc_fh *ffhp) | ||
893 | { | ||
894 | #ifdef MSNFS | ||
895 | return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS); | ||
896 | #else | ||
897 | return 0; | ||
898 | #endif | ||
899 | } | ||
900 | |||
901 | static __be32 | 876 | static __be32 |
902 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 877 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
903 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | 878 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
904 | { | 879 | { |
905 | struct inode *inode; | ||
906 | mm_segment_t oldfs; | 880 | mm_segment_t oldfs; |
907 | __be32 err; | 881 | __be32 err; |
908 | int host_err; | 882 | int host_err; |
909 | 883 | ||
910 | err = nfserr_perm; | 884 | err = nfserr_perm; |
911 | inode = file->f_path.dentry->d_inode; | ||
912 | |||
913 | if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) | ||
914 | goto out; | ||
915 | 885 | ||
916 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { | 886 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { |
917 | struct splice_desc sd = { | 887 | struct splice_desc sd = { |
@@ -937,7 +907,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
937 | fsnotify_access(file); | 907 | fsnotify_access(file); |
938 | } else | 908 | } else |
939 | err = nfserrno(host_err); | 909 | err = nfserrno(host_err); |
940 | out: | ||
941 | return err; | 910 | return err; |
942 | } | 911 | } |
943 | 912 | ||
@@ -1002,14 +971,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1002 | int stable = *stablep; | 971 | int stable = *stablep; |
1003 | int use_wgather; | 972 | int use_wgather; |
1004 | 973 | ||
1005 | #ifdef MSNFS | ||
1006 | err = nfserr_perm; | ||
1007 | |||
1008 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | ||
1009 | (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt))) | ||
1010 | goto out; | ||
1011 | #endif | ||
1012 | |||
1013 | dentry = file->f_path.dentry; | 974 | dentry = file->f_path.dentry; |
1014 | inode = dentry->d_inode; | 975 | inode = dentry->d_inode; |
1015 | exp = fhp->fh_export; | 976 | exp = fhp->fh_export; |
@@ -1060,7 +1021,6 @@ out_nfserr: | |||
1060 | err = 0; | 1021 | err = 0; |
1061 | else | 1022 | else |
1062 | err = nfserrno(host_err); | 1023 | err = nfserrno(host_err); |
1063 | out: | ||
1064 | return err; | 1024 | return err; |
1065 | } | 1025 | } |
1066 | 1026 | ||
@@ -1378,11 +1338,18 @@ out_nfserr: | |||
1378 | } | 1338 | } |
1379 | 1339 | ||
1380 | #ifdef CONFIG_NFSD_V3 | 1340 | #ifdef CONFIG_NFSD_V3 |
1341 | |||
1342 | static inline int nfsd_create_is_exclusive(int createmode) | ||
1343 | { | ||
1344 | return createmode == NFS3_CREATE_EXCLUSIVE | ||
1345 | || createmode == NFS4_CREATE_EXCLUSIVE4_1; | ||
1346 | } | ||
1347 | |||
1381 | /* | 1348 | /* |
1382 | * NFSv3 version of nfsd_create | 1349 | * NFSv3 and NFSv4 version of nfsd_create |
1383 | */ | 1350 | */ |
1384 | __be32 | 1351 | __be32 |
1385 | nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | 1352 | do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, |
1386 | char *fname, int flen, struct iattr *iap, | 1353 | char *fname, int flen, struct iattr *iap, |
1387 | struct svc_fh *resfhp, int createmode, u32 *verifier, | 1354 | struct svc_fh *resfhp, int createmode, u32 *verifier, |
1388 | int *truncp, int *created) | 1355 | int *truncp, int *created) |
@@ -1401,7 +1368,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1401 | goto out; | 1368 | goto out; |
1402 | if (!(iap->ia_valid & ATTR_MODE)) | 1369 | if (!(iap->ia_valid & ATTR_MODE)) |
1403 | iap->ia_mode = 0; | 1370 | iap->ia_mode = 0; |
1404 | err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); | 1371 | err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); |
1405 | if (err) | 1372 | if (err) |
1406 | goto out; | 1373 | goto out; |
1407 | 1374 | ||
@@ -1423,11 +1390,18 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1423 | if (IS_ERR(dchild)) | 1390 | if (IS_ERR(dchild)) |
1424 | goto out_nfserr; | 1391 | goto out_nfserr; |
1425 | 1392 | ||
1393 | /* If file doesn't exist, check for permissions to create one */ | ||
1394 | if (!dchild->d_inode) { | ||
1395 | err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); | ||
1396 | if (err) | ||
1397 | goto out; | ||
1398 | } | ||
1399 | |||
1426 | err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); | 1400 | err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); |
1427 | if (err) | 1401 | if (err) |
1428 | goto out; | 1402 | goto out; |
1429 | 1403 | ||
1430 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1404 | if (nfsd_create_is_exclusive(createmode)) { |
1431 | /* solaris7 gets confused (bugid 4218508) if these have | 1405 | /* solaris7 gets confused (bugid 4218508) if these have |
1432 | * the high bit set, so just clear the high bits. If this is | 1406 | * the high bit set, so just clear the high bits. If this is |
1433 | * ever changed to use different attrs for storing the | 1407 | * ever changed to use different attrs for storing the |
@@ -1468,6 +1442,11 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1468 | && dchild->d_inode->i_atime.tv_sec == v_atime | 1442 | && dchild->d_inode->i_atime.tv_sec == v_atime |
1469 | && dchild->d_inode->i_size == 0 ) | 1443 | && dchild->d_inode->i_size == 0 ) |
1470 | break; | 1444 | break; |
1445 | case NFS4_CREATE_EXCLUSIVE4_1: | ||
1446 | if ( dchild->d_inode->i_mtime.tv_sec == v_mtime | ||
1447 | && dchild->d_inode->i_atime.tv_sec == v_atime | ||
1448 | && dchild->d_inode->i_size == 0 ) | ||
1449 | goto set_attr; | ||
1471 | /* fallthru */ | 1450 | /* fallthru */ |
1472 | case NFS3_CREATE_GUARDED: | 1451 | case NFS3_CREATE_GUARDED: |
1473 | err = nfserr_exist; | 1452 | err = nfserr_exist; |
@@ -1486,7 +1465,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1486 | 1465 | ||
1487 | nfsd_check_ignore_resizing(iap); | 1466 | nfsd_check_ignore_resizing(iap); |
1488 | 1467 | ||
1489 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1468 | if (nfsd_create_is_exclusive(createmode)) { |
1490 | /* Cram the verifier into atime/mtime */ | 1469 | /* Cram the verifier into atime/mtime */ |
1491 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME | 1470 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME |
1492 | | ATTR_MTIME_SET|ATTR_ATIME_SET; | 1471 | | ATTR_MTIME_SET|ATTR_ATIME_SET; |
@@ -1680,6 +1659,14 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1680 | err = nfserrno(host_err); | 1659 | err = nfserrno(host_err); |
1681 | goto out_dput; | 1660 | goto out_dput; |
1682 | } | 1661 | } |
1662 | err = nfserr_noent; | ||
1663 | if (!dold->d_inode) | ||
1664 | goto out_drop_write; | ||
1665 | host_err = nfsd_break_lease(dold->d_inode); | ||
1666 | if (host_err) { | ||
1667 | err = nfserrno(host_err); | ||
1668 | goto out_drop_write; | ||
1669 | } | ||
1683 | host_err = vfs_link(dold, dirp, dnew); | 1670 | host_err = vfs_link(dold, dirp, dnew); |
1684 | if (!host_err) { | 1671 | if (!host_err) { |
1685 | err = nfserrno(commit_metadata(ffhp)); | 1672 | err = nfserrno(commit_metadata(ffhp)); |
@@ -1691,6 +1678,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1691 | else | 1678 | else |
1692 | err = nfserrno(host_err); | 1679 | err = nfserrno(host_err); |
1693 | } | 1680 | } |
1681 | out_drop_write: | ||
1694 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); | 1682 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); |
1695 | out_dput: | 1683 | out_dput: |
1696 | dput(dnew); | 1684 | dput(dnew); |
@@ -1765,13 +1753,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1765 | if (ndentry == trap) | 1753 | if (ndentry == trap) |
1766 | goto out_dput_new; | 1754 | goto out_dput_new; |
1767 | 1755 | ||
1768 | if (svc_msnfs(ffhp) && | ||
1769 | ((atomic_read(&odentry->d_count) > 1) | ||
1770 | || (atomic_read(&ndentry->d_count) > 1))) { | ||
1771 | host_err = -EPERM; | ||
1772 | goto out_dput_new; | ||
1773 | } | ||
1774 | |||
1775 | host_err = -EXDEV; | 1756 | host_err = -EXDEV; |
1776 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) | 1757 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) |
1777 | goto out_dput_new; | 1758 | goto out_dput_new; |
@@ -1779,15 +1760,22 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1779 | if (host_err) | 1760 | if (host_err) |
1780 | goto out_dput_new; | 1761 | goto out_dput_new; |
1781 | 1762 | ||
1763 | host_err = nfsd_break_lease(odentry->d_inode); | ||
1764 | if (host_err) | ||
1765 | goto out_drop_write; | ||
1766 | if (ndentry->d_inode) { | ||
1767 | host_err = nfsd_break_lease(ndentry->d_inode); | ||
1768 | if (host_err) | ||
1769 | goto out_drop_write; | ||
1770 | } | ||
1782 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1771 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1783 | if (!host_err) { | 1772 | if (!host_err) { |
1784 | host_err = commit_metadata(tfhp); | 1773 | host_err = commit_metadata(tfhp); |
1785 | if (!host_err) | 1774 | if (!host_err) |
1786 | host_err = commit_metadata(ffhp); | 1775 | host_err = commit_metadata(ffhp); |
1787 | } | 1776 | } |
1788 | 1777 | out_drop_write: | |
1789 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 1778 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); |
1790 | |||
1791 | out_dput_new: | 1779 | out_dput_new: |
1792 | dput(ndentry); | 1780 | dput(ndentry); |
1793 | out_dput_old: | 1781 | out_dput_old: |
@@ -1848,26 +1836,22 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1848 | 1836 | ||
1849 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | 1837 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); |
1850 | if (host_err) | 1838 | if (host_err) |
1851 | goto out_nfserr; | 1839 | goto out_put; |
1852 | 1840 | ||
1853 | if (type != S_IFDIR) { /* It's UNLINK */ | 1841 | host_err = nfsd_break_lease(rdentry->d_inode); |
1854 | #ifdef MSNFS | 1842 | if (host_err) |
1855 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1843 | goto out_drop_write; |
1856 | (atomic_read(&rdentry->d_count) > 1)) { | 1844 | if (type != S_IFDIR) |
1857 | host_err = -EPERM; | ||
1858 | } else | ||
1859 | #endif | ||
1860 | host_err = vfs_unlink(dirp, rdentry); | 1845 | host_err = vfs_unlink(dirp, rdentry); |
1861 | } else { /* It's RMDIR */ | 1846 | else |
1862 | host_err = vfs_rmdir(dirp, rdentry); | 1847 | host_err = vfs_rmdir(dirp, rdentry); |
1863 | } | ||
1864 | |||
1865 | dput(rdentry); | ||
1866 | |||
1867 | if (!host_err) | 1848 | if (!host_err) |
1868 | host_err = commit_metadata(fhp); | 1849 | host_err = commit_metadata(fhp); |
1869 | 1850 | out_drop_write: | |
1870 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1851 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1852 | out_put: | ||
1853 | dput(rdentry); | ||
1854 | |||
1871 | out_nfserr: | 1855 | out_nfserr: |
1872 | err = nfserrno(host_err); | 1856 | err = nfserrno(host_err); |
1873 | out: | 1857 | out: |
@@ -2062,7 +2046,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2062 | struct inode *inode = dentry->d_inode; | 2046 | struct inode *inode = dentry->d_inode; |
2063 | int err; | 2047 | int err; |
2064 | 2048 | ||
2065 | if (acc == NFSD_MAY_NOP) | 2049 | if ((acc & NFSD_MAY_MASK) == NFSD_MAY_NOP) |
2066 | return 0; | 2050 | return 0; |
2067 | #if 0 | 2051 | #if 0 |
2068 | dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", | 2052 | dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", |
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 9a370a5e36b7..e0bbac04d1dd 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -17,10 +17,14 @@ | |||
17 | #define NFSD_MAY_SATTR 8 | 17 | #define NFSD_MAY_SATTR 8 |
18 | #define NFSD_MAY_TRUNC 16 | 18 | #define NFSD_MAY_TRUNC 16 |
19 | #define NFSD_MAY_LOCK 32 | 19 | #define NFSD_MAY_LOCK 32 |
20 | #define NFSD_MAY_MASK 63 | ||
21 | |||
22 | /* extra hints to permission and open routines: */ | ||
20 | #define NFSD_MAY_OWNER_OVERRIDE 64 | 23 | #define NFSD_MAY_OWNER_OVERRIDE 64 |
21 | #define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/ | 24 | #define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/ |
22 | #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256 | 25 | #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256 |
23 | #define NFSD_MAY_NOT_BREAK_LEASE 512 | 26 | #define NFSD_MAY_NOT_BREAK_LEASE 512 |
27 | #define NFSD_MAY_BYPASS_GSS 1024 | ||
24 | 28 | ||
25 | #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) | 29 | #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) |
26 | #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) | 30 | #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) |
@@ -54,7 +58,7 @@ __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, | |||
54 | int type, dev_t rdev, struct svc_fh *res); | 58 | int type, dev_t rdev, struct svc_fh *res); |
55 | #ifdef CONFIG_NFSD_V3 | 59 | #ifdef CONFIG_NFSD_V3 |
56 | __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); | 60 | __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); |
57 | __be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *, | 61 | __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, |
58 | char *name, int len, struct iattr *attrs, | 62 | char *name, int len, struct iattr *attrs, |
59 | struct svc_fh *res, int createmode, | 63 | struct svc_fh *res, int createmode, |
60 | u32 *verifier, int *truncp, int *created); | 64 | u32 *verifier, int *truncp, int *created); |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 4d476ff08ae6..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; |
@@ -484,18 +490,17 @@ static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) | |||
484 | static inline void | 490 | static inline void |
485 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) | 491 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) |
486 | { | 492 | { |
487 | BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved); | 493 | BUG_ON(!fhp->fh_pre_saved); |
488 | cinfo->atomic = 1; | 494 | cinfo->atomic = fhp->fh_post_saved; |
489 | cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); | 495 | cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); |
490 | if (cinfo->change_supported) { | 496 | |
491 | cinfo->before_change = fhp->fh_pre_change; | 497 | cinfo->before_change = fhp->fh_pre_change; |
492 | cinfo->after_change = fhp->fh_post_change; | 498 | cinfo->after_change = fhp->fh_post_change; |
493 | } else { | 499 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; |
494 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; | 500 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; |
495 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; | 501 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; |
496 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; | 502 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; |
497 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; | 503 | |
498 | } | ||
499 | } | 504 | } |
500 | 505 | ||
501 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); | 506 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); |
@@ -519,6 +524,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
519 | struct nfsd4_sequence *seq); | 524 | struct nfsd4_sequence *seq); |
520 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, | 525 | extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, |
521 | 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 *); | ||
522 | extern __be32 nfsd4_create_session(struct svc_rqst *, | 528 | extern __be32 nfsd4_create_session(struct svc_rqst *, |
523 | struct nfsd4_compound_state *, | 529 | struct nfsd4_compound_state *, |
524 | struct nfsd4_create_session *); | 530 | struct nfsd4_create_session *); |