aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2007-07-18 20:38:57 -0400
committerSteve French <sfrench@us.ibm.com>2007-07-18 20:38:57 -0400
commit1ff8392c32a2645d2665ca779ecb91bb29361c13 (patch)
tree860b95e9a499ade4060848740fc6ce1fbb4e4e8d /fs/nfsd
parent70b315b0dd3879cb3ab8aadffb14f10b2d19b9c3 (diff)
parent5bae7ac9feba925fd0099057f6b23d7be80b7b41 (diff)
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: fs/cifs/export.c
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/auth.c18
-rw-r--r--fs/nfsd/export.c289
-rw-r--r--fs/nfsd/lockd.c1
-rw-r--r--fs/nfsd/nfs4acl.c12
-rw-r--r--fs/nfsd/nfs4callback.c20
-rw-r--r--fs/nfsd/nfs4idmap.c13
-rw-r--r--fs/nfsd/nfs4proc.c35
-rw-r--r--fs/nfsd/nfs4state.c47
-rw-r--r--fs/nfsd/nfs4xdr.c101
-rw-r--r--fs/nfsd/nfsctl.c3
-rw-r--r--fs/nfsd/nfsfh.c51
-rw-r--r--fs/nfsd/nfsproc.c3
-rw-r--r--fs/nfsd/nfssvc.c12
-rw-r--r--fs/nfsd/vfs.c156
14 files changed, 587 insertions, 174 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 6e92b0fe5323..cf61dc8ae942 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -12,17 +12,31 @@
12 12
13#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) 13#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
14 14
15static int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
16{
17 struct exp_flavor_info *f;
18 struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
19
20 for (f = exp->ex_flavors; f < end; f++) {
21 if (f->pseudoflavor == rqstp->rq_flavor)
22 return f->flags;
23 }
24 return exp->ex_flags;
25
26}
27
15int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) 28int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
16{ 29{
17 struct svc_cred cred = rqstp->rq_cred; 30 struct svc_cred cred = rqstp->rq_cred;
18 int i; 31 int i;
32 int flags = nfsexp_flags(rqstp, exp);
19 int ret; 33 int ret;
20 34
21 if (exp->ex_flags & NFSEXP_ALLSQUASH) { 35 if (flags & NFSEXP_ALLSQUASH) {
22 cred.cr_uid = exp->ex_anon_uid; 36 cred.cr_uid = exp->ex_anon_uid;
23 cred.cr_gid = exp->ex_anon_gid; 37 cred.cr_gid = exp->ex_anon_gid;
24 cred.cr_group_info = groups_alloc(0); 38 cred.cr_group_info = groups_alloc(0);
25 } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) { 39 } else if (flags & NFSEXP_ROOTSQUASH) {
26 struct group_info *gi; 40 struct group_info *gi;
27 if (!cred.cr_uid) 41 if (!cred.cr_uid)
28 cred.cr_uid = exp->ex_anon_uid; 42 cred.cr_uid = exp->ex_anon_uid;
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 79bd03b8bbf8..c7bbf460b009 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -26,12 +26,15 @@
26#include <linux/mount.h> 26#include <linux/mount.h>
27#include <linux/hash.h> 27#include <linux/hash.h>
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/exportfs.h>
29 30
30#include <linux/sunrpc/svc.h> 31#include <linux/sunrpc/svc.h>
31#include <linux/nfsd/nfsd.h> 32#include <linux/nfsd/nfsd.h>
32#include <linux/nfsd/nfsfh.h> 33#include <linux/nfsd/nfsfh.h>
33#include <linux/nfsd/syscall.h> 34#include <linux/nfsd/syscall.h>
34#include <linux/lockd/bind.h> 35#include <linux/lockd/bind.h>
36#include <linux/sunrpc/msg_prot.h>
37#include <linux/sunrpc/gss_api.h>
35 38
36#define NFSDDBG_FACILITY NFSDDBG_EXPORT 39#define NFSDDBG_FACILITY NFSDDBG_EXPORT
37 40
@@ -451,8 +454,48 @@ out_free_all:
451 return err; 454 return err;
452} 455}
453 456
457static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
458{
459 int listsize, err;
460 struct exp_flavor_info *f;
461
462 err = get_int(mesg, &listsize);
463 if (err)
464 return err;
465 if (listsize < 0 || listsize > MAX_SECINFO_LIST)
466 return -EINVAL;
467
468 for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
469 err = get_int(mesg, &f->pseudoflavor);
470 if (err)
471 return err;
472 /*
473 * Just a quick sanity check; we could also try to check
474 * whether this pseudoflavor is supported, but at worst
475 * an unsupported pseudoflavor on the export would just
476 * be a pseudoflavor that won't match the flavor of any
477 * authenticated request. The administrator will
478 * probably discover the problem when someone fails to
479 * authenticate.
480 */
481 if (f->pseudoflavor < 0)
482 return -EINVAL;
483 err = get_int(mesg, &f->flags);
484 if (err)
485 return err;
486 /* Only some flags are allowed to differ between flavors: */
487 if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
488 return -EINVAL;
489 }
490 exp->ex_nflavors = listsize;
491 return 0;
492}
493
454#else /* CONFIG_NFSD_V4 */ 494#else /* CONFIG_NFSD_V4 */
455static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; } 495static inline int
496fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
497static inline int
498secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
456#endif 499#endif
457 500
458static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) 501static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
@@ -476,6 +519,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
476 519
477 exp.ex_uuid = NULL; 520 exp.ex_uuid = NULL;
478 521
522 /* secinfo */
523 exp.ex_nflavors = 0;
524
479 if (mesg[mlen-1] != '\n') 525 if (mesg[mlen-1] != '\n')
480 return -EINVAL; 526 return -EINVAL;
481 mesg[mlen-1] = 0; 527 mesg[mlen-1] = 0;
@@ -553,7 +599,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
553 if (exp.ex_uuid == NULL) 599 if (exp.ex_uuid == NULL)
554 err = -ENOMEM; 600 err = -ENOMEM;
555 } 601 }
556 } else 602 } else if (strcmp(buf, "secinfo") == 0)
603 err = secinfo_parse(&mesg, buf, &exp);
604 else
557 /* quietly ignore unknown words and anything 605 /* quietly ignore unknown words and anything
558 * following. Newer user-space can try to set 606 * following. Newer user-space can try to set
559 * new values, then see what the result was. 607 * new values, then see what the result was.
@@ -593,6 +641,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
593 641
594static void exp_flags(struct seq_file *m, int flag, int fsid, 642static void exp_flags(struct seq_file *m, int flag, int fsid,
595 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); 643 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
644static void show_secinfo(struct seq_file *m, struct svc_export *exp);
596 645
597static int svc_export_show(struct seq_file *m, 646static int svc_export_show(struct seq_file *m,
598 struct cache_detail *cd, 647 struct cache_detail *cd,
@@ -622,6 +671,7 @@ static int svc_export_show(struct seq_file *m,
622 seq_printf(m, "%02x", exp->ex_uuid[i]); 671 seq_printf(m, "%02x", exp->ex_uuid[i]);
623 } 672 }
624 } 673 }
674 show_secinfo(m, exp);
625 } 675 }
626 seq_puts(m, ")\n"); 676 seq_puts(m, ")\n");
627 return 0; 677 return 0;
@@ -654,6 +704,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
654{ 704{
655 struct svc_export *new = container_of(cnew, struct svc_export, h); 705 struct svc_export *new = container_of(cnew, struct svc_export, h);
656 struct svc_export *item = container_of(citem, struct svc_export, h); 706 struct svc_export *item = container_of(citem, struct svc_export, h);
707 int i;
657 708
658 new->ex_flags = item->ex_flags; 709 new->ex_flags = item->ex_flags;
659 new->ex_anon_uid = item->ex_anon_uid; 710 new->ex_anon_uid = item->ex_anon_uid;
@@ -669,6 +720,10 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
669 item->ex_fslocs.locations_count = 0; 720 item->ex_fslocs.locations_count = 0;
670 new->ex_fslocs.migrated = item->ex_fslocs.migrated; 721 new->ex_fslocs.migrated = item->ex_fslocs.migrated;
671 item->ex_fslocs.migrated = 0; 722 item->ex_fslocs.migrated = 0;
723 new->ex_nflavors = item->ex_nflavors;
724 for (i = 0; i < MAX_SECINFO_LIST; i++) {
725 new->ex_flavors[i] = item->ex_flavors[i];
726 }
672} 727}
673 728
674static struct cache_head *svc_export_alloc(void) 729static struct cache_head *svc_export_alloc(void)
@@ -738,16 +793,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
738 int err; 793 int err;
739 794
740 if (!clp) 795 if (!clp)
741 return NULL; 796 return ERR_PTR(-ENOENT);
742 797
743 key.ek_client = clp; 798 key.ek_client = clp;
744 key.ek_fsidtype = fsid_type; 799 key.ek_fsidtype = fsid_type;
745 memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); 800 memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
746 801
747 ek = svc_expkey_lookup(&key); 802 ek = svc_expkey_lookup(&key);
748 if (ek != NULL) 803 if (ek == NULL)
749 if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) 804 return ERR_PTR(-ENOMEM);
750 ek = ERR_PTR(err); 805 err = cache_check(&svc_expkey_cache, &ek->h, reqp);
806 if (err)
807 return ERR_PTR(err);
751 return ek; 808 return ek;
752} 809}
753 810
@@ -808,30 +865,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
808 struct cache_req *reqp) 865 struct cache_req *reqp)
809{ 866{
810 struct svc_export *exp, key; 867 struct svc_export *exp, key;
868 int err;
811 869
812 if (!clp) 870 if (!clp)
813 return NULL; 871 return ERR_PTR(-ENOENT);
814 872
815 key.ex_client = clp; 873 key.ex_client = clp;
816 key.ex_mnt = mnt; 874 key.ex_mnt = mnt;
817 key.ex_dentry = dentry; 875 key.ex_dentry = dentry;
818 876
819 exp = svc_export_lookup(&key); 877 exp = svc_export_lookup(&key);
820 if (exp != NULL) { 878 if (exp == NULL)
821 int err; 879 return ERR_PTR(-ENOMEM);
822 880 err = cache_check(&svc_export_cache, &exp->h, reqp);
823 err = cache_check(&svc_export_cache, &exp->h, reqp); 881 if (err)
824 switch (err) { 882 return ERR_PTR(err);
825 case 0: break;
826 case -EAGAIN:
827 case -ETIMEDOUT:
828 exp = ERR_PTR(err);
829 break;
830 default:
831 exp = NULL;
832 }
833 }
834
835 return exp; 883 return exp;
836} 884}
837 885
@@ -847,7 +895,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
847 dget(dentry); 895 dget(dentry);
848 exp = exp_get_by_name(clp, mnt, dentry, reqp); 896 exp = exp_get_by_name(clp, mnt, dentry, reqp);
849 897
850 while (exp == NULL && !IS_ROOT(dentry)) { 898 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
851 struct dentry *parent; 899 struct dentry *parent;
852 900
853 parent = dget_parent(dentry); 901 parent = dget_parent(dentry);
@@ -900,7 +948,7 @@ static void exp_fsid_unhash(struct svc_export *exp)
900 return; 948 return;
901 949
902 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); 950 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
903 if (ek && !IS_ERR(ek)) { 951 if (!IS_ERR(ek)) {
904 ek->h.expiry_time = get_seconds()-1; 952 ek->h.expiry_time = get_seconds()-1;
905 cache_put(&ek->h, &svc_expkey_cache); 953 cache_put(&ek->h, &svc_expkey_cache);
906 } 954 }
@@ -938,7 +986,7 @@ static void exp_unhash(struct svc_export *exp)
938 struct inode *inode = exp->ex_dentry->d_inode; 986 struct inode *inode = exp->ex_dentry->d_inode;
939 987
940 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); 988 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
941 if (ek && !IS_ERR(ek)) { 989 if (!IS_ERR(ek)) {
942 ek->h.expiry_time = get_seconds()-1; 990 ek->h.expiry_time = get_seconds()-1;
943 cache_put(&ek->h, &svc_expkey_cache); 991 cache_put(&ek->h, &svc_expkey_cache);
944 } 992 }
@@ -989,13 +1037,12 @@ exp_export(struct nfsctl_export *nxp)
989 1037
990 /* must make sure there won't be an ex_fsid clash */ 1038 /* must make sure there won't be an ex_fsid clash */
991 if ((nxp->ex_flags & NFSEXP_FSID) && 1039 if ((nxp->ex_flags & NFSEXP_FSID) &&
992 (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && 1040 (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
993 !IS_ERR(fsid_key) &&
994 fsid_key->ek_mnt && 1041 fsid_key->ek_mnt &&
995 (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) 1042 (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
996 goto finish; 1043 goto finish;
997 1044
998 if (exp) { 1045 if (!IS_ERR(exp)) {
999 /* just a flags/id/fsid update */ 1046 /* just a flags/id/fsid update */
1000 1047
1001 exp_fsid_unhash(exp); 1048 exp_fsid_unhash(exp);
@@ -1104,7 +1151,7 @@ exp_unexport(struct nfsctl_export *nxp)
1104 err = -EINVAL; 1151 err = -EINVAL;
1105 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); 1152 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
1106 path_release(&nd); 1153 path_release(&nd);
1107 if (!exp) 1154 if (IS_ERR(exp))
1108 goto out_domain; 1155 goto out_domain;
1109 1156
1110 exp_do_unexport(exp); 1157 exp_do_unexport(exp);
@@ -1149,10 +1196,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
1149 err = PTR_ERR(exp); 1196 err = PTR_ERR(exp);
1150 goto out; 1197 goto out;
1151 } 1198 }
1152 if (!exp) {
1153 dprintk("nfsd: exp_rootfh export not found.\n");
1154 goto out;
1155 }
1156 1199
1157 /* 1200 /*
1158 * fh must be initialized before calling fh_compose 1201 * fh must be initialized before calling fh_compose
@@ -1176,17 +1219,130 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
1176{ 1219{
1177 struct svc_export *exp; 1220 struct svc_export *exp;
1178 struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); 1221 struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
1179 if (!ek || IS_ERR(ek)) 1222 if (IS_ERR(ek))
1180 return ERR_PTR(PTR_ERR(ek)); 1223 return ERR_PTR(PTR_ERR(ek));
1181 1224
1182 exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); 1225 exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
1183 cache_put(&ek->h, &svc_expkey_cache); 1226 cache_put(&ek->h, &svc_expkey_cache);
1184 1227
1185 if (!exp || IS_ERR(exp)) 1228 if (IS_ERR(exp))
1186 return ERR_PTR(PTR_ERR(exp)); 1229 return ERR_PTR(PTR_ERR(exp));
1187 return exp; 1230 return exp;
1188} 1231}
1189 1232
1233__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
1234{
1235 struct exp_flavor_info *f;
1236 struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1237
1238 /* legacy gss-only clients are always OK: */
1239 if (exp->ex_client == rqstp->rq_gssclient)
1240 return 0;
1241 /* ip-address based client; check sec= export option: */
1242 for (f = exp->ex_flavors; f < end; f++) {
1243 if (f->pseudoflavor == rqstp->rq_flavor)
1244 return 0;
1245 }
1246 /* defaults in absence of sec= options: */
1247 if (exp->ex_nflavors == 0) {
1248 if (rqstp->rq_flavor == RPC_AUTH_NULL ||
1249 rqstp->rq_flavor == RPC_AUTH_UNIX)
1250 return 0;
1251 }
1252 return nfserr_wrongsec;
1253}
1254
1255/*
1256 * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
1257 * auth_unix client) if it's available and has secinfo information;
1258 * otherwise, will try to use rq_gssclient.
1259 *
1260 * Called from functions that handle requests; functions that do work on
1261 * behalf of mountd are passed a single client name to use, and should
1262 * use exp_get_by_name() or exp_find().
1263 */
1264struct svc_export *
1265rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
1266 struct dentry *dentry)
1267{
1268 struct svc_export *gssexp, *exp = NULL;
1269
1270 if (rqstp->rq_client == NULL)
1271 goto gss;
1272
1273 /* First try the auth_unix client: */
1274 exp = exp_get_by_name(rqstp->rq_client, mnt, dentry,
1275 &rqstp->rq_chandle);
1276 if (PTR_ERR(exp) == -ENOENT)
1277 goto gss;
1278 if (IS_ERR(exp))
1279 return exp;
1280 /* If it has secinfo, assume there are no gss/... clients */
1281 if (exp->ex_nflavors > 0)
1282 return exp;
1283gss:
1284 /* Otherwise, try falling back on gss client */
1285 if (rqstp->rq_gssclient == NULL)
1286 return exp;
1287 gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry,
1288 &rqstp->rq_chandle);
1289 if (PTR_ERR(gssexp) == -ENOENT)
1290 return exp;
1291 if (exp && !IS_ERR(exp))
1292 exp_put(exp);
1293 return gssexp;
1294}
1295
1296struct svc_export *
1297rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
1298{
1299 struct svc_export *gssexp, *exp = NULL;
1300
1301 if (rqstp->rq_client == NULL)
1302 goto gss;
1303
1304 /* First try the auth_unix client: */
1305 exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
1306 if (PTR_ERR(exp) == -ENOENT)
1307 goto gss;
1308 if (IS_ERR(exp))
1309 return exp;
1310 /* If it has secinfo, assume there are no gss/... clients */
1311 if (exp->ex_nflavors > 0)
1312 return exp;
1313gss:
1314 /* Otherwise, try falling back on gss client */
1315 if (rqstp->rq_gssclient == NULL)
1316 return exp;
1317 gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
1318 &rqstp->rq_chandle);
1319 if (PTR_ERR(gssexp) == -ENOENT)
1320 return exp;
1321 if (exp && !IS_ERR(exp))
1322 exp_put(exp);
1323 return gssexp;
1324}
1325
1326struct svc_export *
1327rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
1328 struct dentry *dentry)
1329{
1330 struct svc_export *exp;
1331
1332 dget(dentry);
1333 exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
1334
1335 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
1336 struct dentry *parent;
1337
1338 parent = dget_parent(dentry);
1339 dput(dentry);
1340 dentry = parent;
1341 exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
1342 }
1343 dput(dentry);
1344 return exp;
1345}
1190 1346
1191/* 1347/*
1192 * Called when we need the filehandle for the root of the pseudofs, 1348 * Called when we need the filehandle for the root of the pseudofs,
@@ -1194,8 +1350,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
1194 * export point with fsid==0 1350 * export point with fsid==0
1195 */ 1351 */
1196__be32 1352__be32
1197exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, 1353exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1198 struct cache_req *creq)
1199{ 1354{
1200 struct svc_export *exp; 1355 struct svc_export *exp;
1201 __be32 rv; 1356 __be32 rv;
@@ -1203,12 +1358,16 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
1203 1358
1204 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); 1359 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1205 1360
1206 exp = exp_find(clp, FSID_NUM, fsidv, creq); 1361 exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
1362 if (PTR_ERR(exp) == -ENOENT)
1363 return nfserr_perm;
1207 if (IS_ERR(exp)) 1364 if (IS_ERR(exp))
1208 return nfserrno(PTR_ERR(exp)); 1365 return nfserrno(PTR_ERR(exp));
1209 if (exp == NULL)
1210 return nfserr_perm;
1211 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); 1366 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
1367 if (rv)
1368 goto out;
1369 rv = check_nfsd_access(exp, rqstp);
1370out:
1212 exp_put(exp); 1371 exp_put(exp);
1213 return rv; 1372 return rv;
1214} 1373}
@@ -1296,28 +1455,62 @@ static struct flags {
1296 { 0, {"", ""}} 1455 { 0, {"", ""}}
1297}; 1456};
1298 1457
1299static void exp_flags(struct seq_file *m, int flag, int fsid, 1458static void show_expflags(struct seq_file *m, int flags, int mask)
1300 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
1301{ 1459{
1302 int first = 0;
1303 struct flags *flg; 1460 struct flags *flg;
1461 int state, first = 0;
1304 1462
1305 for (flg = expflags; flg->flag; flg++) { 1463 for (flg = expflags; flg->flag; flg++) {
1306 int state = (flg->flag & flag)?0:1; 1464 if (flg->flag & ~mask)
1465 continue;
1466 state = (flg->flag & flags) ? 0 : 1;
1307 if (*flg->name[state]) 1467 if (*flg->name[state])
1308 seq_printf(m, "%s%s", first++?",":"", flg->name[state]); 1468 seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1309 } 1469 }
1470}
1471
1472static void show_secinfo_flags(struct seq_file *m, int flags)
1473{
1474 seq_printf(m, ",");
1475 show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
1476}
1477
1478static void show_secinfo(struct seq_file *m, struct svc_export *exp)
1479{
1480 struct exp_flavor_info *f;
1481 struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1482 int lastflags = 0, first = 0;
1483
1484 if (exp->ex_nflavors == 0)
1485 return;
1486 for (f = exp->ex_flavors; f < end; f++) {
1487 if (first || f->flags != lastflags) {
1488 if (!first)
1489 show_secinfo_flags(m, lastflags);
1490 seq_printf(m, ",sec=%d", f->pseudoflavor);
1491 lastflags = f->flags;
1492 } else {
1493 seq_printf(m, ":%d", f->pseudoflavor);
1494 }
1495 }
1496 show_secinfo_flags(m, lastflags);
1497}
1498
1499static void exp_flags(struct seq_file *m, int flag, int fsid,
1500 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
1501{
1502 show_expflags(m, flag, NFSEXP_ALLFLAGS);
1310 if (flag & NFSEXP_FSID) 1503 if (flag & NFSEXP_FSID)
1311 seq_printf(m, "%sfsid=%d", first++?",":"", fsid); 1504 seq_printf(m, ",fsid=%d", fsid);
1312 if (anonu != (uid_t)-2 && anonu != (0x10000-2)) 1505 if (anonu != (uid_t)-2 && anonu != (0x10000-2))
1313 seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); 1506 seq_printf(m, ",sanonuid=%d", anonu);
1314 if (anong != (gid_t)-2 && anong != (0x10000-2)) 1507 if (anong != (gid_t)-2 && anong != (0x10000-2))
1315 seq_printf(m, "%sanongid=%d", first++?",":"", anong); 1508 seq_printf(m, ",sanongid=%d", anong);
1316 if (fsloc && fsloc->locations_count > 0) { 1509 if (fsloc && fsloc->locations_count > 0) {
1317 char *loctype = (fsloc->migrated) ? "refer" : "replicas"; 1510 char *loctype = (fsloc->migrated) ? "refer" : "replicas";
1318 int i; 1511 int i;
1319 1512
1320 seq_printf(m, "%s%s=", first++?",":"", loctype); 1513 seq_printf(m, ",%s=", loctype);
1321 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\"); 1514 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
1322 seq_putc(m, '@'); 1515 seq_putc(m, '@');
1323 seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\"); 1516 seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 221acd1f11f6..9e4a568a5013 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -65,6 +65,7 @@ nlm_fclose(struct file *filp)
65static struct nlmsvc_binding nfsd_nlm_ops = { 65static struct nlmsvc_binding nfsd_nlm_ops = {
66 .fopen = nlm_fopen, /* open file for locking */ 66 .fopen = nlm_fopen, /* open file for locking */
67 .fclose = nlm_fclose, /* close file */ 67 .fclose = nlm_fclose, /* close file */
68 .get_grace_period = get_nfs4_grace_period,
68}; 69};
69 70
70void 71void
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index cc3b7badd486..b6ed38380ab8 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -183,8 +183,13 @@ static void
183summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) 183summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
184{ 184{
185 struct posix_acl_entry *pa, *pe; 185 struct posix_acl_entry *pa, *pe;
186 pas->users = 0; 186
187 pas->groups = 0; 187 /*
188 * Only pas.users and pas.groups need initialization; previous
189 * posix_acl_valid() calls ensure that the other fields will be
190 * initialized in the following loop. But, just to placate gcc:
191 */
192 memset(pas, 0, sizeof(*pas));
188 pas->mask = 07; 193 pas->mask = 07;
189 194
190 pe = acl->a_entries + acl->a_count; 195 pe = acl->a_entries + acl->a_count;
@@ -732,13 +737,16 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
732 *pacl = posix_state_to_acl(&effective_acl_state, flags); 737 *pacl = posix_state_to_acl(&effective_acl_state, flags);
733 if (IS_ERR(*pacl)) { 738 if (IS_ERR(*pacl)) {
734 ret = PTR_ERR(*pacl); 739 ret = PTR_ERR(*pacl);
740 *pacl = NULL;
735 goto out_dstate; 741 goto out_dstate;
736 } 742 }
737 *dpacl = posix_state_to_acl(&default_acl_state, 743 *dpacl = posix_state_to_acl(&default_acl_state,
738 flags | NFS4_ACL_TYPE_DEFAULT); 744 flags | NFS4_ACL_TYPE_DEFAULT);
739 if (IS_ERR(*dpacl)) { 745 if (IS_ERR(*dpacl)) {
740 ret = PTR_ERR(*dpacl); 746 ret = PTR_ERR(*dpacl);
747 *dpacl = NULL;
741 posix_acl_release(*pacl); 748 posix_acl_release(*pacl);
749 *pacl = NULL;
742 goto out_dstate; 750 goto out_dstate;
743 } 751 }
744 sort_pacl(*pacl); 752 sort_pacl(*pacl);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 864090edc28b..31d6633c7fe4 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -75,7 +75,7 @@ enum nfs_cb_opnum4 {
75#define op_enc_sz 1 75#define op_enc_sz 1
76#define op_dec_sz 2 76#define op_dec_sz 2
77#define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2)) 77#define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2))
78#define enc_stateid_sz 16 78#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2)
79#define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \ 79#define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \
80 1 + enc_stateid_sz + \ 80 1 + enc_stateid_sz + \
81 enc_nfs4_fh_sz) 81 enc_nfs4_fh_sz)
@@ -394,7 +394,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
394 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], 394 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
395 .rpc_argp = clp, 395 .rpc_argp = clp,
396 }; 396 };
397 char clientname[16];
398 int status; 397 int status;
399 398
400 if (atomic_read(&cb->cb_set)) 399 if (atomic_read(&cb->cb_set))
@@ -417,11 +416,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
417 memset(program->stats, 0, sizeof(cb->cb_stat)); 416 memset(program->stats, 0, sizeof(cb->cb_stat));
418 program->stats->program = program; 417 program->stats->program = program;
419 418
420 /* Just here to make some printk's more useful: */
421 snprintf(clientname, sizeof(clientname),
422 "%u.%u.%u.%u", NIPQUAD(addr.sin_addr));
423 args.servername = clientname;
424
425 /* Create RPC client */ 419 /* Create RPC client */
426 cb->cb_client = rpc_create(&args); 420 cb->cb_client = rpc_create(&args);
427 if (IS_ERR(cb->cb_client)) { 421 if (IS_ERR(cb->cb_client)) {
@@ -429,29 +423,23 @@ nfsd4_probe_callback(struct nfs4_client *clp)
429 goto out_err; 423 goto out_err;
430 } 424 }
431 425
432 /* Kick rpciod, put the call on the wire. */
433 if (rpciod_up() != 0)
434 goto out_clnt;
435
436 /* the task holds a reference to the nfs4_client struct */ 426 /* the task holds a reference to the nfs4_client struct */
437 atomic_inc(&clp->cl_count); 427 atomic_inc(&clp->cl_count);
438 428
439 msg.rpc_cred = nfsd4_lookupcred(clp,0); 429 msg.rpc_cred = nfsd4_lookupcred(clp,0);
440 if (IS_ERR(msg.rpc_cred)) 430 if (IS_ERR(msg.rpc_cred))
441 goto out_rpciod; 431 goto out_release_clp;
442 status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); 432 status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
443 put_rpccred(msg.rpc_cred); 433 put_rpccred(msg.rpc_cred);
444 434
445 if (status != 0) { 435 if (status != 0) {
446 dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n"); 436 dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
447 goto out_rpciod; 437 goto out_release_clp;
448 } 438 }
449 return; 439 return;
450 440
451out_rpciod: 441out_release_clp:
452 atomic_dec(&clp->cl_count); 442 atomic_dec(&clp->cl_count);
453 rpciod_down();
454out_clnt:
455 rpc_shutdown_client(cb->cb_client); 443 rpc_shutdown_client(cb->cb_client);
456out_err: 444out_err:
457 cb->cb_client = NULL; 445 cb->cb_client = NULL;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 45aa21ce6784..2cf9a9a2d89c 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -587,6 +587,15 @@ idmap_lookup(struct svc_rqst *rqstp,
587 return ret; 587 return ret;
588} 588}
589 589
590static char *
591rqst_authname(struct svc_rqst *rqstp)
592{
593 struct auth_domain *clp;
594
595 clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client;
596 return clp->name;
597}
598
590static int 599static int
591idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, 600idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
592 uid_t *id) 601 uid_t *id)
@@ -600,7 +609,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
600 return -EINVAL; 609 return -EINVAL;
601 memcpy(key.name, name, namelen); 610 memcpy(key.name, name, namelen);
602 key.name[namelen] = '\0'; 611 key.name[namelen] = '\0';
603 strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); 612 strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
604 ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); 613 ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
605 if (ret == -ENOENT) 614 if (ret == -ENOENT)
606 ret = -ESRCH; /* nfserr_badname */ 615 ret = -ESRCH; /* nfserr_badname */
@@ -620,7 +629,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
620 }; 629 };
621 int ret; 630 int ret;
622 631
623 strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); 632 strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
624 ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); 633 ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
625 if (ret == -ENOENT) 634 if (ret == -ENOENT)
626 return sprintf(name, "%u", id); 635 return sprintf(name, "%u", id);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8522729830db..3c627128e205 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -47,6 +47,7 @@
47#include <linux/nfsd/state.h> 47#include <linux/nfsd/state.h>
48#include <linux/nfsd/xdr4.h> 48#include <linux/nfsd/xdr4.h>
49#include <linux/nfs4_acl.h> 49#include <linux/nfs4_acl.h>
50#include <linux/sunrpc/gss_api.h>
50 51
51#define NFSDDBG_FACILITY NFSDDBG_PROC 52#define NFSDDBG_FACILITY NFSDDBG_PROC
52 53
@@ -286,8 +287,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
286 __be32 status; 287 __be32 status;
287 288
288 fh_put(&cstate->current_fh); 289 fh_put(&cstate->current_fh);
289 status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh, 290 status = exp_pseudoroot(rqstp, &cstate->current_fh);
290 &rqstp->rq_chandle);
291 return status; 291 return status;
292} 292}
293 293
@@ -474,8 +474,8 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
474 __be32 ret; 474 __be32 ret;
475 475
476 fh_init(&tmp_fh, NFS4_FHSIZE); 476 fh_init(&tmp_fh, NFS4_FHSIZE);
477 if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, 477 ret = exp_pseudoroot(rqstp, &tmp_fh);
478 &rqstp->rq_chandle)) != 0) 478 if (ret)
479 return ret; 479 return ret;
480 if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { 480 if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
481 fh_put(&tmp_fh); 481 fh_put(&tmp_fh);
@@ -611,6 +611,30 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
611} 611}
612 612
613static __be32 613static __be32
614nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
615 struct nfsd4_secinfo *secinfo)
616{
617 struct svc_fh resfh;
618 struct svc_export *exp;
619 struct dentry *dentry;
620 __be32 err;
621
622 fh_init(&resfh, NFS4_FHSIZE);
623 err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
624 secinfo->si_name, secinfo->si_namelen,
625 &exp, &dentry);
626 if (err)
627 return err;
628 if (dentry->d_inode == NULL) {
629 exp_put(exp);
630 err = nfserr_noent;
631 } else
632 secinfo->si_exp = exp;
633 dput(dentry);
634 return err;
635}
636
637static __be32
614nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 638nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
615 struct nfsd4_setattr *setattr) 639 struct nfsd4_setattr *setattr)
616{ 640{
@@ -1009,6 +1033,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
1009 [OP_SAVEFH] = { 1033 [OP_SAVEFH] = {
1010 .op_func = (nfsd4op_func)nfsd4_savefh, 1034 .op_func = (nfsd4op_func)nfsd4_savefh,
1011 }, 1035 },
1036 [OP_SECINFO] = {
1037 .op_func = (nfsd4op_func)nfsd4_secinfo,
1038 },
1012 [OP_SETATTR] = { 1039 [OP_SETATTR] = {
1013 .op_func = (nfsd4op_func)nfsd4_setattr, 1040 .op_func = (nfsd4op_func)nfsd4_setattr,
1014 }, 1041 },
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3cc8ce422ab1..e4a4c87ec8c6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -49,8 +49,10 @@
49#include <linux/nfsd/state.h> 49#include <linux/nfsd/state.h>
50#include <linux/nfsd/xdr4.h> 50#include <linux/nfsd/xdr4.h>
51#include <linux/namei.h> 51#include <linux/namei.h>
52#include <linux/swap.h>
52#include <linux/mutex.h> 53#include <linux/mutex.h>
53#include <linux/lockd/bind.h> 54#include <linux/lockd/bind.h>
55#include <linux/module.h>
54 56
55#define NFSDDBG_FACILITY NFSDDBG_PROC 57#define NFSDDBG_FACILITY NFSDDBG_PROC
56 58
@@ -149,6 +151,7 @@ get_nfs4_file(struct nfs4_file *fi)
149} 151}
150 152
151static int num_delegations; 153static int num_delegations;
154unsigned int max_delegations;
152 155
153/* 156/*
154 * Open owner state (share locks) 157 * Open owner state (share locks)
@@ -192,7 +195,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
192 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; 195 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
193 196
194 dprintk("NFSD alloc_init_deleg\n"); 197 dprintk("NFSD alloc_init_deleg\n");
195 if (num_delegations > STATEID_HASH_SIZE * 4) 198 if (fp->fi_had_conflict)
199 return NULL;
200 if (num_delegations > max_delegations)
196 return NULL; 201 return NULL;
197 dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); 202 dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
198 if (dp == NULL) 203 if (dp == NULL)
@@ -378,7 +383,6 @@ shutdown_callback_client(struct nfs4_client *clp)
378 if (clnt) { 383 if (clnt) {
379 clp->cl_callback.cb_client = NULL; 384 clp->cl_callback.cb_client = NULL;
380 rpc_shutdown_client(clnt); 385 rpc_shutdown_client(clnt);
381 rpciod_down();
382 } 386 }
383} 387}
384 388
@@ -1000,6 +1004,7 @@ alloc_init_file(struct inode *ino)
1000 list_add(&fp->fi_hash, &file_hashtbl[hashval]); 1004 list_add(&fp->fi_hash, &file_hashtbl[hashval]);
1001 fp->fi_inode = igrab(ino); 1005 fp->fi_inode = igrab(ino);
1002 fp->fi_id = current_fileid++; 1006 fp->fi_id = current_fileid++;
1007 fp->fi_had_conflict = false;
1003 return fp; 1008 return fp;
1004 } 1009 }
1005 return NULL; 1010 return NULL;
@@ -1326,6 +1331,7 @@ do_recall(void *__dp)
1326{ 1331{
1327 struct nfs4_delegation *dp = __dp; 1332 struct nfs4_delegation *dp = __dp;
1328 1333
1334 dp->dl_file->fi_had_conflict = true;
1329 nfsd4_cb_recall(dp); 1335 nfsd4_cb_recall(dp);
1330 return 0; 1336 return 0;
1331} 1337}
@@ -3191,20 +3197,49 @@ nfsd4_load_reboot_recovery_data(void)
3191 printk("NFSD: Failure reading reboot recovery data\n"); 3197 printk("NFSD: Failure reading reboot recovery data\n");
3192} 3198}
3193 3199
3200unsigned long
3201get_nfs4_grace_period(void)
3202{
3203 return max(user_lease_time, lease_time) * HZ;
3204}
3205
3206/*
3207 * Since the lifetime of a delegation isn't limited to that of an open, a
3208 * client may quite reasonably hang on to a delegation as long as it has
3209 * the inode cached. This becomes an obvious problem the first time a
3210 * client's inode cache approaches the size of the server's total memory.
3211 *
3212 * For now we avoid this problem by imposing a hard limit on the number
3213 * of delegations, which varies according to the server's memory size.
3214 */
3215static void
3216set_max_delegations(void)
3217{
3218 /*
3219 * Allow at most 4 delegations per megabyte of RAM. Quick
3220 * estimates suggest that in the worst case (where every delegation
3221 * is for a different inode), a delegation could take about 1.5K,
3222 * giving a worst case usage of about 6% of memory.
3223 */
3224 max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
3225}
3226
3194/* initialization to perform when the nfsd service is started: */ 3227/* initialization to perform when the nfsd service is started: */
3195 3228
3196static void 3229static void
3197__nfs4_state_start(void) 3230__nfs4_state_start(void)
3198{ 3231{
3199 time_t grace_time; 3232 unsigned long grace_time;
3200 3233
3201 boot_time = get_seconds(); 3234 boot_time = get_seconds();
3202 grace_time = max(user_lease_time, lease_time); 3235 grace_time = get_nfs_grace_period();
3203 lease_time = user_lease_time; 3236 lease_time = user_lease_time;
3204 in_grace = 1; 3237 in_grace = 1;
3205 printk("NFSD: starting %ld-second grace period\n", grace_time); 3238 printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
3239 grace_time/HZ);
3206 laundry_wq = create_singlethread_workqueue("nfsd4"); 3240 laundry_wq = create_singlethread_workqueue("nfsd4");
3207 queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ); 3241 queue_delayed_work(laundry_wq, &laundromat_work, grace_time);
3242 set_max_delegations();
3208} 3243}
3209 3244
3210int 3245int
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 15809dfd88a5..b3d55c6747fd 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -56,6 +56,8 @@
56#include <linux/nfsd_idmap.h> 56#include <linux/nfsd_idmap.h>
57#include <linux/nfs4.h> 57#include <linux/nfs4.h>
58#include <linux/nfs4_acl.h> 58#include <linux/nfs4_acl.h>
59#include <linux/sunrpc/gss_api.h>
60#include <linux/sunrpc/svcauth_gss.h>
59 61
60#define NFSDDBG_FACILITY NFSDDBG_XDR 62#define NFSDDBG_FACILITY NFSDDBG_XDR
61 63
@@ -819,6 +821,23 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
819} 821}
820 822
821static __be32 823static __be32
824nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
825 struct nfsd4_secinfo *secinfo)
826{
827 DECODE_HEAD;
828
829 READ_BUF(4);
830 READ32(secinfo->si_namelen);
831 READ_BUF(secinfo->si_namelen);
832 SAVEMEM(secinfo->si_name, secinfo->si_namelen);
833 status = check_filename(secinfo->si_name, secinfo->si_namelen,
834 nfserr_noent);
835 if (status)
836 return status;
837 DECODE_TAIL;
838}
839
840static __be32
822nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) 841nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
823{ 842{
824 DECODE_HEAD; 843 DECODE_HEAD;
@@ -1131,6 +1150,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1131 case OP_SAVEFH: 1150 case OP_SAVEFH:
1132 op->status = nfs_ok; 1151 op->status = nfs_ok;
1133 break; 1152 break;
1153 case OP_SECINFO:
1154 op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);
1155 break;
1134 case OP_SETATTR: 1156 case OP_SETATTR:
1135 op->status = nfsd4_decode_setattr(argp, &op->u.setattr); 1157 op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
1136 break; 1158 break;
@@ -1296,7 +1318,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
1296 char *path, *rootpath; 1318 char *path, *rootpath;
1297 1319
1298 fh_init(&tmp_fh, NFS4_FHSIZE); 1320 fh_init(&tmp_fh, NFS4_FHSIZE);
1299 *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle); 1321 *stat = exp_pseudoroot(rqstp, &tmp_fh);
1300 if (*stat) 1322 if (*stat)
1301 return NULL; 1323 return NULL;
1302 rootpath = tmp_fh.fh_export->ex_path; 1324 rootpath = tmp_fh.fh_export->ex_path;
@@ -1847,11 +1869,19 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1847 if (d_mountpoint(dentry)) { 1869 if (d_mountpoint(dentry)) {
1848 int err; 1870 int err;
1849 1871
1872 /*
1873 * Why the heck aren't we just using nfsd_lookup??
1874 * Different "."/".." handling? Something else?
1875 * At least, add a comment here to explain....
1876 */
1850 err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); 1877 err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
1851 if (err) { 1878 if (err) {
1852 nfserr = nfserrno(err); 1879 nfserr = nfserrno(err);
1853 goto out_put; 1880 goto out_put;
1854 } 1881 }
1882 nfserr = check_nfsd_access(exp, cd->rd_rqstp);
1883 if (nfserr)
1884 goto out_put;
1855 1885
1856 } 1886 }
1857 nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, 1887 nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
@@ -2419,6 +2449,72 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
2419 } 2449 }
2420} 2450}
2421 2451
2452static void
2453nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr,
2454 struct nfsd4_secinfo *secinfo)
2455{
2456 int i = 0;
2457 struct svc_export *exp = secinfo->si_exp;
2458 u32 nflavs;
2459 struct exp_flavor_info *flavs;
2460 struct exp_flavor_info def_flavs[2];
2461 ENCODE_HEAD;
2462
2463 if (nfserr)
2464 goto out;
2465 if (exp->ex_nflavors) {
2466 flavs = exp->ex_flavors;
2467 nflavs = exp->ex_nflavors;
2468 } else { /* Handling of some defaults in absence of real secinfo: */
2469 flavs = def_flavs;
2470 if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
2471 nflavs = 2;
2472 flavs[0].pseudoflavor = RPC_AUTH_UNIX;
2473 flavs[1].pseudoflavor = RPC_AUTH_NULL;
2474 } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
2475 nflavs = 1;
2476 flavs[0].pseudoflavor
2477 = svcauth_gss_flavor(exp->ex_client);
2478 } else {
2479 nflavs = 1;
2480 flavs[0].pseudoflavor
2481 = exp->ex_client->flavour->flavour;
2482 }
2483 }
2484
2485 RESERVE_SPACE(4);
2486 WRITE32(nflavs);
2487 ADJUST_ARGS();
2488 for (i = 0; i < nflavs; i++) {
2489 u32 flav = flavs[i].pseudoflavor;
2490 struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
2491
2492 if (gm) {
2493 RESERVE_SPACE(4);
2494 WRITE32(RPC_AUTH_GSS);
2495 ADJUST_ARGS();
2496 RESERVE_SPACE(4 + gm->gm_oid.len);
2497 WRITE32(gm->gm_oid.len);
2498 WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
2499 ADJUST_ARGS();
2500 RESERVE_SPACE(4);
2501 WRITE32(0); /* qop */
2502 ADJUST_ARGS();
2503 RESERVE_SPACE(4);
2504 WRITE32(gss_pseudoflavor_to_service(gm, flav));
2505 ADJUST_ARGS();
2506 gss_mech_put(gm);
2507 } else {
2508 RESERVE_SPACE(4);
2509 WRITE32(flav);
2510 ADJUST_ARGS();
2511 }
2512 }
2513out:
2514 if (exp)
2515 exp_put(exp);
2516}
2517
2422/* 2518/*
2423 * The SETATTR encode routine is special -- it always encodes a bitmap, 2519 * The SETATTR encode routine is special -- it always encodes a bitmap,
2424 * regardless of the error status. 2520 * regardless of the error status.
@@ -2559,6 +2655,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
2559 break; 2655 break;
2560 case OP_SAVEFH: 2656 case OP_SAVEFH:
2561 break; 2657 break;
2658 case OP_SECINFO:
2659 nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo);
2660 break;
2562 case OP_SETATTR: 2661 case OP_SETATTR:
2563 nfsd4_encode_setattr(resp, op->status, &op->u.setattr); 2662 nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
2564 break; 2663 break;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 71c686dc7257..baac89d917ca 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -35,7 +35,6 @@
35#include <linux/nfsd/cache.h> 35#include <linux/nfsd/cache.h>
36#include <linux/nfsd/xdr.h> 36#include <linux/nfsd/xdr.h>
37#include <linux/nfsd/syscall.h> 37#include <linux/nfsd/syscall.h>
38#include <linux/nfsd/interface.h>
39 38
40#include <asm/uaccess.h> 39#include <asm/uaccess.h>
41 40
@@ -245,7 +244,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
245 } 244 }
246 exp_readunlock(); 245 exp_readunlock();
247 if (err == 0) 246 if (err == 0)
248 err = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base; 247 err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
249 out: 248 out:
250 return err; 249 return err;
251} 250}
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 6ca2d24fc216..0eb464a39aae 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -15,10 +15,12 @@
15#include <linux/string.h> 15#include <linux/string.h>
16#include <linux/stat.h> 16#include <linux/stat.h>
17#include <linux/dcache.h> 17#include <linux/dcache.h>
18#include <linux/exportfs.h>
18#include <linux/mount.h> 19#include <linux/mount.h>
19 20
20#include <linux/sunrpc/clnt.h> 21#include <linux/sunrpc/clnt.h>
21#include <linux/sunrpc/svc.h> 22#include <linux/sunrpc/svc.h>
23#include <linux/sunrpc/svcauth_gss.h>
22#include <linux/nfsd/nfsd.h> 24#include <linux/nfsd/nfsd.h>
23 25
24#define NFSDDBG_FACILITY NFSDDBG_FH 26#define NFSDDBG_FACILITY NFSDDBG_FH
@@ -27,10 +29,6 @@
27static int nfsd_nr_verified; 29static int nfsd_nr_verified;
28static int nfsd_nr_put; 30static int nfsd_nr_put;
29 31
30extern struct export_operations export_op_default;
31
32#define CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun)
33
34/* 32/*
35 * our acceptability function. 33 * our acceptability function.
36 * if NOSUBTREECHECK, accept anything 34 * if NOSUBTREECHECK, accept anything
@@ -123,8 +121,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
123 int data_left = fh->fh_size/4; 121 int data_left = fh->fh_size/4;
124 122
125 error = nfserr_stale; 123 error = nfserr_stale;
126 if (rqstp->rq_client == NULL)
127 goto out;
128 if (rqstp->rq_vers > 2) 124 if (rqstp->rq_vers > 2)
129 error = nfserr_badhandle; 125 error = nfserr_badhandle;
130 if (rqstp->rq_vers == 4 && fh->fh_size == 0) 126 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
@@ -148,7 +144,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
148 fh->fh_fsid[1] = fh->fh_fsid[2]; 144 fh->fh_fsid[1] = fh->fh_fsid[2];
149 } 145 }
150 if ((data_left -= len)<0) goto out; 146 if ((data_left -= len)<0) goto out;
151 exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle); 147 exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap);
152 datap += len; 148 datap += len;
153 } else { 149 } else {
154 dev_t xdev; 150 dev_t xdev;
@@ -159,19 +155,17 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
159 xdev = old_decode_dev(fh->ofh_xdev); 155 xdev = old_decode_dev(fh->ofh_xdev);
160 xino = u32_to_ino_t(fh->ofh_xino); 156 xino = u32_to_ino_t(fh->ofh_xino);
161 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); 157 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
162 exp = exp_find(rqstp->rq_client, FSID_DEV, tfh, 158 exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
163 &rqstp->rq_chandle);
164 } 159 }
165 160
166 if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN 161 error = nfserr_stale;
167 || PTR_ERR(exp) == -ETIMEDOUT)) { 162 if (PTR_ERR(exp) == -ENOENT)
168 error = nfserrno(PTR_ERR(exp));
169 goto out; 163 goto out;
170 }
171 164
172 error = nfserr_stale; 165 if (IS_ERR(exp)) {
173 if (!exp || IS_ERR(exp)) 166 error = nfserrno(PTR_ERR(exp));
174 goto out; 167 goto out;
168 }
175 169
176 /* Check if the request originated from a secure port. */ 170 /* Check if the request originated from a secure port. */
177 error = nfserr_perm; 171 error = nfserr_perm;
@@ -211,11 +205,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
211 if (fileid_type == 0) 205 if (fileid_type == 0)
212 dentry = dget(exp->ex_dentry); 206 dentry = dget(exp->ex_dentry);
213 else { 207 else {
214 struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op; 208 dentry = exportfs_decode_fh(exp->ex_mnt, datap,
215 dentry = CALL(nop,decode_fh)(exp->ex_mnt->mnt_sb, 209 data_left, fileid_type,
216 datap, data_left, 210 nfsd_acceptable, exp);
217 fileid_type,
218 nfsd_acceptable, exp);
219 } 211 }
220 if (dentry == NULL) 212 if (dentry == NULL)
221 goto out; 213 goto out;
@@ -257,8 +249,19 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
257 if (error) 249 if (error)
258 goto out; 250 goto out;
259 251
252 if (!(access & MAY_LOCK)) {
253 /*
254 * pseudoflavor restrictions are not enforced on NLM,
255 * which clients virtually always use auth_sys for,
256 * even while using RPCSEC_GSS for NFS.
257 */
258 error = check_nfsd_access(exp, rqstp);
259 if (error)
260 goto out;
261 }
262
260 /* Finally, check access permissions. */ 263 /* Finally, check access permissions. */
261 error = nfsd_permission(exp, dentry, access); 264 error = nfsd_permission(rqstp, exp, dentry, access);
262 265
263 if (error) { 266 if (error) {
264 dprintk("fh_verify: %s/%s permission failure, " 267 dprintk("fh_verify: %s/%s permission failure, "
@@ -286,15 +289,13 @@ out:
286static inline int _fh_update(struct dentry *dentry, struct svc_export *exp, 289static inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
287 __u32 *datap, int *maxsize) 290 __u32 *datap, int *maxsize)
288{ 291{
289 struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op;
290
291 if (dentry == exp->ex_dentry) { 292 if (dentry == exp->ex_dentry) {
292 *maxsize = 0; 293 *maxsize = 0;
293 return 0; 294 return 0;
294 } 295 }
295 296
296 return CALL(nop,encode_fh)(dentry, datap, maxsize, 297 return exportfs_encode_fh(dentry, datap, maxsize,
297 !(exp->ex_flags&NFSEXP_NOSUBTREECHECK)); 298 !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
298} 299}
299 300
300/* 301/*
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index b2c7147aa921..977a71f64e19 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -278,7 +278,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
278 * echo thing > device-special-file-or-pipe 278 * echo thing > device-special-file-or-pipe
279 * by doing a CREATE with type==0 279 * by doing a CREATE with type==0
280 */ 280 */
281 nfserr = nfsd_permission(newfhp->fh_export, 281 nfserr = nfsd_permission(rqstp,
282 newfhp->fh_export,
282 newfhp->fh_dentry, 283 newfhp->fh_dentry,
283 MAY_WRITE|MAY_LOCAL_ACCESS); 284 MAY_WRITE|MAY_LOCAL_ACCESS);
284 if (nfserr && nfserr != nfserr_rofs) 285 if (nfserr && nfserr != nfserr_rofs)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index ff55950efb43..a8c89ae4c743 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -19,6 +19,7 @@
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/smp.h> 20#include <linux/smp.h>
21#include <linux/smp_lock.h> 21#include <linux/smp_lock.h>
22#include <linux/freezer.h>
22#include <linux/fs_struct.h> 23#include <linux/fs_struct.h>
23 24
24#include <linux/sunrpc/types.h> 25#include <linux/sunrpc/types.h>
@@ -432,6 +433,7 @@ nfsd(struct svc_rqst *rqstp)
432 * dirty pages. 433 * dirty pages.
433 */ 434 */
434 current->flags |= PF_LESS_THROTTLE; 435 current->flags |= PF_LESS_THROTTLE;
436 set_freezable();
435 437
436 /* 438 /*
437 * The main request loop 439 * The main request loop
@@ -492,6 +494,15 @@ out:
492 module_put_and_exit(0); 494 module_put_and_exit(0);
493} 495}
494 496
497static __be32 map_new_errors(u32 vers, __be32 nfserr)
498{
499 if (nfserr == nfserr_jukebox && vers == 2)
500 return nfserr_dropit;
501 if (nfserr == nfserr_wrongsec && vers < 4)
502 return nfserr_acces;
503 return nfserr;
504}
505
495int 506int
496nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) 507nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
497{ 508{
@@ -534,6 +545,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
534 545
535 /* Now call the procedure handler, and encode NFS status. */ 546 /* Now call the procedure handler, and encode NFS status. */
536 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); 547 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
548 nfserr = map_new_errors(rqstp->rq_vers, nfserr);
537 if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2) 549 if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2)
538 nfserr = nfserr_dropit; 550 nfserr = nfserr_dropit;
539 if (nfserr == nfserr_dropit) { 551 if (nfserr == nfserr_dropit) {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 7e6aa245b5d5..e90f4a8a1d01 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -23,7 +23,7 @@
23#include <linux/file.h> 23#include <linux/file.h>
24#include <linux/mount.h> 24#include <linux/mount.h>
25#include <linux/major.h> 25#include <linux/major.h>
26#include <linux/ext2_fs.h> 26#include <linux/splice.h>
27#include <linux/proc_fs.h> 27#include <linux/proc_fs.h>
28#include <linux/stat.h> 28#include <linux/stat.h>
29#include <linux/fcntl.h> 29#include <linux/fcntl.h>
@@ -113,7 +113,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
113 113
114 while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); 114 while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
115 115
116 exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle); 116 exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts);
117 if (IS_ERR(exp2)) { 117 if (IS_ERR(exp2)) {
118 err = PTR_ERR(exp2); 118 err = PTR_ERR(exp2);
119 dput(mounts); 119 dput(mounts);
@@ -135,21 +135,10 @@ out:
135 return err; 135 return err;
136} 136}
137 137
138/*
139 * Look up one component of a pathname.
140 * N.B. After this call _both_ fhp and resfh need an fh_put
141 *
142 * If the lookup would cross a mountpoint, and the mounted filesystem
143 * is exported to the client with NFSEXP_NOHIDE, then the lookup is
144 * accepted as it stands and the mounted directory is
145 * returned. Otherwise the covered directory is returned.
146 * NOTE: this mountpoint crossing is not supported properly by all
147 * clients and is explicitly disallowed for NFSv3
148 * NeilBrown <neilb@cse.unsw.edu.au>
149 */
150__be32 138__be32
151nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, 139nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
152 int len, struct svc_fh *resfh) 140 const char *name, int len,
141 struct svc_export **exp_ret, struct dentry **dentry_ret)
153{ 142{
154 struct svc_export *exp; 143 struct svc_export *exp;
155 struct dentry *dparent; 144 struct dentry *dparent;
@@ -168,8 +157,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
168 exp = fhp->fh_export; 157 exp = fhp->fh_export;
169 exp_get(exp); 158 exp_get(exp);
170 159
171 err = nfserr_acces;
172
173 /* Lookup the name, but don't follow links */ 160 /* Lookup the name, but don't follow links */
174 if (isdotent(name, len)) { 161 if (isdotent(name, len)) {
175 if (len==1) 162 if (len==1)
@@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
190 dput(dentry); 177 dput(dentry);
191 dentry = dp; 178 dentry = dp;
192 179
193 exp2 = exp_parent(exp->ex_client, mnt, dentry, 180 exp2 = rqst_exp_parent(rqstp, mnt, dentry);
194 &rqstp->rq_chandle); 181 if (PTR_ERR(exp2) == -ENOENT) {
195 if (IS_ERR(exp2)) { 182 dput(dentry);
183 dentry = dget(dparent);
184 } else if (IS_ERR(exp2)) {
196 host_err = PTR_ERR(exp2); 185 host_err = PTR_ERR(exp2);
197 dput(dentry); 186 dput(dentry);
198 mntput(mnt); 187 mntput(mnt);
199 goto out_nfserr; 188 goto out_nfserr;
200 }
201 if (!exp2) {
202 dput(dentry);
203 dentry = dget(dparent);
204 } else { 189 } else {
205 exp_put(exp); 190 exp_put(exp);
206 exp = exp2; 191 exp = exp2;
@@ -223,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
223 } 208 }
224 } 209 }
225 } 210 }
211 *dentry_ret = dentry;
212 *exp_ret = exp;
213 return 0;
214
215out_nfserr:
216 exp_put(exp);
217 return nfserrno(host_err);
218}
219
220/*
221 * Look up one component of a pathname.
222 * N.B. After this call _both_ fhp and resfh need an fh_put
223 *
224 * If the lookup would cross a mountpoint, and the mounted filesystem
225 * is exported to the client with NFSEXP_NOHIDE, then the lookup is
226 * accepted as it stands and the mounted directory is
227 * returned. Otherwise the covered directory is returned.
228 * NOTE: this mountpoint crossing is not supported properly by all
229 * clients and is explicitly disallowed for NFSv3
230 * NeilBrown <neilb@cse.unsw.edu.au>
231 */
232__be32
233nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
234 int len, struct svc_fh *resfh)
235{
236 struct svc_export *exp;
237 struct dentry *dentry;
238 __be32 err;
239
240 err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
241 if (err)
242 return err;
243 err = check_nfsd_access(exp, rqstp);
244 if (err)
245 goto out;
226 /* 246 /*
227 * Note: we compose the file handle now, but as the 247 * Note: we compose the file handle now, but as the
228 * dentry may be negative, it may need to be updated. 248 * dentry may be negative, it may need to be updated.
@@ -230,16 +250,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
230 err = fh_compose(resfh, exp, dentry, fhp); 250 err = fh_compose(resfh, exp, dentry, fhp);
231 if (!err && !dentry->d_inode) 251 if (!err && !dentry->d_inode)
232 err = nfserr_noent; 252 err = nfserr_noent;
233 dput(dentry);
234out: 253out:
254 dput(dentry);
235 exp_put(exp); 255 exp_put(exp);
236 return err; 256 return err;
237
238out_nfserr:
239 err = nfserrno(host_err);
240 goto out;
241} 257}
242 258
259
243/* 260/*
244 * Set various file attributes. 261 * Set various file attributes.
245 * N.B. After this call fhp needs an fh_put 262 * N.B. After this call fhp needs an fh_put
@@ -311,7 +328,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
311 /* The size case is special. It changes the file as well as the attributes. */ 328 /* The size case is special. It changes the file as well as the attributes. */
312 if (iap->ia_valid & ATTR_SIZE) { 329 if (iap->ia_valid & ATTR_SIZE) {
313 if (iap->ia_size < inode->i_size) { 330 if (iap->ia_size < inode->i_size) {
314 err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); 331 err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
315 if (err) 332 if (err)
316 goto out; 333 goto out;
317 } 334 }
@@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
435 /* Get inode */ 452 /* Get inode */
436 error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); 453 error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
437 if (error) 454 if (error)
438 goto out; 455 return error;
439 456
440 dentry = fhp->fh_dentry; 457 dentry = fhp->fh_dentry;
441 inode = dentry->d_inode; 458 inode = dentry->d_inode;
@@ -444,33 +461,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
444 461
445 host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); 462 host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
446 if (host_error == -EINVAL) { 463 if (host_error == -EINVAL) {
447 error = nfserr_attrnotsupp; 464 return nfserr_attrnotsupp;
448 goto out;
449 } else if (host_error < 0) 465 } else if (host_error < 0)
450 goto out_nfserr; 466 goto out_nfserr;
451 467
452 host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); 468 host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
453 if (host_error < 0) 469 if (host_error < 0)
454 goto out_nfserr; 470 goto out_release;
455 471
456 if (S_ISDIR(inode->i_mode)) { 472 if (S_ISDIR(inode->i_mode))
457 host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); 473 host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
458 if (host_error < 0)
459 goto out_nfserr;
460 }
461 474
462 error = nfs_ok; 475out_release:
463
464out:
465 posix_acl_release(pacl); 476 posix_acl_release(pacl);
466 posix_acl_release(dpacl); 477 posix_acl_release(dpacl);
467 return (error);
468out_nfserr: 478out_nfserr:
469 if (host_error == -EOPNOTSUPP) 479 if (host_error == -EOPNOTSUPP)
470 error = nfserr_attrnotsupp; 480 return nfserr_attrnotsupp;
471 else 481 else
472 error = nfserrno(host_error); 482 return nfserrno(host_error);
473 goto out;
474} 483}
475 484
476static struct posix_acl * 485static struct posix_acl *
@@ -607,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
607 616
608 sresult |= map->access; 617 sresult |= map->access;
609 618
610 err2 = nfsd_permission(export, dentry, map->how); 619 err2 = nfsd_permission(rqstp, export, dentry, map->how);
611 switch (err2) { 620 switch (err2) {
612 case nfs_ok: 621 case nfs_ok:
613 result |= map->access; 622 result |= map->access;
@@ -801,26 +810,32 @@ found:
801} 810}
802 811
803/* 812/*
804 * Grab and keep cached pages assosiated with a file in the svc_rqst 813 * Grab and keep cached pages associated with a file in the svc_rqst
805 * so that they can be passed to the netowork sendmsg/sendpage routines 814 * so that they can be passed to the network sendmsg/sendpage routines
806 * directrly. They will be released after the sending has completed. 815 * directly. They will be released after the sending has completed.
807 */ 816 */
808static int 817static int
809nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset , unsigned long size) 818nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
819 struct splice_desc *sd)
810{ 820{
811 unsigned long count = desc->count; 821 struct svc_rqst *rqstp = sd->u.data;
812 struct svc_rqst *rqstp = desc->arg.data;
813 struct page **pp = rqstp->rq_respages + rqstp->rq_resused; 822 struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
823 struct page *page = buf->page;
824 size_t size;
825 int ret;
826
827 ret = buf->ops->confirm(pipe, buf);
828 if (unlikely(ret))
829 return ret;
814 830
815 if (size > count) 831 size = sd->len;
816 size = count;
817 832
818 if (rqstp->rq_res.page_len == 0) { 833 if (rqstp->rq_res.page_len == 0) {
819 get_page(page); 834 get_page(page);
820 put_page(*pp); 835 put_page(*pp);
821 *pp = page; 836 *pp = page;
822 rqstp->rq_resused++; 837 rqstp->rq_resused++;
823 rqstp->rq_res.page_base = offset; 838 rqstp->rq_res.page_base = buf->offset;
824 rqstp->rq_res.page_len = size; 839 rqstp->rq_res.page_len = size;
825 } else if (page != pp[-1]) { 840 } else if (page != pp[-1]) {
826 get_page(page); 841 get_page(page);
@@ -832,11 +847,15 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
832 } else 847 } else
833 rqstp->rq_res.page_len += size; 848 rqstp->rq_res.page_len += size;
834 849
835 desc->count = count - size;
836 desc->written += size;
837 return size; 850 return size;
838} 851}
839 852
853static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
854 struct splice_desc *sd)
855{
856 return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
857}
858
840static __be32 859static __be32
841nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, 860nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
842 loff_t offset, struct kvec *vec, int vlen, unsigned long *count) 861 loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
@@ -861,10 +880,16 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
861 if (ra && ra->p_set) 880 if (ra && ra->p_set)
862 file->f_ra = ra->p_ra; 881 file->f_ra = ra->p_ra;
863 882
864 if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { 883 if (file->f_op->splice_read && rqstp->rq_splice_ok) {
884 struct splice_desc sd = {
885 .len = 0,
886 .total_len = *count,
887 .pos = offset,
888 .u.data = rqstp,
889 };
890
865 rqstp->rq_resused = 1; 891 rqstp->rq_resused = 1;
866 host_err = file->f_op->sendfile(file, &offset, *count, 892 host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
867 nfsd_read_actor, rqstp);
868 } else { 893 } else {
869 oldfs = get_fs(); 894 oldfs = get_fs();
870 set_fs(KERNEL_DS); 895 set_fs(KERNEL_DS);
@@ -1018,7 +1043,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1018 __be32 err; 1043 __be32 err;
1019 1044
1020 if (file) { 1045 if (file) {
1021 err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, 1046 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1022 MAY_READ|MAY_OWNER_OVERRIDE); 1047 MAY_READ|MAY_OWNER_OVERRIDE);
1023 if (err) 1048 if (err)
1024 goto out; 1049 goto out;
@@ -1047,7 +1072,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1047 __be32 err = 0; 1072 __be32 err = 0;
1048 1073
1049 if (file) { 1074 if (file) {
1050 err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, 1075 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1051 MAY_WRITE|MAY_OWNER_OVERRIDE); 1076 MAY_WRITE|MAY_OWNER_OVERRIDE);
1052 if (err) 1077 if (err)
1053 goto out; 1078 goto out;
@@ -1776,7 +1801,8 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
1776 * Check for a user's access permissions to this inode. 1801 * Check for a user's access permissions to this inode.
1777 */ 1802 */
1778__be32 1803__be32
1779nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) 1804nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
1805 struct dentry *dentry, int acc)
1780{ 1806{
1781 struct inode *inode = dentry->d_inode; 1807 struct inode *inode = dentry->d_inode;
1782 int err; 1808 int err;
@@ -1807,7 +1833,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
1807 */ 1833 */
1808 if (!(acc & MAY_LOCAL_ACCESS)) 1834 if (!(acc & MAY_LOCAL_ACCESS))
1809 if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { 1835 if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
1810 if (EX_RDONLY(exp) || IS_RDONLY(inode)) 1836 if (EX_RDONLY(exp, rqstp) || IS_RDONLY(inode))
1811 return nfserr_rofs; 1837 return nfserr_rofs;
1812 if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) 1838 if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
1813 return nfserr_perm; 1839 return nfserr_perm;