diff options
author | Steve French <sfrench@us.ibm.com> | 2007-07-18 20:38:57 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-07-18 20:38:57 -0400 |
commit | 1ff8392c32a2645d2665ca779ecb91bb29361c13 (patch) | |
tree | 860b95e9a499ade4060848740fc6ce1fbb4e4e8d /fs/nfsd | |
parent | 70b315b0dd3879cb3ab8aadffb14f10b2d19b9c3 (diff) | |
parent | 5bae7ac9feba925fd0099057f6b23d7be80b7b41 (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.c | 18 | ||||
-rw-r--r-- | fs/nfsd/export.c | 289 | ||||
-rw-r--r-- | fs/nfsd/lockd.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfs4acl.c | 12 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 20 | ||||
-rw-r--r-- | fs/nfsd/nfs4idmap.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 35 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 47 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 101 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 51 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 12 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 156 |
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 | ||
15 | static 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 | |||
15 | int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | 28 | int 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 | ||
457 | static 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 */ |
455 | static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; } | 495 | static inline int |
496 | fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;} | ||
497 | static inline int | ||
498 | secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; } | ||
456 | #endif | 499 | #endif |
457 | 500 | ||
458 | static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | 501 | static 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 | ||
594 | static void exp_flags(struct seq_file *m, int flag, int fsid, | 642 | static 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); |
644 | static void show_secinfo(struct seq_file *m, struct svc_export *exp); | ||
596 | 645 | ||
597 | static int svc_export_show(struct seq_file *m, | 646 | static 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 | ||
674 | static struct cache_head *svc_export_alloc(void) | 729 | static 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 | */ | ||
1264 | struct svc_export * | ||
1265 | rqst_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; | ||
1283 | gss: | ||
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 | |||
1296 | struct svc_export * | ||
1297 | rqst_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; | ||
1313 | gss: | ||
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 | |||
1326 | struct svc_export * | ||
1327 | rqst_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 |
1197 | exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | 1353 | exp_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); | ||
1370 | out: | ||
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 | ||
1299 | static void exp_flags(struct seq_file *m, int flag, int fsid, | 1458 | static 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 | |||
1472 | static 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 | |||
1478 | static 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 | |||
1499 | static 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) | |||
65 | static struct nlmsvc_binding nfsd_nlm_ops = { | 65 | static 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 | ||
70 | void | 71 | void |
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 | |||
183 | summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) | 183 | summarize_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 | ||
451 | out_rpciod: | 441 | out_release_clp: |
452 | atomic_dec(&clp->cl_count); | 442 | atomic_dec(&clp->cl_count); |
453 | rpciod_down(); | ||
454 | out_clnt: | ||
455 | rpc_shutdown_client(cb->cb_client); | 443 | rpc_shutdown_client(cb->cb_client); |
456 | out_err: | 444 | out_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 | ||
590 | static char * | ||
591 | rqst_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 | |||
590 | static int | 599 | static int |
591 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, | 600 | idmap_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 | ||
613 | static __be32 | 613 | static __be32 |
614 | nfsd4_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 | |||
637 | static __be32 | ||
614 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 638 | nfsd4_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 | ||
151 | static int num_delegations; | 153 | static int num_delegations; |
154 | unsigned 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 | ||
3200 | unsigned long | ||
3201 | get_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 | */ | ||
3215 | static void | ||
3216 | set_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 | ||
3196 | static void | 3229 | static 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 | ||
3210 | int | 3245 | int |
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 | ||
821 | static __be32 | 823 | static __be32 |
824 | nfsd4_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 | |||
840 | static __be32 | ||
822 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) | 841 | nfsd4_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 | ||
2452 | static void | ||
2453 | nfsd4_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 | } | ||
2513 | out: | ||
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 @@ | |||
27 | static int nfsd_nr_verified; | 29 | static int nfsd_nr_verified; |
28 | static int nfsd_nr_put; | 30 | static int nfsd_nr_put; |
29 | 31 | ||
30 | extern 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: | |||
286 | static inline int _fh_update(struct dentry *dentry, struct svc_export *exp, | 289 | static 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 | ||
497 | static __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 | |||
495 | int | 506 | int |
496 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | 507 | nfsd_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 |
151 | nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | 139 | nfsd_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 | |||
215 | out_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 | ||
233 | nfsd_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); | ||
234 | out: | 253 | out: |
254 | dput(dentry); | ||
235 | exp_put(exp); | 255 | exp_put(exp); |
236 | return err; | 256 | return err; |
237 | |||
238 | out_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; | 475 | out_release: |
463 | |||
464 | out: | ||
465 | posix_acl_release(pacl); | 476 | posix_acl_release(pacl); |
466 | posix_acl_release(dpacl); | 477 | posix_acl_release(dpacl); |
467 | return (error); | ||
468 | out_nfserr: | 478 | out_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 | ||
476 | static struct posix_acl * | 485 | static 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 | */ |
808 | static int | 817 | static int |
809 | nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset , unsigned long size) | 818 | nfsd_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 | ||
853 | static 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 | |||
840 | static __be32 | 859 | static __be32 |
841 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 860 | nfsd_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 |
1779 | nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | 1804 | nfsd_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; |