diff options
Diffstat (limited to 'fs/nfsd/export.c')
-rw-r--r-- | fs/nfsd/export.c | 289 |
1 files changed, 241 insertions, 48 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 79bd03b8bbf8..2d295dda4c1d 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 = ERR_PTR(-ENOENT); | ||
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 (!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 = ERR_PTR(-ENOENT); | ||
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 (!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, ",anonuid=%u", 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, ",anongid=%u", 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\\"); |