aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/Kconfig12
-rw-r--r--fs/nfsd/cache.h2
-rw-r--r--fs/nfsd/export.c418
-rw-r--r--fs/nfsd/lockd.c2
-rw-r--r--fs/nfsd/nfs4proc.c64
-rw-r--r--fs/nfsd/nfs4recover.c54
-rw-r--r--fs/nfsd/nfs4state.c291
-rw-r--r--fs/nfsd/nfs4xdr.c156
-rw-r--r--fs/nfsd/nfscache.c3
-rw-r--r--fs/nfsd/nfsctl.c343
-rw-r--r--fs/nfsd/nfssvc.c33
-rw-r--r--fs/nfsd/state.h7
-rw-r--r--fs/nfsd/vfs.c3
-rw-r--r--fs/nfsd/vfs.h1
-rw-r--r--fs/nfsd/xdr4.h30
15 files changed, 508 insertions, 911 deletions
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index fbb2a5ef581..10e6366608f 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -28,18 +28,6 @@ config NFSD
28 28
29 If unsure, say N. 29 If unsure, say N.
30 30
31config 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
43config NFSD_V2_ACL 31config NFSD_V2_ACL
44 bool 32 bool
45 depends on NFSD 33 depends on NFSD
diff --git a/fs/nfsd/cache.h b/fs/nfsd/cache.h
index d892be61016..93cc9d34c45 100644
--- a/fs/nfsd/cache.h
+++ b/fs/nfsd/cache.h
@@ -69,7 +69,7 @@ enum {
69 69
70int nfsd_reply_cache_init(void); 70int nfsd_reply_cache_init(void);
71void nfsd_reply_cache_shutdown(void); 71void nfsd_reply_cache_shutdown(void);
72int nfsd_cache_lookup(struct svc_rqst *, int); 72int nfsd_cache_lookup(struct svc_rqst *);
73void nfsd_cache_update(struct svc_rqst *, int, __be32 *); 73void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
74 74
75#ifdef CONFIG_NFSD_V4 75#ifdef CONFIG_NFSD_V4
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index b9566e46219..f4cc1e2bfc5 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -797,58 +797,6 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
797 return ek; 797 return ek;
798} 798}
799 799
800#ifdef CONFIG_NFSD_DEPRECATED
801static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
802 struct svc_export *exp)
803{
804 struct svc_expkey key, *ek;
805
806 key.ek_client = clp;
807 key.ek_fsidtype = fsid_type;
808 memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
809 key.ek_path = exp->ex_path;
810 key.h.expiry_time = NEVER;
811 key.h.flags = 0;
812
813 ek = svc_expkey_lookup(&key);
814 if (ek)
815 ek = svc_expkey_update(&key,ek);
816 if (ek) {
817 cache_put(&ek->h, &svc_expkey_cache);
818 return 0;
819 }
820 return -ENOMEM;
821}
822
823/*
824 * Find the client's export entry matching xdev/xino.
825 */
826static inline struct svc_expkey *
827exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
828{
829 u32 fsidv[3];
830
831 if (old_valid_dev(dev)) {
832 mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL);
833 return exp_find_key(clp, FSID_DEV, fsidv, NULL);
834 }
835 mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL);
836 return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL);
837}
838
839/*
840 * Find the client's export entry matching fsid
841 */
842static inline struct svc_expkey *
843exp_get_fsid_key(svc_client *clp, int fsid)
844{
845 u32 fsidv[2];
846
847 mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL);
848
849 return exp_find_key(clp, FSID_NUM, fsidv, NULL);
850}
851#endif
852 800
853static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, 801static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
854 struct cache_req *reqp) 802 struct cache_req *reqp)
@@ -890,275 +838,7 @@ static struct svc_export *exp_parent(svc_client *clp, struct path *path)
890 return exp; 838 return exp;
891} 839}
892 840
893#ifdef CONFIG_NFSD_DEPRECATED
894/*
895 * Hashtable locking. Write locks are placed only by user processes
896 * wanting to modify export information.
897 * Write locking only done in this file. Read locking
898 * needed externally.
899 */
900
901static DECLARE_RWSEM(hash_sem);
902
903void
904exp_readlock(void)
905{
906 down_read(&hash_sem);
907}
908
909static inline void
910exp_writelock(void)
911{
912 down_write(&hash_sem);
913}
914
915void
916exp_readunlock(void)
917{
918 up_read(&hash_sem);
919}
920
921static inline void
922exp_writeunlock(void)
923{
924 up_write(&hash_sem);
925}
926#else
927
928/* hash_sem not needed once deprecated interface is removed */
929void exp_readlock(void) {}
930static inline void exp_writelock(void){}
931void exp_readunlock(void) {}
932static inline void exp_writeunlock(void){}
933
934#endif
935
936#ifdef CONFIG_NFSD_DEPRECATED
937static void exp_do_unexport(svc_export *unexp);
938static int exp_verify_string(char *cp, int max);
939
940static void exp_fsid_unhash(struct svc_export *exp)
941{
942 struct svc_expkey *ek;
943
944 if ((exp->ex_flags & NFSEXP_FSID) == 0)
945 return;
946
947 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
948 if (!IS_ERR(ek)) {
949 sunrpc_invalidate(&ek->h, &svc_expkey_cache);
950 cache_put(&ek->h, &svc_expkey_cache);
951 }
952}
953
954static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
955{
956 u32 fsid[2];
957
958 if ((exp->ex_flags & NFSEXP_FSID) == 0)
959 return 0;
960
961 mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL);
962 return exp_set_key(clp, FSID_NUM, fsid, exp);
963}
964
965static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
966{
967 u32 fsid[2];
968 struct inode *inode = exp->ex_path.dentry->d_inode;
969 dev_t dev = inode->i_sb->s_dev;
970
971 if (old_valid_dev(dev)) {
972 mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL);
973 return exp_set_key(clp, FSID_DEV, fsid, exp);
974 }
975 mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL);
976 return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp);
977}
978 841
979static void exp_unhash(struct svc_export *exp)
980{
981 struct svc_expkey *ek;
982 struct inode *inode = exp->ex_path.dentry->d_inode;
983
984 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
985 if (!IS_ERR(ek)) {
986 sunrpc_invalidate(&ek->h, &svc_expkey_cache);
987 cache_put(&ek->h, &svc_expkey_cache);
988 }
989}
990
991/*
992 * Export a file system.
993 */
994int
995exp_export(struct nfsctl_export *nxp)
996{
997 svc_client *clp;
998 struct svc_export *exp = NULL;
999 struct svc_export new;
1000 struct svc_expkey *fsid_key = NULL;
1001 struct path path;
1002 int err;
1003
1004 /* Consistency check */
1005 err = -EINVAL;
1006 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
1007 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
1008 goto out;
1009
1010 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
1011 nxp->ex_client, nxp->ex_path,
1012 (unsigned)nxp->ex_dev, (long)nxp->ex_ino,
1013 nxp->ex_flags);
1014
1015 /* Try to lock the export table for update */
1016 exp_writelock();
1017
1018 /* Look up client info */
1019 if (!(clp = auth_domain_find(nxp->ex_client)))
1020 goto out_unlock;
1021
1022
1023 /* Look up the dentry */
1024 err = kern_path(nxp->ex_path, 0, &path);
1025 if (err)
1026 goto out_put_clp;
1027 err = -EINVAL;
1028
1029 exp = exp_get_by_name(clp, &path, NULL);
1030
1031 memset(&new, 0, sizeof(new));
1032
1033 /* must make sure there won't be an ex_fsid clash */
1034 if ((nxp->ex_flags & NFSEXP_FSID) &&
1035 (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
1036 fsid_key->ek_path.mnt &&
1037 (fsid_key->ek_path.mnt != path.mnt ||
1038 fsid_key->ek_path.dentry != path.dentry))
1039 goto finish;
1040
1041 if (!IS_ERR(exp)) {
1042 /* just a flags/id/fsid update */
1043
1044 exp_fsid_unhash(exp);
1045 exp->ex_flags = nxp->ex_flags;
1046 exp->ex_anon_uid = nxp->ex_anon_uid;
1047 exp->ex_anon_gid = nxp->ex_anon_gid;
1048 exp->ex_fsid = nxp->ex_dev;
1049
1050 err = exp_fsid_hash(clp, exp);
1051 goto finish;
1052 }
1053
1054 err = check_export(path.dentry->d_inode, &nxp->ex_flags, NULL);
1055 if (err) goto finish;
1056
1057 err = -ENOMEM;
1058
1059 dprintk("nfsd: creating export entry %p for client %p\n", exp, clp);
1060
1061 new.h.expiry_time = NEVER;
1062 new.h.flags = 0;
1063 new.ex_pathname = kstrdup(nxp->ex_path, GFP_KERNEL);
1064 if (!new.ex_pathname)
1065 goto finish;
1066 new.ex_client = clp;
1067 new.ex_path = path;
1068 new.ex_flags = nxp->ex_flags;
1069 new.ex_anon_uid = nxp->ex_anon_uid;
1070 new.ex_anon_gid = nxp->ex_anon_gid;
1071 new.ex_fsid = nxp->ex_dev;
1072
1073 exp = svc_export_lookup(&new);
1074 if (exp)
1075 exp = svc_export_update(&new, exp);
1076
1077 if (!exp)
1078 goto finish;
1079
1080 if (exp_hash(clp, exp) ||
1081 exp_fsid_hash(clp, exp)) {
1082 /* failed to create at least one index */
1083 exp_do_unexport(exp);
1084 cache_flush();
1085 } else
1086 err = 0;
1087finish:
1088 kfree(new.ex_pathname);
1089 if (!IS_ERR_OR_NULL(exp))
1090 exp_put(exp);
1091 if (!IS_ERR_OR_NULL(fsid_key))
1092 cache_put(&fsid_key->h, &svc_expkey_cache);
1093 path_put(&path);
1094out_put_clp:
1095 auth_domain_put(clp);
1096out_unlock:
1097 exp_writeunlock();
1098out:
1099 return err;
1100}
1101
1102/*
1103 * Unexport a file system. The export entry has already
1104 * been removed from the client's list of exported fs's.
1105 */
1106static void
1107exp_do_unexport(svc_export *unexp)
1108{
1109 sunrpc_invalidate(&unexp->h, &svc_export_cache);
1110 exp_unhash(unexp);
1111 exp_fsid_unhash(unexp);
1112}
1113
1114
1115/*
1116 * unexport syscall.
1117 */
1118int
1119exp_unexport(struct nfsctl_export *nxp)
1120{
1121 struct auth_domain *dom;
1122 svc_export *exp;
1123 struct path path;
1124 int err;
1125
1126 /* Consistency check */
1127 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
1128 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
1129 return -EINVAL;
1130
1131 exp_writelock();
1132
1133 err = -EINVAL;
1134 dom = auth_domain_find(nxp->ex_client);
1135 if (!dom) {
1136 dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client);
1137 goto out_unlock;
1138 }
1139
1140 err = kern_path(nxp->ex_path, 0, &path);
1141 if (err)
1142 goto out_domain;
1143
1144 err = -EINVAL;
1145 exp = exp_get_by_name(dom, &path, NULL);
1146 path_put(&path);
1147 if (IS_ERR(exp))
1148 goto out_domain;
1149
1150 exp_do_unexport(exp);
1151 exp_put(exp);
1152 err = 0;
1153
1154out_domain:
1155 auth_domain_put(dom);
1156 cache_flush();
1157out_unlock:
1158 exp_writeunlock();
1159 return err;
1160}
1161#endif /* CONFIG_NFSD_DEPRECATED */
1162 842
1163/* 843/*
1164 * Obtain the root fh on behalf of a client. 844 * Obtain the root fh on behalf of a client.
@@ -1367,7 +1047,6 @@ static void *e_start(struct seq_file *m, loff_t *pos)
1367 unsigned hash, export; 1047 unsigned hash, export;
1368 struct cache_head *ch; 1048 struct cache_head *ch;
1369 1049
1370 exp_readlock();
1371 read_lock(&svc_export_cache.hash_lock); 1050 read_lock(&svc_export_cache.hash_lock);
1372 if (!n--) 1051 if (!n--)
1373 return SEQ_START_TOKEN; 1052 return SEQ_START_TOKEN;
@@ -1418,7 +1097,6 @@ static void e_stop(struct seq_file *m, void *p)
1418 __releases(svc_export_cache.hash_lock) 1097 __releases(svc_export_cache.hash_lock)
1419{ 1098{
1420 read_unlock(&svc_export_cache.hash_lock); 1099 read_unlock(&svc_export_cache.hash_lock);
1421 exp_readunlock();
1422} 1100}
1423 1101
1424static struct flags { 1102static struct flags {
@@ -1550,97 +1228,6 @@ const struct seq_operations nfs_exports_op = {
1550 .show = e_show, 1228 .show = e_show,
1551}; 1229};
1552 1230
1553#ifdef CONFIG_NFSD_DEPRECATED
1554/*
1555 * Add or modify a client.
1556 * Change requests may involve the list of host addresses. The list of
1557 * exports and possibly existing uid maps are left untouched.
1558 */
1559int
1560exp_addclient(struct nfsctl_client *ncp)
1561{
1562 struct auth_domain *dom;
1563 int i, err;
1564 struct in6_addr addr6;
1565
1566 /* First, consistency check. */
1567 err = -EINVAL;
1568 if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1569 goto out;
1570 if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
1571 goto out;
1572
1573 /* Lock the hashtable */
1574 exp_writelock();
1575
1576 dom = unix_domain_find(ncp->cl_ident);
1577
1578 err = -ENOMEM;
1579 if (!dom)
1580 goto out_unlock;
1581
1582 /* Insert client into hashtable. */
1583 for (i = 0; i < ncp->cl_naddr; i++) {
1584 ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
1585 auth_unix_add_addr(&init_net, &addr6, dom);
1586 }
1587 auth_unix_forget_old(dom);
1588 auth_domain_put(dom);
1589
1590 err = 0;
1591
1592out_unlock:
1593 exp_writeunlock();
1594out:
1595 return err;
1596}
1597
1598/*
1599 * Delete a client given an identifier.
1600 */
1601int
1602exp_delclient(struct nfsctl_client *ncp)
1603{
1604 int err;
1605 struct auth_domain *dom;
1606
1607 err = -EINVAL;
1608 if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1609 goto out;
1610
1611 /* Lock the hashtable */
1612 exp_writelock();
1613
1614 dom = auth_domain_find(ncp->cl_ident);
1615 /* just make sure that no addresses work
1616 * and that it will expire soon
1617 */
1618 if (dom) {
1619 err = auth_unix_forget_old(dom);
1620 auth_domain_put(dom);
1621 }
1622
1623 exp_writeunlock();
1624out:
1625 return err;
1626}
1627
1628/*
1629 * Verify that string is non-empty and does not exceed max length.
1630 */
1631static int
1632exp_verify_string(char *cp, int max)
1633{
1634 int i;
1635
1636 for (i = 0; i < max; i++)
1637 if (!cp[i])
1638 return i;
1639 cp[i] = 0;
1640 printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
1641 return 0;
1642}
1643#endif /* CONFIG_NFSD_DEPRECATED */
1644 1231
1645/* 1232/*
1646 * Initialize the exports module. 1233 * Initialize the exports module.
@@ -1667,10 +1254,8 @@ nfsd_export_init(void)
1667void 1254void
1668nfsd_export_flush(void) 1255nfsd_export_flush(void)
1669{ 1256{
1670 exp_writelock();
1671 cache_purge(&svc_expkey_cache); 1257 cache_purge(&svc_expkey_cache);
1672 cache_purge(&svc_export_cache); 1258 cache_purge(&svc_export_cache);
1673 exp_writeunlock();
1674} 1259}
1675 1260
1676/* 1261/*
@@ -1682,12 +1267,9 @@ nfsd_export_shutdown(void)
1682 1267
1683 dprintk("nfsd: shutting down export module.\n"); 1268 dprintk("nfsd: shutting down export module.\n");
1684 1269
1685 exp_writelock();
1686
1687 cache_unregister(&svc_expkey_cache); 1270 cache_unregister(&svc_expkey_cache);
1688 cache_unregister(&svc_export_cache); 1271 cache_unregister(&svc_export_cache);
1689 svcauth_unix_purge(); 1272 svcauth_unix_purge();
1690 1273
1691 exp_writeunlock();
1692 dprintk("nfsd: export shutdown complete.\n"); 1274 dprintk("nfsd: export shutdown complete.\n");
1693} 1275}
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 7c831a2731f..77e7a5cca88 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -35,10 +35,8 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
35 memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size); 35 memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size);
36 fh.fh_export = NULL; 36 fh.fh_export = NULL;
37 37
38 exp_readlock();
39 nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); 38 nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp);
40 fh_put(&fh); 39 fh_put(&fh);
41 exp_readunlock();
42 /* We return nlm error codes as nlm doesn't know 40 /* We return nlm error codes as nlm doesn't know
43 * about nfsd, but nfsd does know about nlm.. 41 * about nfsd, but nfsd does know about nlm..
44 */ 42 */
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 3a6dbd70b34..05b397ce70f 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -156,6 +156,8 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
156 !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 156 !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
157 return nfserr_inval; 157 return nfserr_inval;
158 158
159 accmode |= NFSD_MAY_READ_IF_EXEC;
160
159 if (open->op_share_access & NFS4_SHARE_ACCESS_READ) 161 if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
160 accmode |= NFSD_MAY_READ; 162 accmode |= NFSD_MAY_READ;
161 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 163 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
@@ -291,6 +293,15 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
291 if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) 293 if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
292 return nfserr_inval; 294 return nfserr_inval;
293 295
296 /*
297 * RFC5661 18.51.3
298 * Before RECLAIM_COMPLETE done, server should deny new lock
299 */
300 if (nfsd4_has_session(cstate) &&
301 !cstate->session->se_client->cl_firststate &&
302 open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
303 return nfserr_grace;
304
294 if (nfsd4_has_session(cstate)) 305 if (nfsd4_has_session(cstate))
295 copy_clientid(&open->op_clientid, cstate->session); 306 copy_clientid(&open->op_clientid, cstate->session);
296 307
@@ -682,7 +693,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
682 readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); 693 readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
683 readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); 694 readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
684 695
685 if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) || 696 if ((cookie == 1) || (cookie == 2) ||
686 (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) 697 (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
687 return nfserr_bad_cookie; 698 return nfserr_bad_cookie;
688 699
@@ -921,7 +932,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
921 count = 4 + (verify->ve_attrlen >> 2); 932 count = 4 + (verify->ve_attrlen >> 2);
922 buf = kmalloc(count << 2, GFP_KERNEL); 933 buf = kmalloc(count << 2, GFP_KERNEL);
923 if (!buf) 934 if (!buf)
924 return nfserr_resource; 935 return nfserr_jukebox;
925 936
926 status = nfsd4_encode_fattr(&cstate->current_fh, 937 status = nfsd4_encode_fattr(&cstate->current_fh,
927 cstate->current_fh.fh_export, 938 cstate->current_fh.fh_export,
@@ -998,6 +1009,15 @@ struct nfsd4_operation {
998 nfsd4op_func op_func; 1009 nfsd4op_func op_func;
999 u32 op_flags; 1010 u32 op_flags;
1000 char *op_name; 1011 char *op_name;
1012 /*
1013 * We use the DRC for compounds containing non-idempotent
1014 * operations, *except* those that are 4.1-specific (since
1015 * sessions provide their own EOS), and except for stateful
1016 * operations other than setclientid and setclientid_confirm
1017 * (since sequence numbers provide EOS for open, lock, etc in
1018 * the v4.0 case).
1019 */
1020 bool op_cacheresult;
1001}; 1021};
1002 1022
1003static struct nfsd4_operation nfsd4_ops[]; 1023static struct nfsd4_operation nfsd4_ops[];
@@ -1042,6 +1062,11 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
1042 return &nfsd4_ops[op->opnum]; 1062 return &nfsd4_ops[op->opnum];
1043} 1063}
1044 1064
1065bool nfsd4_cache_this_op(struct nfsd4_op *op)
1066{
1067 return OPDESC(op)->op_cacheresult;
1068}
1069
1045static bool need_wrongsec_check(struct svc_rqst *rqstp) 1070static bool need_wrongsec_check(struct svc_rqst *rqstp)
1046{ 1071{
1047 struct nfsd4_compoundres *resp = rqstp->rq_resp; 1072 struct nfsd4_compoundres *resp = rqstp->rq_resp;
@@ -1209,7 +1234,6 @@ encode_op:
1209 fh_put(&resp->cstate.save_fh); 1234 fh_put(&resp->cstate.save_fh);
1210 BUG_ON(resp->cstate.replay_owner); 1235 BUG_ON(resp->cstate.replay_owner);
1211out: 1236out:
1212 nfsd4_release_compoundargs(args);
1213 /* Reset deferral mechanism for RPC deferrals */ 1237 /* Reset deferral mechanism for RPC deferrals */
1214 rqstp->rq_usedeferral = 1; 1238 rqstp->rq_usedeferral = 1;
1215 dprintk("nfsv4 compound returned %d\n", ntohl(status)); 1239 dprintk("nfsv4 compound returned %d\n", ntohl(status));
@@ -1232,6 +1256,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1232 [OP_CREATE] = { 1256 [OP_CREATE] = {
1233 .op_func = (nfsd4op_func)nfsd4_create, 1257 .op_func = (nfsd4op_func)nfsd4_create,
1234 .op_name = "OP_CREATE", 1258 .op_name = "OP_CREATE",
1259 .op_cacheresult = true,
1235 }, 1260 },
1236 [OP_DELEGRETURN] = { 1261 [OP_DELEGRETURN] = {
1237 .op_func = (nfsd4op_func)nfsd4_delegreturn, 1262 .op_func = (nfsd4op_func)nfsd4_delegreturn,
@@ -1249,6 +1274,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1249 [OP_LINK] = { 1274 [OP_LINK] = {
1250 .op_func = (nfsd4op_func)nfsd4_link, 1275 .op_func = (nfsd4op_func)nfsd4_link,
1251 .op_name = "OP_LINK", 1276 .op_name = "OP_LINK",
1277 .op_cacheresult = true,
1252 }, 1278 },
1253 [OP_LOCK] = { 1279 [OP_LOCK] = {
1254 .op_func = (nfsd4op_func)nfsd4_lock, 1280 .op_func = (nfsd4op_func)nfsd4_lock,
@@ -1322,10 +1348,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
1322 [OP_REMOVE] = { 1348 [OP_REMOVE] = {
1323 .op_func = (nfsd4op_func)nfsd4_remove, 1349 .op_func = (nfsd4op_func)nfsd4_remove,
1324 .op_name = "OP_REMOVE", 1350 .op_name = "OP_REMOVE",
1351 .op_cacheresult = true,
1325 }, 1352 },
1326 [OP_RENAME] = { 1353 [OP_RENAME] = {
1327 .op_name = "OP_RENAME", 1354 .op_name = "OP_RENAME",
1328 .op_func = (nfsd4op_func)nfsd4_rename, 1355 .op_func = (nfsd4op_func)nfsd4_rename,
1356 .op_cacheresult = true,
1329 }, 1357 },
1330 [OP_RENEW] = { 1358 [OP_RENEW] = {
1331 .op_func = (nfsd4op_func)nfsd4_renew, 1359 .op_func = (nfsd4op_func)nfsd4_renew,
@@ -1351,16 +1379,19 @@ static struct nfsd4_operation nfsd4_ops[] = {
1351 [OP_SETATTR] = { 1379 [OP_SETATTR] = {
1352 .op_func = (nfsd4op_func)nfsd4_setattr, 1380 .op_func = (nfsd4op_func)nfsd4_setattr,
1353 .op_name = "OP_SETATTR", 1381 .op_name = "OP_SETATTR",
1382 .op_cacheresult = true,
1354 }, 1383 },
1355 [OP_SETCLIENTID] = { 1384 [OP_SETCLIENTID] = {
1356 .op_func = (nfsd4op_func)nfsd4_setclientid, 1385 .op_func = (nfsd4op_func)nfsd4_setclientid,
1357 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1386 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1358 .op_name = "OP_SETCLIENTID", 1387 .op_name = "OP_SETCLIENTID",
1388 .op_cacheresult = true,
1359 }, 1389 },
1360 [OP_SETCLIENTID_CONFIRM] = { 1390 [OP_SETCLIENTID_CONFIRM] = {
1361 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, 1391 .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1362 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, 1392 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1363 .op_name = "OP_SETCLIENTID_CONFIRM", 1393 .op_name = "OP_SETCLIENTID_CONFIRM",
1394 .op_cacheresult = true,
1364 }, 1395 },
1365 [OP_VERIFY] = { 1396 [OP_VERIFY] = {
1366 .op_func = (nfsd4op_func)nfsd4_verify, 1397 .op_func = (nfsd4op_func)nfsd4_verify,
@@ -1369,6 +1400,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
1369 [OP_WRITE] = { 1400 [OP_WRITE] = {
1370 .op_func = (nfsd4op_func)nfsd4_write, 1401 .op_func = (nfsd4op_func)nfsd4_write,
1371 .op_name = "OP_WRITE", 1402 .op_name = "OP_WRITE",
1403 .op_cacheresult = true,
1372 }, 1404 },
1373 [OP_RELEASE_LOCKOWNER] = { 1405 [OP_RELEASE_LOCKOWNER] = {
1374 .op_func = (nfsd4op_func)nfsd4_release_lockowner, 1406 .op_func = (nfsd4op_func)nfsd4_release_lockowner,
@@ -1402,6 +1434,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
1402 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, 1434 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1403 .op_name = "OP_SEQUENCE", 1435 .op_name = "OP_SEQUENCE",
1404 }, 1436 },
1437 [OP_DESTROY_CLIENTID] = {
1438 .op_func = NULL,
1439 .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1440 .op_name = "OP_DESTROY_CLIENTID",
1441 },
1405 [OP_RECLAIM_COMPLETE] = { 1442 [OP_RECLAIM_COMPLETE] = {
1406 .op_func = (nfsd4op_func)nfsd4_reclaim_complete, 1443 .op_func = (nfsd4op_func)nfsd4_reclaim_complete,
1407 .op_flags = ALLOWED_WITHOUT_FH, 1444 .op_flags = ALLOWED_WITHOUT_FH,
@@ -1412,6 +1449,16 @@ static struct nfsd4_operation nfsd4_ops[] = {
1412 .op_flags = OP_HANDLES_WRONGSEC, 1449 .op_flags = OP_HANDLES_WRONGSEC,
1413 .op_name = "OP_SECINFO_NO_NAME", 1450 .op_name = "OP_SECINFO_NO_NAME",
1414 }, 1451 },
1452 [OP_TEST_STATEID] = {
1453 .op_func = (nfsd4op_func)nfsd4_test_stateid,
1454 .op_flags = ALLOWED_WITHOUT_FH,
1455 .op_name = "OP_TEST_STATEID",
1456 },
1457 [OP_FREE_STATEID] = {
1458 .op_func = (nfsd4op_func)nfsd4_free_stateid,
1459 .op_flags = ALLOWED_WITHOUT_FH,
1460 .op_name = "OP_FREE_STATEID",
1461 },
1415}; 1462};
1416 1463
1417static const char *nfsd4_op_name(unsigned opnum) 1464static const char *nfsd4_op_name(unsigned opnum)
@@ -1424,16 +1471,6 @@ static const char *nfsd4_op_name(unsigned opnum)
1424#define nfsd4_voidres nfsd4_voidargs 1471#define nfsd4_voidres nfsd4_voidargs
1425struct nfsd4_voidargs { int dummy; }; 1472struct nfsd4_voidargs { int dummy; };
1426 1473
1427/*
1428 * TODO: At the present time, the NFSv4 server does not do XID caching
1429 * of requests. Implementing XID caching would not be a serious problem,
1430 * although it would require a mild change in interfaces since one
1431 * doesn't know whether an NFSv4 request is idempotent until after the
1432 * XDR decode. However, XID caching totally confuses pynfs (Peter
1433 * Astrand's regression testsuite for NFSv4 servers), which reuses
1434 * XID's liberally, so I've left it unimplemented until pynfs generates
1435 * better XID's.
1436 */
1437static struct svc_procedure nfsd_procedures4[2] = { 1474static struct svc_procedure nfsd_procedures4[2] = {
1438 [NFSPROC4_NULL] = { 1475 [NFSPROC4_NULL] = {
1439 .pc_func = (svc_procfunc) nfsd4_proc_null, 1476 .pc_func = (svc_procfunc) nfsd4_proc_null,
@@ -1449,6 +1486,7 @@ static struct svc_procedure nfsd_procedures4[2] = {
1449 .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, 1486 .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres,
1450 .pc_argsize = sizeof(struct nfsd4_compoundargs), 1487 .pc_argsize = sizeof(struct nfsd4_compoundargs),
1451 .pc_ressize = sizeof(struct nfsd4_compoundres), 1488 .pc_ressize = sizeof(struct nfsd4_compoundres),
1489 .pc_release = nfsd4_release_compoundargs,
1452 .pc_cachetype = RC_NOCACHE, 1490 .pc_cachetype = RC_NOCACHE,
1453 .pc_xdrressize = NFSD_BUFSIZE/4, 1491 .pc_xdrressize = NFSD_BUFSIZE/4,
1454 }, 1492 },
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index ffb59ef6f82..02eb38ecbfe 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -88,7 +88,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
88 struct xdr_netobj cksum; 88 struct xdr_netobj cksum;
89 struct hash_desc desc; 89 struct hash_desc desc;
90 struct scatterlist sg; 90 struct scatterlist sg;
91 __be32 status = nfserr_resource; 91 __be32 status = nfserr_jukebox;
92 92
93 dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", 93 dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
94 clname->len, clname->data); 94 clname->len, clname->data);
@@ -191,52 +191,42 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen,
191} 191}
192 192
193static int 193static int
194nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) 194nfsd4_list_rec_dir(recdir_func *f)
195{ 195{
196 const struct cred *original_cred; 196 const struct cred *original_cred;
197 struct file *filp; 197 struct dentry *dir = rec_file->f_path.dentry;
198 LIST_HEAD(names); 198 LIST_HEAD(names);
199 struct name_list *entry;
200 struct dentry *dentry;
201 int status; 199 int status;
202 200
203 if (!rec_file)
204 return 0;
205
206 status = nfs4_save_creds(&original_cred); 201 status = nfs4_save_creds(&original_cred);
207 if (status < 0) 202 if (status < 0)
208 return status; 203 return status;
209 204
210 filp = dentry_open(dget(dir), mntget(rec_file->f_path.mnt), O_RDONLY, 205 status = vfs_llseek(rec_file, 0, SEEK_SET);
211 current_cred()); 206 if (status < 0) {
212 status = PTR_ERR(filp); 207 nfs4_reset_creds(original_cred);
213 if (IS_ERR(filp)) 208 return status;
214 goto out; 209 }
215 status = vfs_readdir(filp, nfsd4_build_namelist, &names); 210
216 fput(filp); 211 status = vfs_readdir(rec_file, nfsd4_build_namelist, &names);
217 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); 212 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
218 while (!list_empty(&names)) { 213 while (!list_empty(&names)) {
214 struct name_list *entry;
219 entry = list_entry(names.next, struct name_list, list); 215 entry = list_entry(names.next, struct name_list, list);
220 216 if (!status) {
221 dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); 217 struct dentry *dentry;
222 if (IS_ERR(dentry)) { 218 dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
223 status = PTR_ERR(dentry); 219 if (IS_ERR(dentry)) {
224 break; 220 status = PTR_ERR(dentry);
221 break;
222 }
223 status = f(dir, dentry);
224 dput(dentry);
225 } 225 }
226 status = f(dir, dentry);
227 dput(dentry);
228 if (status)
229 break;
230 list_del(&entry->list); 226 list_del(&entry->list);
231 kfree(entry); 227 kfree(entry);
232 } 228 }
233 mutex_unlock(&dir->d_inode->i_mutex); 229 mutex_unlock(&dir->d_inode->i_mutex);
234out:
235 while (!list_empty(&names)) {
236 entry = list_entry(names.next, struct name_list, list);
237 list_del(&entry->list);
238 kfree(entry);
239 }
240 nfs4_reset_creds(original_cred); 230 nfs4_reset_creds(original_cred);
241 return status; 231 return status;
242} 232}
@@ -322,7 +312,7 @@ nfsd4_recdir_purge_old(void) {
322 status = mnt_want_write(rec_file->f_path.mnt); 312 status = mnt_want_write(rec_file->f_path.mnt);
323 if (status) 313 if (status)
324 goto out; 314 goto out;
325 status = nfsd4_list_rec_dir(rec_file->f_path.dentry, purge_old); 315 status = nfsd4_list_rec_dir(purge_old);
326 if (status == 0) 316 if (status == 0)
327 vfs_fsync(rec_file, 0); 317 vfs_fsync(rec_file, 0);
328 mnt_drop_write(rec_file->f_path.mnt); 318 mnt_drop_write(rec_file->f_path.mnt);
@@ -352,7 +342,7 @@ nfsd4_recdir_load(void) {
352 if (!rec_file) 342 if (!rec_file)
353 return 0; 343 return 0;
354 344
355 status = nfsd4_list_rec_dir(rec_file->f_path.dentry, load_recdir); 345 status = nfsd4_list_rec_dir(load_recdir);
356 if (status) 346 if (status)
357 printk("nfsd4: failed loading clients from recovery" 347 printk("nfsd4: failed loading clients from recovery"
358 " directory %s\n", rec_file->f_path.dentry->d_name.name); 348 " directory %s\n", rec_file->f_path.dentry->d_name.name);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e98f3c2e949..6f8bcc733f7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -37,6 +37,7 @@
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>
40#include <linux/pagemap.h>
40#include <linux/sunrpc/svcauth_gss.h> 41#include <linux/sunrpc/svcauth_gss.h>
41#include <linux/sunrpc/clnt.h> 42#include <linux/sunrpc/clnt.h>
42#include "xdr4.h" 43#include "xdr4.h"
@@ -60,9 +61,12 @@ static u64 current_sessionid = 1;
60 61
61/* forward declarations */ 62/* forward declarations */
62static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); 63static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
64static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
65static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
63static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); 66static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
64static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; 67static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
65static void nfs4_set_recdir(char *recdir); 68static void nfs4_set_recdir(char *recdir);
69static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner);
66 70
67/* Locking: */ 71/* Locking: */
68 72
@@ -188,8 +192,15 @@ static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
188static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 192static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
189{ 193{
190 if (atomic_dec_and_test(&fp->fi_access[oflag])) { 194 if (atomic_dec_and_test(&fp->fi_access[oflag])) {
191 nfs4_file_put_fd(fp, O_RDWR);
192 nfs4_file_put_fd(fp, oflag); 195 nfs4_file_put_fd(fp, oflag);
196 /*
197 * It's also safe to get rid of the RDWR open *if*
198 * we no longer have need of the other kind of access
199 * or if we already have the other kind of open:
200 */
201 if (fp->fi_fds[1-oflag]
202 || atomic_read(&fp->fi_access[1 - oflag]) == 0)
203 nfs4_file_put_fd(fp, O_RDWR);
193 } 204 }
194} 205}
195 206
@@ -381,14 +392,6 @@ static int nfs4_access_to_omode(u32 access)
381 BUG(); 392 BUG();
382} 393}
383 394
384static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
385{
386 unsigned int access;
387
388 set_access(&access, stp->st_access_bmap);
389 return nfs4_access_to_omode(access);
390}
391
392static void unhash_generic_stateid(struct nfs4_stateid *stp) 395static void unhash_generic_stateid(struct nfs4_stateid *stp)
393{ 396{
394 list_del(&stp->st_hash); 397 list_del(&stp->st_hash);
@@ -398,11 +401,14 @@ static void unhash_generic_stateid(struct nfs4_stateid *stp)
398 401
399static void free_generic_stateid(struct nfs4_stateid *stp) 402static void free_generic_stateid(struct nfs4_stateid *stp)
400{ 403{
401 int oflag; 404 int i;
402 405
403 if (stp->st_access_bmap) { 406 if (stp->st_access_bmap) {
404 oflag = nfs4_access_bmap_to_omode(stp); 407 for (i = 1; i < 4; i++) {
405 nfs4_file_put_access(stp->st_file, oflag); 408 if (test_bit(i, &stp->st_access_bmap))
409 nfs4_file_put_access(stp->st_file,
410 nfs4_access_to_omode(i));
411 }
406 } 412 }
407 put_nfs4_file(stp->st_file); 413 put_nfs4_file(stp->st_file);
408 kmem_cache_free(stateid_slab, stp); 414 kmem_cache_free(stateid_slab, stp);
@@ -1507,6 +1513,29 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
1507 return slot->sl_status; 1513 return slot->sl_status;
1508} 1514}
1509 1515
1516#define NFSD_MIN_REQ_HDR_SEQ_SZ ((\
1517 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
1518 1 + /* MIN tag is length with zero, only length */ \
1519 3 + /* version, opcount, opcode */ \
1520 XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
1521 /* seqid, slotID, slotID, cache */ \
1522 4 ) * sizeof(__be32))
1523
1524#define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
1525 2 + /* verifier: AUTH_NULL, length 0 */\
1526 1 + /* status */ \
1527 1 + /* MIN tag is length with zero, only length */ \
1528 3 + /* opcount, opcode, opstatus*/ \
1529 XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
1530 /* seqid, slotID, slotID, slotID, status */ \
1531 5 ) * sizeof(__be32))
1532
1533static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel)
1534{
1535 return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ
1536 || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ;
1537}
1538
1510__be32 1539__be32
1511nfsd4_create_session(struct svc_rqst *rqstp, 1540nfsd4_create_session(struct svc_rqst *rqstp,
1512 struct nfsd4_compound_state *cstate, 1541 struct nfsd4_compound_state *cstate,
@@ -1575,6 +1604,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1575 cr_ses->flags &= ~SESSION4_PERSIST; 1604 cr_ses->flags &= ~SESSION4_PERSIST;
1576 cr_ses->flags &= ~SESSION4_RDMA; 1605 cr_ses->flags &= ~SESSION4_RDMA;
1577 1606
1607 status = nfserr_toosmall;
1608 if (check_forechannel_attrs(cr_ses->fore_channel))
1609 goto out;
1610
1578 status = nfserr_jukebox; 1611 status = nfserr_jukebox;
1579 new = alloc_init_session(rqstp, conf, cr_ses); 1612 new = alloc_init_session(rqstp, conf, cr_ses);
1580 if (!new) 1613 if (!new)
@@ -1736,6 +1769,14 @@ static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_sess
1736 return args->opcnt > session->se_fchannel.maxops; 1769 return args->opcnt > session->se_fchannel.maxops;
1737} 1770}
1738 1771
1772static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
1773 struct nfsd4_session *session)
1774{
1775 struct xdr_buf *xb = &rqstp->rq_arg;
1776
1777 return xb->len > session->se_fchannel.maxreq_sz;
1778}
1779
1739__be32 1780__be32
1740nfsd4_sequence(struct svc_rqst *rqstp, 1781nfsd4_sequence(struct svc_rqst *rqstp,
1741 struct nfsd4_compound_state *cstate, 1782 struct nfsd4_compound_state *cstate,
@@ -1768,6 +1809,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
1768 if (nfsd4_session_too_many_ops(rqstp, session)) 1809 if (nfsd4_session_too_many_ops(rqstp, session))
1769 goto out; 1810 goto out;
1770 1811
1812 status = nfserr_req_too_big;
1813 if (nfsd4_request_too_big(rqstp, session))
1814 goto out;
1815
1771 status = nfserr_badslot; 1816 status = nfserr_badslot;
1772 if (seq->slotid >= session->se_fchannel.maxreqs) 1817 if (seq->slotid >= session->se_fchannel.maxreqs)
1773 goto out; 1818 goto out;
@@ -1908,7 +1953,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1908 * of 5 bullet points, labeled as CASE0 - CASE4 below. 1953 * of 5 bullet points, labeled as CASE0 - CASE4 below.
1909 */ 1954 */
1910 unconf = find_unconfirmed_client_by_str(dname, strhashval); 1955 unconf = find_unconfirmed_client_by_str(dname, strhashval);
1911 status = nfserr_resource; 1956 status = nfserr_jukebox;
1912 if (!conf) { 1957 if (!conf) {
1913 /* 1958 /*
1914 * RFC 3530 14.2.33 CASE 4: 1959 * RFC 3530 14.2.33 CASE 4:
@@ -2337,15 +2382,6 @@ out:
2337 return ret; 2382 return ret;
2338} 2383}
2339 2384
2340static inline void
2341nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
2342{
2343 if (share_access & NFS4_SHARE_ACCESS_WRITE)
2344 nfs4_file_put_access(fp, O_WRONLY);
2345 if (share_access & NFS4_SHARE_ACCESS_READ)
2346 nfs4_file_put_access(fp, O_RDONLY);
2347}
2348
2349static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 2385static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
2350{ 2386{
2351 /* We're assuming the state code never drops its reference 2387 /* We're assuming the state code never drops its reference
@@ -2396,8 +2432,8 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
2396} 2432}
2397 2433
2398static const struct lock_manager_operations nfsd_lease_mng_ops = { 2434static const struct lock_manager_operations nfsd_lease_mng_ops = {
2399 .fl_break = nfsd_break_deleg_cb, 2435 .lm_break = nfsd_break_deleg_cb,
2400 .fl_change = nfsd_change_deleg_cb, 2436 .lm_change = nfsd_change_deleg_cb,
2401}; 2437};
2402 2438
2403 2439
@@ -2454,7 +2490,7 @@ renew:
2454 if (open->op_stateowner == NULL) { 2490 if (open->op_stateowner == NULL) {
2455 sop = alloc_init_open_stateowner(strhashval, clp, open); 2491 sop = alloc_init_open_stateowner(strhashval, clp, open);
2456 if (sop == NULL) 2492 if (sop == NULL)
2457 return nfserr_resource; 2493 return nfserr_jukebox;
2458 open->op_stateowner = sop; 2494 open->op_stateowner = sop;
2459 } 2495 }
2460 list_del_init(&sop->so_close_lru); 2496 list_del_init(&sop->so_close_lru);
@@ -2556,12 +2592,18 @@ static inline int nfs4_access_to_access(u32 nfs4_access)
2556 return flags; 2592 return flags;
2557} 2593}
2558 2594
2559static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file 2595static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
2560*fp, struct svc_fh *cur_fh, u32 nfs4_access) 2596 struct svc_fh *cur_fh, struct nfsd4_open *open)
2561{ 2597{
2562 __be32 status; 2598 __be32 status;
2563 int oflag = nfs4_access_to_omode(nfs4_access); 2599 int oflag = nfs4_access_to_omode(open->op_share_access);
2564 int access = nfs4_access_to_access(nfs4_access); 2600 int access = nfs4_access_to_access(open->op_share_access);
2601
2602 /* CLAIM_DELEGATE_CUR is used in response to a broken lease;
2603 * allowing it to break the lease and return EAGAIN leaves the
2604 * client unable to make progress in returning the delegation */
2605 if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
2606 access |= NFSD_MAY_NOT_BREAK_LEASE;
2565 2607
2566 if (!fp->fi_fds[oflag]) { 2608 if (!fp->fi_fds[oflag]) {
2567 status = nfsd_open(rqstp, cur_fh, S_IFREG, access, 2609 status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
@@ -2584,9 +2626,9 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
2584 2626
2585 stp = nfs4_alloc_stateid(); 2627 stp = nfs4_alloc_stateid();
2586 if (stp == NULL) 2628 if (stp == NULL)
2587 return nfserr_resource; 2629 return nfserr_jukebox;
2588 2630
2589 status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); 2631 status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
2590 if (status) { 2632 if (status) {
2591 kmem_cache_free(stateid_slab, stp); 2633 kmem_cache_free(stateid_slab, stp);
2592 return status; 2634 return status;
@@ -2619,14 +2661,14 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
2619 2661
2620 new_access = !test_bit(op_share_access, &stp->st_access_bmap); 2662 new_access = !test_bit(op_share_access, &stp->st_access_bmap);
2621 if (new_access) { 2663 if (new_access) {
2622 status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access); 2664 status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
2623 if (status) 2665 if (status)
2624 return status; 2666 return status;
2625 } 2667 }
2626 status = nfsd4_truncate(rqstp, cur_fh, open); 2668 status = nfsd4_truncate(rqstp, cur_fh, open);
2627 if (status) { 2669 if (status) {
2628 if (new_access) { 2670 if (new_access) {
2629 int oflag = nfs4_access_to_omode(new_access); 2671 int oflag = nfs4_access_to_omode(op_share_access);
2630 nfs4_file_put_access(fp, oflag); 2672 nfs4_file_put_access(fp, oflag);
2631 } 2673 }
2632 return status; 2674 return status;
@@ -2815,7 +2857,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
2815 status = nfserr_bad_stateid; 2857 status = nfserr_bad_stateid;
2816 if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) 2858 if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
2817 goto out; 2859 goto out;
2818 status = nfserr_resource; 2860 status = nfserr_jukebox;
2819 fp = alloc_init_file(ino); 2861 fp = alloc_init_file(ino);
2820 if (fp == NULL) 2862 if (fp == NULL)
2821 goto out; 2863 goto out;
@@ -3137,6 +3179,37 @@ static int is_delegation_stateid(stateid_t *stateid)
3137 return stateid->si_fileid == 0; 3179 return stateid->si_fileid == 0;
3138} 3180}
3139 3181
3182static int is_open_stateid(struct nfs4_stateid *stateid)
3183{
3184 return stateid->st_openstp == NULL;
3185}
3186
3187__be32 nfs4_validate_stateid(stateid_t *stateid, int flags)
3188{
3189 struct nfs4_stateid *stp = NULL;
3190 __be32 status = nfserr_stale_stateid;
3191
3192 if (STALE_STATEID(stateid))
3193 goto out;
3194
3195 status = nfserr_expired;
3196 stp = search_for_stateid(stateid);
3197 if (!stp)
3198 goto out;
3199 status = nfserr_bad_stateid;
3200
3201 if (!stp->st_stateowner->so_confirmed)
3202 goto out;
3203
3204 status = check_stateid_generation(stateid, &stp->st_stateid, flags);
3205 if (status)
3206 goto out;
3207
3208 status = nfs_ok;
3209out:
3210 return status;
3211}
3212
3140/* 3213/*
3141* Checks for stateid operations 3214* Checks for stateid operations
3142*/ 3215*/
@@ -3216,6 +3289,81 @@ out:
3216 return status; 3289 return status;
3217} 3290}
3218 3291
3292static __be32
3293nfsd4_free_delegation_stateid(stateid_t *stateid)
3294{
3295 struct nfs4_delegation *dp = search_for_delegation(stateid);
3296 if (dp)
3297 return nfserr_locks_held;
3298 return nfserr_bad_stateid;
3299}
3300
3301static __be32
3302nfsd4_free_lock_stateid(struct nfs4_stateid *stp)
3303{
3304 if (check_for_locks(stp->st_file, stp->st_stateowner))
3305 return nfserr_locks_held;
3306 release_lock_stateid(stp);
3307 return nfs_ok;
3308}
3309
3310/*
3311 * Test if the stateid is valid
3312 */
3313__be32
3314nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3315 struct nfsd4_test_stateid *test_stateid)
3316{
3317 test_stateid->ts_has_session = nfsd4_has_session(cstate);
3318 return nfs_ok;
3319}
3320
3321/*
3322 * Free a state id
3323 */
3324__be32
3325nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3326 struct nfsd4_free_stateid *free_stateid)
3327{
3328 stateid_t *stateid = &free_stateid->fr_stateid;
3329 struct nfs4_stateid *stp;
3330 __be32 ret;
3331
3332 nfs4_lock_state();
3333 if (is_delegation_stateid(stateid)) {
3334 ret = nfsd4_free_delegation_stateid(stateid);
3335 goto out;
3336 }
3337
3338 stp = search_for_stateid(stateid);
3339 if (!stp) {
3340 ret = nfserr_bad_stateid;
3341 goto out;
3342 }
3343 if (stateid->si_generation != 0) {
3344 if (stateid->si_generation < stp->st_stateid.si_generation) {
3345 ret = nfserr_old_stateid;
3346 goto out;
3347 }
3348 if (stateid->si_generation > stp->st_stateid.si_generation) {
3349 ret = nfserr_bad_stateid;
3350 goto out;
3351 }
3352 }
3353
3354 if (is_open_stateid(stp)) {
3355 ret = nfserr_locks_held;
3356 goto out;
3357 } else {
3358 ret = nfsd4_free_lock_stateid(stp);
3359 goto out;
3360 }
3361
3362out:
3363 nfs4_unlock_state();
3364 return ret;
3365}
3366
3219static inline int 3367static inline int
3220setlkflg (int type) 3368setlkflg (int type)
3221{ 3369{
@@ -3384,18 +3532,16 @@ out:
3384 return status; 3532 return status;
3385} 3533}
3386 3534
3387 3535static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access)
3388/*
3389 * unset all bits in union bitmap (bmap) that
3390 * do not exist in share (from successful OPEN_DOWNGRADE)
3391 */
3392static void
3393reset_union_bmap_access(unsigned long access, unsigned long *bmap)
3394{ 3536{
3395 int i; 3537 int i;
3538
3396 for (i = 1; i < 4; i++) { 3539 for (i = 1; i < 4; i++) {
3397 if ((i & access) != i) 3540 if (test_bit(i, &stp->st_access_bmap)
3398 __clear_bit(i, bmap); 3541 && ((i & to_access) != i)) {
3542 nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(i));
3543 __clear_bit(i, &stp->st_access_bmap);
3544 }
3399 } 3545 }
3400} 3546}
3401 3547
@@ -3416,7 +3562,6 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
3416{ 3562{
3417 __be32 status; 3563 __be32 status;
3418 struct nfs4_stateid *stp; 3564 struct nfs4_stateid *stp;
3419 unsigned int share_access;
3420 3565
3421 dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", 3566 dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
3422 (int)cstate->current_fh.fh_dentry->d_name.len, 3567 (int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3425,6 +3570,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
3425 if (!access_valid(od->od_share_access, cstate->minorversion) 3570 if (!access_valid(od->od_share_access, cstate->minorversion)
3426 || !deny_valid(od->od_share_deny)) 3571 || !deny_valid(od->od_share_deny))
3427 return nfserr_inval; 3572 return nfserr_inval;
3573 /* We don't yet support WANT bits: */
3574 od->od_share_access &= NFS4_SHARE_ACCESS_MASK;
3428 3575
3429 nfs4_lock_state(); 3576 nfs4_lock_state();
3430 if ((status = nfs4_preprocess_seqid_op(cstate, 3577 if ((status = nfs4_preprocess_seqid_op(cstate,
@@ -3445,10 +3592,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
3445 stp->st_deny_bmap, od->od_share_deny); 3592 stp->st_deny_bmap, od->od_share_deny);
3446 goto out; 3593 goto out;
3447 } 3594 }
3448 set_access(&share_access, stp->st_access_bmap); 3595 nfs4_file_downgrade(stp, od->od_share_access);
3449 nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access);
3450 3596
3451 reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
3452 reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); 3597 reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
3453 3598
3454 update_stateid(&stp->st_stateid); 3599 update_stateid(&stp->st_stateid);
@@ -3594,6 +3739,14 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
3594static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; 3739static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
3595static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; 3740static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
3596 3741
3742static int
3743same_stateid(stateid_t *id_one, stateid_t *id_two)
3744{
3745 if (id_one->si_stateownerid != id_two->si_stateownerid)
3746 return 0;
3747 return id_one->si_fileid == id_two->si_fileid;
3748}
3749
3597static struct nfs4_stateid * 3750static struct nfs4_stateid *
3598find_stateid(stateid_t *stid, int flags) 3751find_stateid(stateid_t *stid, int flags)
3599{ 3752{
@@ -3623,6 +3776,44 @@ find_stateid(stateid_t *stid, int flags)
3623 return NULL; 3776 return NULL;
3624} 3777}
3625 3778
3779static struct nfs4_stateid *
3780search_for_stateid(stateid_t *stid)
3781{
3782 struct nfs4_stateid *local;
3783 unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid);
3784
3785 list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
3786 if (same_stateid(&local->st_stateid, stid))
3787 return local;
3788 }
3789
3790 list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
3791 if (same_stateid(&local->st_stateid, stid))
3792 return local;
3793 }
3794 return NULL;
3795}
3796
3797static struct nfs4_delegation *
3798search_for_delegation(stateid_t *stid)
3799{
3800 struct nfs4_file *fp;
3801 struct nfs4_delegation *dp;
3802 struct list_head *pos;
3803 int i;
3804
3805 for (i = 0; i < FILE_HASH_SIZE; i++) {
3806 list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
3807 list_for_each(pos, &fp->fi_delegations) {
3808 dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
3809 if (same_stateid(&dp->dl_stateid, stid))
3810 return dp;
3811 }
3812 }
3813 }
3814 return NULL;
3815}
3816
3626static struct nfs4_delegation * 3817static struct nfs4_delegation *
3627find_delegation_stateid(struct inode *ino, stateid_t *stid) 3818find_delegation_stateid(struct inode *ino, stateid_t *stid)
3628{ 3819{
@@ -3854,7 +4045,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3854 /* XXX: Do we need to check for duplicate stateowners on 4045 /* XXX: Do we need to check for duplicate stateowners on
3855 * the same file, or should they just be allowed (and 4046 * the same file, or should they just be allowed (and
3856 * create new stateids)? */ 4047 * create new stateids)? */
3857 status = nfserr_resource; 4048 status = nfserr_jukebox;
3858 lock_sop = alloc_init_lock_stateowner(strhashval, 4049 lock_sop = alloc_init_lock_stateowner(strhashval,
3859 open_sop->so_client, open_stp, lock); 4050 open_sop->so_client, open_stp, lock);
3860 if (lock_sop == NULL) 4051 if (lock_sop == NULL)
@@ -3938,9 +4129,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3938 case (EDEADLK): 4129 case (EDEADLK):
3939 status = nfserr_deadlock; 4130 status = nfserr_deadlock;
3940 break; 4131 break;
3941 default: 4132 default:
3942 dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 4133 dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
3943 status = nfserr_resource; 4134 status = nfserrno(err);
3944 break; 4135 break;
3945 } 4136 }
3946out: 4137out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 99018110321..f8109960525 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -44,13 +44,15 @@
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/pagemap.h>
47#include <linux/sunrpc/svcauth_gss.h> 48#include <linux/sunrpc/svcauth_gss.h>
48 49
49#include "idmap.h" 50#include "idmap.h"
50#include "acl.h" 51#include "acl.h"
51#include "xdr4.h" 52#include "xdr4.h"
52#include "vfs.h" 53#include "vfs.h"
53 54#include "state.h"
55#include "cache.h"
54 56
55#define NFSDDBG_FACILITY NFSDDBG_XDR 57#define NFSDDBG_FACILITY NFSDDBG_XDR
56 58
@@ -131,6 +133,22 @@ xdr_error: \
131 } \ 133 } \
132} while (0) 134} while (0)
133 135
136static void save_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
137{
138 savep->p = argp->p;
139 savep->end = argp->end;
140 savep->pagelen = argp->pagelen;
141 savep->pagelist = argp->pagelist;
142}
143
144static void restore_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
145{
146 argp->p = savep->p;
147 argp->end = savep->end;
148 argp->pagelen = savep->pagelen;
149 argp->pagelist = savep->pagelist;
150}
151
134static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) 152static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
135{ 153{
136 /* We want more bytes than seem to be available. 154 /* We want more bytes than seem to be available.
@@ -1246,6 +1264,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
1246} 1264}
1247 1265
1248static __be32 1266static __be32
1267nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
1268 struct nfsd4_free_stateid *free_stateid)
1269{
1270 DECODE_HEAD;
1271
1272 READ_BUF(sizeof(stateid_t));
1273 READ32(free_stateid->fr_stateid.si_generation);
1274 COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
1275
1276 DECODE_TAIL;
1277}
1278
1279static __be32
1249nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, 1280nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
1250 struct nfsd4_sequence *seq) 1281 struct nfsd4_sequence *seq)
1251{ 1282{
@@ -1261,6 +1292,40 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
1261 DECODE_TAIL; 1292 DECODE_TAIL;
1262} 1293}
1263 1294
1295static __be32
1296nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
1297{
1298 unsigned int nbytes;
1299 stateid_t si;
1300 int i;
1301 __be32 *p;
1302 __be32 status;
1303
1304 READ_BUF(4);
1305 test_stateid->ts_num_ids = ntohl(*p++);
1306
1307 nbytes = test_stateid->ts_num_ids * sizeof(stateid_t);
1308 if (nbytes > (u32)((char *)argp->end - (char *)argp->p))
1309 goto xdr_error;
1310
1311 test_stateid->ts_saved_args = argp;
1312 save_buf(argp, &test_stateid->ts_savedp);
1313
1314 for (i = 0; i < test_stateid->ts_num_ids; i++) {
1315 status = nfsd4_decode_stateid(argp, &si);
1316 if (status)
1317 return status;
1318 }
1319
1320 status = 0;
1321out:
1322 return status;
1323xdr_error:
1324 dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__);
1325 status = nfserr_bad_xdr;
1326 goto out;
1327}
1328
1264static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) 1329static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc)
1265{ 1330{
1266 DECODE_HEAD; 1331 DECODE_HEAD;
@@ -1370,7 +1435,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
1370 [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, 1435 [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
1371 [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, 1436 [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
1372 [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, 1437 [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
1373 [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, 1438 [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid,
1374 [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 1439 [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
1375 [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, 1440 [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp,
1376 [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, 1441 [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
@@ -1380,7 +1445,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
1380 [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, 1445 [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
1381 [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, 1446 [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
1382 [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, 1447 [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
1383 [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, 1448 [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid,
1384 [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, 1449 [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
1385 [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, 1450 [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp,
1386 [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, 1451 [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
@@ -1402,6 +1467,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1402 DECODE_HEAD; 1467 DECODE_HEAD;
1403 struct nfsd4_op *op; 1468 struct nfsd4_op *op;
1404 struct nfsd4_minorversion_ops *ops; 1469 struct nfsd4_minorversion_ops *ops;
1470 bool cachethis = false;
1405 int i; 1471 int i;
1406 1472
1407 /* 1473 /*
@@ -1483,7 +1549,16 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1483 argp->opcnt = i+1; 1549 argp->opcnt = i+1;
1484 break; 1550 break;
1485 } 1551 }
1552 /*
1553 * We'll try to cache the result in the DRC if any one
1554 * op in the compound wants to be cached:
1555 */
1556 cachethis |= nfsd4_cache_this_op(op);
1486 } 1557 }
1558 /* Sessions make the DRC unnecessary: */
1559 if (argp->minorversion)
1560 cachethis = false;
1561 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
1487 1562
1488 DECODE_TAIL; 1563 DECODE_TAIL;
1489} 1564}
@@ -1548,6 +1623,18 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
1548 \ 1623 \
1549 save = resp->p; 1624 save = resp->p;
1550 1625
1626static bool seqid_mutating_err(__be32 err)
1627{
1628 /* rfc 3530 section 8.1.5: */
1629 return err != nfserr_stale_clientid &&
1630 err != nfserr_stale_stateid &&
1631 err != nfserr_bad_stateid &&
1632 err != nfserr_bad_seqid &&
1633 err != nfserr_bad_xdr &&
1634 err != nfserr_resource &&
1635 err != nfserr_nofilehandle;
1636}
1637
1551/* 1638/*
1552 * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This 1639 * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
1553 * is where sequence id's are incremented, and the replay cache is filled. 1640 * is where sequence id's are incremented, and the replay cache is filled.
@@ -3116,6 +3203,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
3116} 3203}
3117 3204
3118static __be32 3205static __be32
3206nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
3207 struct nfsd4_free_stateid *free_stateid)
3208{
3209 __be32 *p;
3210
3211 if (nfserr)
3212 return nfserr;
3213
3214 RESERVE_SPACE(4);
3215 WRITE32(nfserr);
3216 ADJUST_ARGS();
3217 return nfserr;
3218}
3219
3220static __be32
3119nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, 3221nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
3120 struct nfsd4_sequence *seq) 3222 struct nfsd4_sequence *seq)
3121{ 3223{
@@ -3138,6 +3240,36 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
3138 return 0; 3240 return 0;
3139} 3241}
3140 3242
3243__be32
3244nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
3245 struct nfsd4_test_stateid *test_stateid)
3246{
3247 struct nfsd4_compoundargs *argp;
3248 stateid_t si;
3249 __be32 *p;
3250 int i;
3251 int valid;
3252
3253 restore_buf(test_stateid->ts_saved_args, &test_stateid->ts_savedp);
3254 argp = test_stateid->ts_saved_args;
3255
3256 RESERVE_SPACE(4);
3257 *p++ = htonl(test_stateid->ts_num_ids);
3258 resp->p = p;
3259
3260 nfs4_lock_state();
3261 for (i = 0; i < test_stateid->ts_num_ids; i++) {
3262 nfsd4_decode_stateid(argp, &si);
3263 valid = nfs4_validate_stateid(&si, test_stateid->ts_has_session);
3264 RESERVE_SPACE(4);
3265 *p++ = htonl(valid);
3266 resp->p = p;
3267 }
3268 nfs4_unlock_state();
3269
3270 return nfserr;
3271}
3272
3141static __be32 3273static __be32
3142nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) 3274nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
3143{ 3275{
@@ -3196,7 +3328,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
3196 [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, 3328 [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
3197 [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, 3329 [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
3198 [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, 3330 [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session,
3199 [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, 3331 [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_free_stateid,
3200 [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 3332 [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
3201 [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, 3333 [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
3202 [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, 3334 [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
@@ -3206,7 +3338,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
3206 [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, 3338 [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
3207 [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, 3339 [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
3208 [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, 3340 [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
3209 [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop, 3341 [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid,
3210 [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, 3342 [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
3211 [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop, 3343 [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop,
3212 [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, 3344 [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop,
@@ -3319,8 +3451,11 @@ nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
3319 return xdr_ressize_check(rqstp, p); 3451 return xdr_ressize_check(rqstp, p);
3320} 3452}
3321 3453
3322void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) 3454int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
3323{ 3455{
3456 struct svc_rqst *rqstp = rq;
3457 struct nfsd4_compoundargs *args = rqstp->rq_argp;
3458
3324 if (args->ops != args->iops) { 3459 if (args->ops != args->iops) {
3325 kfree(args->ops); 3460 kfree(args->ops);
3326 args->ops = args->iops; 3461 args->ops = args->iops;
@@ -3333,13 +3468,12 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
3333 tb->release(tb->buf); 3468 tb->release(tb->buf);
3334 kfree(tb); 3469 kfree(tb);
3335 } 3470 }
3471 return 1;
3336} 3472}
3337 3473
3338int 3474int
3339nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args) 3475nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
3340{ 3476{
3341 __be32 status;
3342
3343 args->p = p; 3477 args->p = p;
3344 args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; 3478 args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
3345 args->pagelist = rqstp->rq_arg.pages; 3479 args->pagelist = rqstp->rq_arg.pages;
@@ -3349,11 +3483,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_comp
3349 args->ops = args->iops; 3483 args->ops = args->iops;
3350 args->rqstp = rqstp; 3484 args->rqstp = rqstp;
3351 3485
3352 status = nfsd4_decode_compound(args); 3486 return !nfsd4_decode_compound(args);
3353 if (status) {
3354 nfsd4_release_compoundargs(args);
3355 }
3356 return !status;
3357} 3487}
3358 3488
3359int 3489int
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 4666a209678..2cbac34a55d 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -118,7 +118,7 @@ hash_refile(struct svc_cacherep *rp)
118 * Note that no operation within the loop may sleep. 118 * Note that no operation within the loop may sleep.
119 */ 119 */
120int 120int
121nfsd_cache_lookup(struct svc_rqst *rqstp, int type) 121nfsd_cache_lookup(struct svc_rqst *rqstp)
122{ 122{
123 struct hlist_node *hn; 123 struct hlist_node *hn;
124 struct hlist_head *rh; 124 struct hlist_head *rh;
@@ -128,6 +128,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
128 vers = rqstp->rq_vers, 128 vers = rqstp->rq_vers,
129 proc = rqstp->rq_proc; 129 proc = rqstp->rq_proc;
130 unsigned long age; 130 unsigned long age;
131 int type = rqstp->rq_cachetype;
131 int rtn; 132 int rtn;
132 133
133 rqstp->rq_cacherep = NULL; 134 rqstp->rq_cacherep = NULL;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 2b1449dd2f4..c7716143cbd 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -24,15 +24,6 @@
24 */ 24 */
25enum { 25enum {
26 NFSD_Root = 1, 26 NFSD_Root = 1,
27#ifdef CONFIG_NFSD_DEPRECATED
28 NFSD_Svc,
29 NFSD_Add,
30 NFSD_Del,
31 NFSD_Export,
32 NFSD_Unexport,
33 NFSD_Getfd,
34 NFSD_Getfs,
35#endif
36 NFSD_List, 27 NFSD_List,
37 NFSD_Export_features, 28 NFSD_Export_features,
38 NFSD_Fh, 29 NFSD_Fh,
@@ -59,15 +50,6 @@ enum {
59/* 50/*
60 * write() for these nodes. 51 * write() for these nodes.
61 */ 52 */
62#ifdef CONFIG_NFSD_DEPRECATED
63static ssize_t write_svc(struct file *file, char *buf, size_t size);
64static ssize_t write_add(struct file *file, char *buf, size_t size);
65static ssize_t write_del(struct file *file, char *buf, size_t size);
66static ssize_t write_export(struct file *file, char *buf, size_t size);
67static ssize_t write_unexport(struct file *file, char *buf, size_t size);
68static ssize_t write_getfd(struct file *file, char *buf, size_t size);
69static ssize_t write_getfs(struct file *file, char *buf, size_t size);
70#endif
71static ssize_t write_filehandle(struct file *file, char *buf, size_t size); 53static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
72static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size); 54static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
73static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size); 55static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
@@ -83,15 +65,6 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
83#endif 65#endif
84 66
85static ssize_t (*write_op[])(struct file *, char *, size_t) = { 67static ssize_t (*write_op[])(struct file *, char *, size_t) = {
86#ifdef CONFIG_NFSD_DEPRECATED
87 [NFSD_Svc] = write_svc,
88 [NFSD_Add] = write_add,
89 [NFSD_Del] = write_del,
90 [NFSD_Export] = write_export,
91 [NFSD_Unexport] = write_unexport,
92 [NFSD_Getfd] = write_getfd,
93 [NFSD_Getfs] = write_getfs,
94#endif
95 [NFSD_Fh] = write_filehandle, 68 [NFSD_Fh] = write_filehandle,
96 [NFSD_FO_UnlockIP] = write_unlock_ip, 69 [NFSD_FO_UnlockIP] = write_unlock_ip,
97 [NFSD_FO_UnlockFS] = write_unlock_fs, 70 [NFSD_FO_UnlockFS] = write_unlock_fs,
@@ -130,16 +103,6 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu
130 103
131static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) 104static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
132{ 105{
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
143 if (! file->private_data) { 106 if (! file->private_data) {
144 /* An attempt to read a transaction file without writing 107 /* An attempt to read a transaction file without writing
145 * causes a 0-byte write so that the file can return 108 * causes a 0-byte write so that the file can return
@@ -226,303 +189,6 @@ static const struct file_operations pool_stats_operations = {
226 * payload - write methods 189 * payload - write methods
227 */ 190 */
228 191
229#ifdef CONFIG_NFSD_DEPRECATED
230/**
231 * write_svc - Start kernel's NFSD server
232 *
233 * Deprecated. /proc/fs/nfsd/threads is preferred.
234 * Function remains to support old versions of nfs-utils.
235 *
236 * Input:
237 * buf: struct nfsctl_svc
238 * svc_port: port number of this
239 * server's listener
240 * svc_nthreads: number of threads to start
241 * size: size in bytes of passed in nfsctl_svc
242 * Output:
243 * On success: returns zero
244 * On error: return code is negative errno value
245 */
246static ssize_t write_svc(struct file *file, char *buf, size_t size)
247{
248 struct nfsctl_svc *data;
249 int err;
250 if (size < sizeof(*data))
251 return -EINVAL;
252 data = (struct nfsctl_svc*) buf;
253 err = nfsd_svc(data->svc_port, data->svc_nthreads);
254 if (err < 0)
255 return err;
256 return 0;
257}
258
259/**
260 * write_add - Add or modify client entry in auth unix cache
261 *
262 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
263 * Function remains to support old versions of nfs-utils.
264 *
265 * Input:
266 * buf: struct nfsctl_client
267 * cl_ident: '\0'-terminated C string
268 * containing domain name
269 * of client
270 * cl_naddr: no. of items in cl_addrlist
271 * cl_addrlist: array of client addresses
272 * cl_fhkeytype: ignored
273 * cl_fhkeylen: ignored
274 * cl_fhkey: ignored
275 * size: size in bytes of passed in nfsctl_client
276 * Output:
277 * On success: returns zero
278 * On error: return code is negative errno value
279 *
280 * Note: Only AF_INET client addresses are passed in, since
281 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
282 */
283static ssize_t write_add(struct file *file, char *buf, size_t size)
284{
285 struct nfsctl_client *data;
286 if (size < sizeof(*data))
287 return -EINVAL;
288 data = (struct nfsctl_client *)buf;
289 return exp_addclient(data);
290}
291
292/**
293 * write_del - Remove client from auth unix cache
294 *
295 * Deprecated. /proc/net/rpc/auth.unix.ip is preferred.
296 * Function remains to support old versions of nfs-utils.
297 *
298 * Input:
299 * buf: struct nfsctl_client
300 * cl_ident: '\0'-terminated C string
301 * containing domain name
302 * of client
303 * cl_naddr: ignored
304 * cl_addrlist: ignored
305 * cl_fhkeytype: ignored
306 * cl_fhkeylen: ignored
307 * cl_fhkey: ignored
308 * size: size in bytes of passed in nfsctl_client
309 * Output:
310 * On success: returns zero
311 * On error: return code is negative errno value
312 *
313 * Note: Only AF_INET client addresses are passed in, since
314 * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
315 */
316static ssize_t write_del(struct file *file, char *buf, size_t size)
317{
318 struct nfsctl_client *data;
319 if (size < sizeof(*data))
320 return -EINVAL;
321 data = (struct nfsctl_client *)buf;
322 return exp_delclient(data);
323}
324
325/**
326 * write_export - Export part or all of a local file system
327 *
328 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
329 * Function remains to support old versions of nfs-utils.
330 *
331 * Input:
332 * buf: struct nfsctl_export
333 * ex_client: '\0'-terminated C string
334 * containing domain name
335 * of client allowed to access
336 * this export
337 * ex_path: '\0'-terminated C string
338 * containing pathname of
339 * directory in local file system
340 * ex_dev: fsid to use for this export
341 * ex_ino: ignored
342 * ex_flags: export flags for this export
343 * ex_anon_uid: UID to use for anonymous
344 * requests
345 * ex_anon_gid: GID to use for anonymous
346 * requests
347 * size: size in bytes of passed in nfsctl_export
348 * Output:
349 * On success: returns zero
350 * On error: return code is negative errno value
351 */
352static ssize_t write_export(struct file *file, char *buf, size_t size)
353{
354 struct nfsctl_export *data;
355 if (size < sizeof(*data))
356 return -EINVAL;
357 data = (struct nfsctl_export*)buf;
358 return exp_export(data);
359}
360
361/**
362 * write_unexport - Unexport a previously exported file system
363 *
364 * Deprecated. /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
365 * Function remains to support old versions of nfs-utils.
366 *
367 * Input:
368 * buf: struct nfsctl_export
369 * ex_client: '\0'-terminated C string
370 * containing domain name
371 * of client no longer allowed
372 * to access this export
373 * ex_path: '\0'-terminated C string
374 * containing pathname of
375 * directory in local file system
376 * ex_dev: ignored
377 * ex_ino: ignored
378 * ex_flags: ignored
379 * ex_anon_uid: ignored
380 * ex_anon_gid: ignored
381 * size: size in bytes of passed in nfsctl_export
382 * Output:
383 * On success: returns zero
384 * On error: return code is negative errno value
385 */
386static ssize_t write_unexport(struct file *file, char *buf, size_t size)
387{
388 struct nfsctl_export *data;
389
390 if (size < sizeof(*data))
391 return -EINVAL;
392 data = (struct nfsctl_export*)buf;
393 return exp_unexport(data);
394}
395
396/**
397 * write_getfs - Get a variable-length NFS file handle by path
398 *
399 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
400 * Function remains to support old versions of nfs-utils.
401 *
402 * Input:
403 * buf: struct nfsctl_fsparm
404 * gd_addr: socket address of client
405 * gd_path: '\0'-terminated C string
406 * containing pathname of
407 * directory in local file system
408 * gd_maxlen: maximum size of returned file
409 * handle
410 * size: size in bytes of passed in nfsctl_fsparm
411 * Output:
412 * On success: passed-in buffer filled with a knfsd_fh structure
413 * (a variable-length raw NFS file handle);
414 * return code is the size in bytes of the file handle
415 * On error: return code is negative errno value
416 *
417 * Note: Only AF_INET client addresses are passed in, since gd_addr
418 * is the same size as a struct sockaddr_in.
419 */
420static ssize_t write_getfs(struct file *file, char *buf, size_t size)
421{
422 struct nfsctl_fsparm *data;
423 struct sockaddr_in *sin;
424 struct auth_domain *clp;
425 int err = 0;
426 struct knfsd_fh *res;
427 struct in6_addr in6;
428
429 if (size < sizeof(*data))
430 return -EINVAL;
431 data = (struct nfsctl_fsparm*)buf;
432 err = -EPROTONOSUPPORT;
433 if (data->gd_addr.sa_family != AF_INET)
434 goto out;
435 sin = (struct sockaddr_in *)&data->gd_addr;
436 if (data->gd_maxlen > NFS3_FHSIZE)
437 data->gd_maxlen = NFS3_FHSIZE;
438
439 res = (struct knfsd_fh*)buf;
440
441 exp_readlock();
442
443 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
444
445 clp = auth_unix_lookup(&init_net, &in6);
446 if (!clp)
447 err = -EPERM;
448 else {
449 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
450 auth_domain_put(clp);
451 }
452 exp_readunlock();
453 if (err == 0)
454 err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
455 out:
456 return err;
457}
458
459/**
460 * write_getfd - Get a fixed-length NFS file handle by path (used by mountd)
461 *
462 * Deprecated. /proc/fs/nfsd/filehandle is preferred.
463 * Function remains to support old versions of nfs-utils.
464 *
465 * Input:
466 * buf: struct nfsctl_fdparm
467 * gd_addr: socket address of client
468 * gd_path: '\0'-terminated C string
469 * containing pathname of
470 * directory in local file system
471 * gd_version: fdparm structure version
472 * size: size in bytes of passed in nfsctl_fdparm
473 * Output:
474 * On success: passed-in buffer filled with nfsctl_res
475 * (a fixed-length raw NFS file handle);
476 * return code is the size in bytes of the file handle
477 * On error: return code is negative errno value
478 *
479 * Note: Only AF_INET client addresses are passed in, since gd_addr
480 * is the same size as a struct sockaddr_in.
481 */
482static ssize_t write_getfd(struct file *file, char *buf, size_t size)
483{
484 struct nfsctl_fdparm *data;
485 struct sockaddr_in *sin;
486 struct auth_domain *clp;
487 int err = 0;
488 struct knfsd_fh fh;
489 char *res;
490 struct in6_addr in6;
491
492 if (size < sizeof(*data))
493 return -EINVAL;
494 data = (struct nfsctl_fdparm*)buf;
495 err = -EPROTONOSUPPORT;
496 if (data->gd_addr.sa_family != AF_INET)
497 goto out;
498 err = -EINVAL;
499 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
500 goto out;
501
502 res = buf;
503 sin = (struct sockaddr_in *)&data->gd_addr;
504 exp_readlock();
505
506 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
507
508 clp = auth_unix_lookup(&init_net, &in6);
509 if (!clp)
510 err = -EPERM;
511 else {
512 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
513 auth_domain_put(clp);
514 }
515 exp_readunlock();
516
517 if (err == 0) {
518 memset(res,0, NFS_FHSIZE);
519 memcpy(res, &fh.fh_base, fh.fh_size);
520 err = NFS_FHSIZE;
521 }
522 out:
523 return err;
524}
525#endif /* CONFIG_NFSD_DEPRECATED */
526 192
527/** 193/**
528 * write_unlock_ip - Release all locks used by a client 194 * write_unlock_ip - Release all locks used by a client
@@ -1397,15 +1063,6 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
1397static int nfsd_fill_super(struct super_block * sb, void * data, int silent) 1063static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1398{ 1064{
1399 static struct tree_descr nfsd_files[] = { 1065 static struct tree_descr nfsd_files[] = {
1400#ifdef CONFIG_NFSD_DEPRECATED
1401 [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
1402 [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
1403 [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
1404 [NFSD_Export] = {".export", &transaction_ops, S_IWUSR},
1405 [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
1406 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
1407 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
1408#endif
1409 [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, 1066 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
1410 [NFSD_Export_features] = {"export_features", 1067 [NFSD_Export_features] = {"export_features",
1411 &export_features_operations, S_IRUGO}, 1068 &export_features_operations, S_IRUGO},
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 18743c4d8bc..dc5a1bf476b 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -528,16 +528,9 @@ nfsd(void *vrqstp)
528 continue; 528 continue;
529 } 529 }
530 530
531
532 /* Lock the export hash tables for reading. */
533 exp_readlock();
534
535 validate_process_creds(); 531 validate_process_creds();
536 svc_process(rqstp); 532 svc_process(rqstp);
537 validate_process_creds(); 533 validate_process_creds();
538
539 /* Unlock export hash tables */
540 exp_readunlock();
541 } 534 }
542 535
543 /* Clear signals before calling svc_exit_thread() */ 536 /* Clear signals before calling svc_exit_thread() */
@@ -577,8 +570,22 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
577 rqstp->rq_vers, rqstp->rq_proc); 570 rqstp->rq_vers, rqstp->rq_proc);
578 proc = rqstp->rq_procinfo; 571 proc = rqstp->rq_procinfo;
579 572
573 /*
574 * Give the xdr decoder a chance to change this if it wants
575 * (necessary in the NFSv4.0 compound case)
576 */
577 rqstp->rq_cachetype = proc->pc_cachetype;
578 /* Decode arguments */
579 xdr = proc->pc_decode;
580 if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
581 rqstp->rq_argp)) {
582 dprintk("nfsd: failed to decode arguments!\n");
583 *statp = rpc_garbage_args;
584 return 1;
585 }
586
580 /* Check whether we have this call in the cache. */ 587 /* Check whether we have this call in the cache. */
581 switch (nfsd_cache_lookup(rqstp, proc->pc_cachetype)) { 588 switch (nfsd_cache_lookup(rqstp)) {
582 case RC_INTR: 589 case RC_INTR:
583 case RC_DROPIT: 590 case RC_DROPIT:
584 return 0; 591 return 0;
@@ -588,16 +595,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
588 /* do it */ 595 /* do it */
589 } 596 }
590 597
591 /* Decode arguments */
592 xdr = proc->pc_decode;
593 if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
594 rqstp->rq_argp)) {
595 dprintk("nfsd: failed to decode arguments!\n");
596 nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
597 *statp = rpc_garbage_args;
598 return 1;
599 }
600
601 /* need to grab the location to store the status, as 598 /* need to grab the location to store the status, as
602 * nfsv4 does some encoding while processing 599 * nfsv4 does some encoding while processing
603 */ 600 */
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 6bd2f3c21f2..5cfebe50405 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -447,12 +447,6 @@ struct nfs4_stateid {
447#define WR_STATE 0x00000020 447#define WR_STATE 0x00000020
448#define CLOSE_STATE 0x00000040 448#define CLOSE_STATE 0x00000040
449 449
450#define seqid_mutating_err(err) \
451 (((err) != nfserr_stale_clientid) && \
452 ((err) != nfserr_bad_seqid) && \
453 ((err) != nfserr_stale_stateid) && \
454 ((err) != nfserr_bad_stateid))
455
456struct nfsd4_compound_state; 450struct nfsd4_compound_state;
457 451
458extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, 452extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
@@ -482,6 +476,7 @@ extern void nfsd4_recdir_purge_old(void);
482extern int nfsd4_create_clid_dir(struct nfs4_client *clp); 476extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
483extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); 477extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
484extern void release_session_client(struct nfsd4_session *); 478extern void release_session_client(struct nfsd4_session *);
479extern __be32 nfs4_validate_stateid(stateid_t *, int);
485 480
486static inline void 481static inline void
487nfs4_put_stateowner(struct nfs4_stateowner *so) 482nfs4_put_stateowner(struct nfs4_stateowner *so)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index fd0acca5370..acf88aea211 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -2114,7 +2114,8 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
2114 2114
2115 /* Allow read access to binaries even when mode 111 */ 2115 /* Allow read access to binaries even when mode 111 */
2116 if (err == -EACCES && S_ISREG(inode->i_mode) && 2116 if (err == -EACCES && S_ISREG(inode->i_mode) &&
2117 acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) 2117 (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) ||
2118 acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC)))
2118 err = inode_permission(inode, MAY_EXEC); 2119 err = inode_permission(inode, MAY_EXEC);
2119 2120
2120 return err? nfserrno(err) : 0; 2121 return err? nfserrno(err) : 0;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index e0bbac04d1d..a22e40e2786 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -25,6 +25,7 @@
25#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256 25#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
26#define NFSD_MAY_NOT_BREAK_LEASE 512 26#define NFSD_MAY_NOT_BREAK_LEASE 512
27#define NFSD_MAY_BYPASS_GSS 1024 27#define NFSD_MAY_BYPASS_GSS 1024
28#define NFSD_MAY_READ_IF_EXEC 2048
28 29
29#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) 30#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
30#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) 31#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 366401e1a53..d2a8d04428c 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -342,6 +342,25 @@ struct nfsd4_setclientid_confirm {
342 nfs4_verifier sc_confirm; 342 nfs4_verifier sc_confirm;
343}; 343};
344 344
345struct nfsd4_saved_compoundargs {
346 __be32 *p;
347 __be32 *end;
348 int pagelen;
349 struct page **pagelist;
350};
351
352struct nfsd4_test_stateid {
353 __be32 ts_num_ids;
354 __be32 ts_has_session;
355 struct nfsd4_compoundargs *ts_saved_args;
356 struct nfsd4_saved_compoundargs ts_savedp;
357};
358
359struct nfsd4_free_stateid {
360 stateid_t fr_stateid; /* request */
361 __be32 fr_status; /* response */
362};
363
345/* also used for NVERIFY */ 364/* also used for NVERIFY */
346struct nfsd4_verify { 365struct nfsd4_verify {
347 u32 ve_bmval[3]; /* request */ 366 u32 ve_bmval[3]; /* request */
@@ -432,10 +451,14 @@ struct nfsd4_op {
432 struct nfsd4_destroy_session destroy_session; 451 struct nfsd4_destroy_session destroy_session;
433 struct nfsd4_sequence sequence; 452 struct nfsd4_sequence sequence;
434 struct nfsd4_reclaim_complete reclaim_complete; 453 struct nfsd4_reclaim_complete reclaim_complete;
454 struct nfsd4_test_stateid test_stateid;
455 struct nfsd4_free_stateid free_stateid;
435 } u; 456 } u;
436 struct nfs4_replay * replay; 457 struct nfs4_replay * replay;
437}; 458};
438 459
460bool nfsd4_cache_this_op(struct nfsd4_op *);
461
439struct nfsd4_compoundargs { 462struct nfsd4_compoundargs {
440 /* scratch variables for XDR decode */ 463 /* scratch variables for XDR decode */
441 __be32 * p; 464 __be32 * p;
@@ -458,6 +481,7 @@ struct nfsd4_compoundargs {
458 u32 opcnt; 481 u32 opcnt;
459 struct nfsd4_op *ops; 482 struct nfsd4_op *ops;
460 struct nfsd4_op iops[8]; 483 struct nfsd4_op iops[8];
484 int cachetype;
461}; 485};
462 486
463struct nfsd4_compoundres { 487struct nfsd4_compoundres {
@@ -559,11 +583,15 @@ extern __be32
559nfsd4_release_lockowner(struct svc_rqst *rqstp, 583nfsd4_release_lockowner(struct svc_rqst *rqstp,
560 struct nfsd4_compound_state *, 584 struct nfsd4_compound_state *,
561 struct nfsd4_release_lockowner *rlockowner); 585 struct nfsd4_release_lockowner *rlockowner);
562extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *); 586extern int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp);
563extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp, 587extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
564 struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr); 588 struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
565extern __be32 nfsd4_renew(struct svc_rqst *rqstp, 589extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
566 struct nfsd4_compound_state *, clientid_t *clid); 590 struct nfsd4_compound_state *, clientid_t *clid);
591extern __be32 nfsd4_test_stateid(struct svc_rqst *rqstp,
592 struct nfsd4_compound_state *, struct nfsd4_test_stateid *test_stateid);
593extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
594 struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
567#endif 595#endif
568 596
569/* 597/*