diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/export.c | 125 | ||||
-rw-r--r-- | fs/nfsd/nfs4recover.c | 50 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 8 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 126 |
5 files changed, 201 insertions, 116 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 5cd882b8871a..5839b229cd0e 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -163,18 +163,16 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
163 | if (!ek) | 163 | if (!ek) |
164 | err = -ENOMEM; | 164 | err = -ENOMEM; |
165 | } else { | 165 | } else { |
166 | struct nameidata nd; | 166 | err = kern_path(buf, 0, &key.ek_path); |
167 | err = path_lookup(buf, 0, &nd); | ||
168 | if (err) | 167 | if (err) |
169 | goto out; | 168 | goto out; |
170 | 169 | ||
171 | dprintk("Found the path %s\n", buf); | 170 | dprintk("Found the path %s\n", buf); |
172 | key.ek_path = nd.path; | ||
173 | 171 | ||
174 | ek = svc_expkey_update(&key, ek); | 172 | ek = svc_expkey_update(&key, ek); |
175 | if (!ek) | 173 | if (!ek) |
176 | err = -ENOMEM; | 174 | err = -ENOMEM; |
177 | path_put(&nd.path); | 175 | path_put(&key.ek_path); |
178 | } | 176 | } |
179 | cache_flush(); | 177 | cache_flush(); |
180 | out: | 178 | out: |
@@ -501,35 +499,22 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
501 | int len; | 499 | int len; |
502 | int err; | 500 | int err; |
503 | struct auth_domain *dom = NULL; | 501 | struct auth_domain *dom = NULL; |
504 | struct nameidata nd; | 502 | struct svc_export exp = {}, *expp; |
505 | struct svc_export exp, *expp; | ||
506 | int an_int; | 503 | int an_int; |
507 | 504 | ||
508 | nd.path.dentry = NULL; | ||
509 | exp.ex_pathname = NULL; | ||
510 | |||
511 | /* fs locations */ | ||
512 | exp.ex_fslocs.locations = NULL; | ||
513 | exp.ex_fslocs.locations_count = 0; | ||
514 | exp.ex_fslocs.migrated = 0; | ||
515 | |||
516 | exp.ex_uuid = NULL; | ||
517 | |||
518 | /* secinfo */ | ||
519 | exp.ex_nflavors = 0; | ||
520 | |||
521 | if (mesg[mlen-1] != '\n') | 505 | if (mesg[mlen-1] != '\n') |
522 | return -EINVAL; | 506 | return -EINVAL; |
523 | mesg[mlen-1] = 0; | 507 | mesg[mlen-1] = 0; |
524 | 508 | ||
525 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 509 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
526 | err = -ENOMEM; | 510 | if (!buf) |
527 | if (!buf) goto out; | 511 | return -ENOMEM; |
528 | 512 | ||
529 | /* client */ | 513 | /* client */ |
530 | len = qword_get(&mesg, buf, PAGE_SIZE); | ||
531 | err = -EINVAL; | 514 | err = -EINVAL; |
532 | if (len <= 0) goto out; | 515 | len = qword_get(&mesg, buf, PAGE_SIZE); |
516 | if (len <= 0) | ||
517 | goto out; | ||
533 | 518 | ||
534 | err = -ENOENT; | 519 | err = -ENOENT; |
535 | dom = auth_domain_find(buf); | 520 | dom = auth_domain_find(buf); |
@@ -538,25 +523,25 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
538 | 523 | ||
539 | /* path */ | 524 | /* path */ |
540 | err = -EINVAL; | 525 | err = -EINVAL; |
541 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) | 526 | if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0) |
542 | goto out; | 527 | goto out1; |
543 | err = path_lookup(buf, 0, &nd); | 528 | |
544 | if (err) goto out_no_path; | 529 | err = kern_path(buf, 0, &exp.ex_path); |
530 | if (err) | ||
531 | goto out1; | ||
545 | 532 | ||
546 | exp.h.flags = 0; | ||
547 | exp.ex_client = dom; | 533 | exp.ex_client = dom; |
548 | exp.ex_path.mnt = nd.path.mnt; | 534 | |
549 | exp.ex_path.dentry = nd.path.dentry; | ||
550 | exp.ex_pathname = kstrdup(buf, GFP_KERNEL); | ||
551 | err = -ENOMEM; | 535 | err = -ENOMEM; |
536 | exp.ex_pathname = kstrdup(buf, GFP_KERNEL); | ||
552 | if (!exp.ex_pathname) | 537 | if (!exp.ex_pathname) |
553 | goto out; | 538 | goto out2; |
554 | 539 | ||
555 | /* expiry */ | 540 | /* expiry */ |
556 | err = -EINVAL; | 541 | err = -EINVAL; |
557 | exp.h.expiry_time = get_expiry(&mesg); | 542 | exp.h.expiry_time = get_expiry(&mesg); |
558 | if (exp.h.expiry_time == 0) | 543 | if (exp.h.expiry_time == 0) |
559 | goto out; | 544 | goto out3; |
560 | 545 | ||
561 | /* flags */ | 546 | /* flags */ |
562 | err = get_int(&mesg, &an_int); | 547 | err = get_int(&mesg, &an_int); |
@@ -564,22 +549,26 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
564 | err = 0; | 549 | err = 0; |
565 | set_bit(CACHE_NEGATIVE, &exp.h.flags); | 550 | set_bit(CACHE_NEGATIVE, &exp.h.flags); |
566 | } else { | 551 | } else { |
567 | if (err || an_int < 0) goto out; | 552 | if (err || an_int < 0) |
553 | goto out3; | ||
568 | exp.ex_flags= an_int; | 554 | exp.ex_flags= an_int; |
569 | 555 | ||
570 | /* anon uid */ | 556 | /* anon uid */ |
571 | err = get_int(&mesg, &an_int); | 557 | err = get_int(&mesg, &an_int); |
572 | if (err) goto out; | 558 | if (err) |
559 | goto out3; | ||
573 | exp.ex_anon_uid= an_int; | 560 | exp.ex_anon_uid= an_int; |
574 | 561 | ||
575 | /* anon gid */ | 562 | /* anon gid */ |
576 | err = get_int(&mesg, &an_int); | 563 | err = get_int(&mesg, &an_int); |
577 | if (err) goto out; | 564 | if (err) |
565 | goto out3; | ||
578 | exp.ex_anon_gid= an_int; | 566 | exp.ex_anon_gid= an_int; |
579 | 567 | ||
580 | /* fsid */ | 568 | /* fsid */ |
581 | err = get_int(&mesg, &an_int); | 569 | err = get_int(&mesg, &an_int); |
582 | if (err) goto out; | 570 | if (err) |
571 | goto out3; | ||
583 | exp.ex_fsid = an_int; | 572 | exp.ex_fsid = an_int; |
584 | 573 | ||
585 | while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) { | 574 | while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) { |
@@ -605,12 +594,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
605 | */ | 594 | */ |
606 | break; | 595 | break; |
607 | if (err) | 596 | if (err) |
608 | goto out; | 597 | goto out4; |
609 | } | 598 | } |
610 | 599 | ||
611 | err = check_export(nd.path.dentry->d_inode, exp.ex_flags, | 600 | err = check_export(exp.ex_path.dentry->d_inode, exp.ex_flags, |
612 | exp.ex_uuid); | 601 | exp.ex_uuid); |
613 | if (err) goto out; | 602 | if (err) |
603 | goto out4; | ||
614 | } | 604 | } |
615 | 605 | ||
616 | expp = svc_export_lookup(&exp); | 606 | expp = svc_export_lookup(&exp); |
@@ -623,15 +613,16 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
623 | err = -ENOMEM; | 613 | err = -ENOMEM; |
624 | else | 614 | else |
625 | exp_put(expp); | 615 | exp_put(expp); |
626 | out: | 616 | out4: |
627 | nfsd4_fslocs_free(&exp.ex_fslocs); | 617 | nfsd4_fslocs_free(&exp.ex_fslocs); |
628 | kfree(exp.ex_uuid); | 618 | kfree(exp.ex_uuid); |
619 | out3: | ||
629 | kfree(exp.ex_pathname); | 620 | kfree(exp.ex_pathname); |
630 | if (nd.path.dentry) | 621 | out2: |
631 | path_put(&nd.path); | 622 | path_put(&exp.ex_path); |
632 | out_no_path: | 623 | out1: |
633 | if (dom) | 624 | auth_domain_put(dom); |
634 | auth_domain_put(dom); | 625 | out: |
635 | kfree(buf); | 626 | kfree(buf); |
636 | return err; | 627 | return err; |
637 | } | 628 | } |
@@ -999,7 +990,7 @@ exp_export(struct nfsctl_export *nxp) | |||
999 | struct svc_export *exp = NULL; | 990 | struct svc_export *exp = NULL; |
1000 | struct svc_export new; | 991 | struct svc_export new; |
1001 | struct svc_expkey *fsid_key = NULL; | 992 | struct svc_expkey *fsid_key = NULL; |
1002 | struct nameidata nd; | 993 | struct path path; |
1003 | int err; | 994 | int err; |
1004 | 995 | ||
1005 | /* Consistency check */ | 996 | /* Consistency check */ |
@@ -1022,12 +1013,12 @@ exp_export(struct nfsctl_export *nxp) | |||
1022 | 1013 | ||
1023 | 1014 | ||
1024 | /* Look up the dentry */ | 1015 | /* Look up the dentry */ |
1025 | err = path_lookup(nxp->ex_path, 0, &nd); | 1016 | err = kern_path(nxp->ex_path, 0, &path); |
1026 | if (err) | 1017 | if (err) |
1027 | goto out_put_clp; | 1018 | goto out_put_clp; |
1028 | err = -EINVAL; | 1019 | err = -EINVAL; |
1029 | 1020 | ||
1030 | exp = exp_get_by_name(clp, nd.path.mnt, nd.path.dentry, NULL); | 1021 | exp = exp_get_by_name(clp, path.mnt, path.dentry, NULL); |
1031 | 1022 | ||
1032 | memset(&new, 0, sizeof(new)); | 1023 | memset(&new, 0, sizeof(new)); |
1033 | 1024 | ||
@@ -1035,8 +1026,8 @@ exp_export(struct nfsctl_export *nxp) | |||
1035 | if ((nxp->ex_flags & NFSEXP_FSID) && | 1026 | if ((nxp->ex_flags & NFSEXP_FSID) && |
1036 | (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) && | 1027 | (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) && |
1037 | fsid_key->ek_path.mnt && | 1028 | fsid_key->ek_path.mnt && |
1038 | (fsid_key->ek_path.mnt != nd.path.mnt || | 1029 | (fsid_key->ek_path.mnt != path.mnt || |
1039 | fsid_key->ek_path.dentry != nd.path.dentry)) | 1030 | fsid_key->ek_path.dentry != path.dentry)) |
1040 | goto finish; | 1031 | goto finish; |
1041 | 1032 | ||
1042 | if (!IS_ERR(exp)) { | 1033 | if (!IS_ERR(exp)) { |
@@ -1052,7 +1043,7 @@ exp_export(struct nfsctl_export *nxp) | |||
1052 | goto finish; | 1043 | goto finish; |
1053 | } | 1044 | } |
1054 | 1045 | ||
1055 | err = check_export(nd.path.dentry->d_inode, nxp->ex_flags, NULL); | 1046 | err = check_export(path.dentry->d_inode, nxp->ex_flags, NULL); |
1056 | if (err) goto finish; | 1047 | if (err) goto finish; |
1057 | 1048 | ||
1058 | err = -ENOMEM; | 1049 | err = -ENOMEM; |
@@ -1065,7 +1056,7 @@ exp_export(struct nfsctl_export *nxp) | |||
1065 | if (!new.ex_pathname) | 1056 | if (!new.ex_pathname) |
1066 | goto finish; | 1057 | goto finish; |
1067 | new.ex_client = clp; | 1058 | new.ex_client = clp; |
1068 | new.ex_path = nd.path; | 1059 | new.ex_path = path; |
1069 | new.ex_flags = nxp->ex_flags; | 1060 | new.ex_flags = nxp->ex_flags; |
1070 | new.ex_anon_uid = nxp->ex_anon_uid; | 1061 | new.ex_anon_uid = nxp->ex_anon_uid; |
1071 | new.ex_anon_gid = nxp->ex_anon_gid; | 1062 | new.ex_anon_gid = nxp->ex_anon_gid; |
@@ -1091,7 +1082,7 @@ finish: | |||
1091 | exp_put(exp); | 1082 | exp_put(exp); |
1092 | if (fsid_key && !IS_ERR(fsid_key)) | 1083 | if (fsid_key && !IS_ERR(fsid_key)) |
1093 | cache_put(&fsid_key->h, &svc_expkey_cache); | 1084 | cache_put(&fsid_key->h, &svc_expkey_cache); |
1094 | path_put(&nd.path); | 1085 | path_put(&path); |
1095 | out_put_clp: | 1086 | out_put_clp: |
1096 | auth_domain_put(clp); | 1087 | auth_domain_put(clp); |
1097 | out_unlock: | 1088 | out_unlock: |
@@ -1122,7 +1113,7 @@ exp_unexport(struct nfsctl_export *nxp) | |||
1122 | { | 1113 | { |
1123 | struct auth_domain *dom; | 1114 | struct auth_domain *dom; |
1124 | svc_export *exp; | 1115 | svc_export *exp; |
1125 | struct nameidata nd; | 1116 | struct path path; |
1126 | int err; | 1117 | int err; |
1127 | 1118 | ||
1128 | /* Consistency check */ | 1119 | /* Consistency check */ |
@@ -1139,13 +1130,13 @@ exp_unexport(struct nfsctl_export *nxp) | |||
1139 | goto out_unlock; | 1130 | goto out_unlock; |
1140 | } | 1131 | } |
1141 | 1132 | ||
1142 | err = path_lookup(nxp->ex_path, 0, &nd); | 1133 | err = kern_path(nxp->ex_path, 0, &path); |
1143 | if (err) | 1134 | if (err) |
1144 | goto out_domain; | 1135 | goto out_domain; |
1145 | 1136 | ||
1146 | err = -EINVAL; | 1137 | err = -EINVAL; |
1147 | exp = exp_get_by_name(dom, nd.path.mnt, nd.path.dentry, NULL); | 1138 | exp = exp_get_by_name(dom, path.mnt, path.dentry, NULL); |
1148 | path_put(&nd.path); | 1139 | path_put(&path); |
1149 | if (IS_ERR(exp)) | 1140 | if (IS_ERR(exp)) |
1150 | goto out_domain; | 1141 | goto out_domain; |
1151 | 1142 | ||
@@ -1167,26 +1158,26 @@ out_unlock: | |||
1167 | * since its harder to fool a kernel module than a user space program. | 1158 | * since its harder to fool a kernel module than a user space program. |
1168 | */ | 1159 | */ |
1169 | int | 1160 | int |
1170 | exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) | 1161 | exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize) |
1171 | { | 1162 | { |
1172 | struct svc_export *exp; | 1163 | struct svc_export *exp; |
1173 | struct nameidata nd; | 1164 | struct path path; |
1174 | struct inode *inode; | 1165 | struct inode *inode; |
1175 | struct svc_fh fh; | 1166 | struct svc_fh fh; |
1176 | int err; | 1167 | int err; |
1177 | 1168 | ||
1178 | err = -EPERM; | 1169 | err = -EPERM; |
1179 | /* NB: we probably ought to check that it's NUL-terminated */ | 1170 | /* NB: we probably ought to check that it's NUL-terminated */ |
1180 | if (path_lookup(path, 0, &nd)) { | 1171 | if (kern_path(name, 0, &path)) { |
1181 | printk("nfsd: exp_rootfh path not found %s", path); | 1172 | printk("nfsd: exp_rootfh path not found %s", name); |
1182 | return err; | 1173 | return err; |
1183 | } | 1174 | } |
1184 | inode = nd.path.dentry->d_inode; | 1175 | inode = path.dentry->d_inode; |
1185 | 1176 | ||
1186 | dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", | 1177 | dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", |
1187 | path, nd.path.dentry, clp->name, | 1178 | name, path.dentry, clp->name, |
1188 | inode->i_sb->s_id, inode->i_ino); | 1179 | inode->i_sb->s_id, inode->i_ino); |
1189 | exp = exp_parent(clp, nd.path.mnt, nd.path.dentry, NULL); | 1180 | exp = exp_parent(clp, path.mnt, path.dentry, NULL); |
1190 | if (IS_ERR(exp)) { | 1181 | if (IS_ERR(exp)) { |
1191 | err = PTR_ERR(exp); | 1182 | err = PTR_ERR(exp); |
1192 | goto out; | 1183 | goto out; |
@@ -1196,7 +1187,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) | |||
1196 | * fh must be initialized before calling fh_compose | 1187 | * fh must be initialized before calling fh_compose |
1197 | */ | 1188 | */ |
1198 | fh_init(&fh, maxsize); | 1189 | fh_init(&fh, maxsize); |
1199 | if (fh_compose(&fh, exp, nd.path.dentry, NULL)) | 1190 | if (fh_compose(&fh, exp, path.dentry, NULL)) |
1200 | err = -EINVAL; | 1191 | err = -EINVAL; |
1201 | else | 1192 | else |
1202 | err = 0; | 1193 | err = 0; |
@@ -1204,7 +1195,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) | |||
1204 | fh_put(&fh); | 1195 | fh_put(&fh); |
1205 | exp_put(exp); | 1196 | exp_put(exp); |
1206 | out: | 1197 | out: |
1207 | path_put(&nd.path); | 1198 | path_put(&path); |
1208 | return err; | 1199 | return err; |
1209 | } | 1200 | } |
1210 | 1201 | ||
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 145b3c877a27..bb93946ace22 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 51 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
52 | 52 | ||
53 | /* Globals */ | 53 | /* Globals */ |
54 | static struct nameidata rec_dir; | 54 | static struct path rec_dir; |
55 | static int rec_dir_init = 0; | 55 | static int rec_dir_init = 0; |
56 | 56 | ||
57 | static void | 57 | static void |
@@ -121,9 +121,9 @@ out_no_tfm: | |||
121 | static void | 121 | static void |
122 | nfsd4_sync_rec_dir(void) | 122 | nfsd4_sync_rec_dir(void) |
123 | { | 123 | { |
124 | mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); | 124 | mutex_lock(&rec_dir.dentry->d_inode->i_mutex); |
125 | nfsd_sync_dir(rec_dir.path.dentry); | 125 | nfsd_sync_dir(rec_dir.dentry); |
126 | mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); | 126 | mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); |
127 | } | 127 | } |
128 | 128 | ||
129 | int | 129 | int |
@@ -143,9 +143,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
143 | nfs4_save_user(&uid, &gid); | 143 | nfs4_save_user(&uid, &gid); |
144 | 144 | ||
145 | /* lock the parent */ | 145 | /* lock the parent */ |
146 | mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); | 146 | mutex_lock(&rec_dir.dentry->d_inode->i_mutex); |
147 | 147 | ||
148 | dentry = lookup_one_len(dname, rec_dir.path.dentry, HEXDIR_LEN-1); | 148 | dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1); |
149 | if (IS_ERR(dentry)) { | 149 | if (IS_ERR(dentry)) { |
150 | status = PTR_ERR(dentry); | 150 | status = PTR_ERR(dentry); |
151 | goto out_unlock; | 151 | goto out_unlock; |
@@ -155,15 +155,15 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
155 | dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); | 155 | dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); |
156 | goto out_put; | 156 | goto out_put; |
157 | } | 157 | } |
158 | status = mnt_want_write(rec_dir.path.mnt); | 158 | status = mnt_want_write(rec_dir.mnt); |
159 | if (status) | 159 | if (status) |
160 | goto out_put; | 160 | goto out_put; |
161 | status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU); | 161 | status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU); |
162 | mnt_drop_write(rec_dir.path.mnt); | 162 | mnt_drop_write(rec_dir.mnt); |
163 | out_put: | 163 | out_put: |
164 | dput(dentry); | 164 | dput(dentry); |
165 | out_unlock: | 165 | out_unlock: |
166 | mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); | 166 | mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); |
167 | if (status == 0) { | 167 | if (status == 0) { |
168 | clp->cl_firststate = 1; | 168 | clp->cl_firststate = 1; |
169 | nfsd4_sync_rec_dir(); | 169 | nfsd4_sync_rec_dir(); |
@@ -226,7 +226,7 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | |||
226 | 226 | ||
227 | nfs4_save_user(&uid, &gid); | 227 | nfs4_save_user(&uid, &gid); |
228 | 228 | ||
229 | filp = dentry_open(dget(dir), mntget(rec_dir.path.mnt), O_RDONLY); | 229 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY); |
230 | status = PTR_ERR(filp); | 230 | status = PTR_ERR(filp); |
231 | if (IS_ERR(filp)) | 231 | if (IS_ERR(filp)) |
232 | goto out; | 232 | goto out; |
@@ -291,9 +291,9 @@ nfsd4_unlink_clid_dir(char *name, int namlen) | |||
291 | 291 | ||
292 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); | 292 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); |
293 | 293 | ||
294 | mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); | 294 | mutex_lock(&rec_dir.dentry->d_inode->i_mutex); |
295 | dentry = lookup_one_len(name, rec_dir.path.dentry, namlen); | 295 | dentry = lookup_one_len(name, rec_dir.dentry, namlen); |
296 | mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); | 296 | mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); |
297 | if (IS_ERR(dentry)) { | 297 | if (IS_ERR(dentry)) { |
298 | status = PTR_ERR(dentry); | 298 | status = PTR_ERR(dentry); |
299 | return status; | 299 | return status; |
@@ -302,7 +302,7 @@ nfsd4_unlink_clid_dir(char *name, int namlen) | |||
302 | if (!dentry->d_inode) | 302 | if (!dentry->d_inode) |
303 | goto out; | 303 | goto out; |
304 | 304 | ||
305 | status = nfsd4_clear_clid_dir(rec_dir.path.dentry, dentry); | 305 | status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry); |
306 | out: | 306 | out: |
307 | dput(dentry); | 307 | dput(dentry); |
308 | return status; | 308 | return status; |
@@ -318,7 +318,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) | |||
318 | if (!rec_dir_init || !clp->cl_firststate) | 318 | if (!rec_dir_init || !clp->cl_firststate) |
319 | return; | 319 | return; |
320 | 320 | ||
321 | status = mnt_want_write(rec_dir.path.mnt); | 321 | status = mnt_want_write(rec_dir.mnt); |
322 | if (status) | 322 | if (status) |
323 | goto out; | 323 | goto out; |
324 | clp->cl_firststate = 0; | 324 | clp->cl_firststate = 0; |
@@ -327,7 +327,7 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) | |||
327 | nfs4_reset_user(uid, gid); | 327 | nfs4_reset_user(uid, gid); |
328 | if (status == 0) | 328 | if (status == 0) |
329 | nfsd4_sync_rec_dir(); | 329 | nfsd4_sync_rec_dir(); |
330 | mnt_drop_write(rec_dir.path.mnt); | 330 | mnt_drop_write(rec_dir.mnt); |
331 | out: | 331 | out: |
332 | if (status) | 332 | if (status) |
333 | printk("NFSD: Failed to remove expired client state directory" | 333 | printk("NFSD: Failed to remove expired client state directory" |
@@ -357,17 +357,17 @@ nfsd4_recdir_purge_old(void) { | |||
357 | 357 | ||
358 | if (!rec_dir_init) | 358 | if (!rec_dir_init) |
359 | return; | 359 | return; |
360 | status = mnt_want_write(rec_dir.path.mnt); | 360 | status = mnt_want_write(rec_dir.mnt); |
361 | if (status) | 361 | if (status) |
362 | goto out; | 362 | goto out; |
363 | status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old); | 363 | status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old); |
364 | if (status == 0) | 364 | if (status == 0) |
365 | nfsd4_sync_rec_dir(); | 365 | nfsd4_sync_rec_dir(); |
366 | mnt_drop_write(rec_dir.path.mnt); | 366 | mnt_drop_write(rec_dir.mnt); |
367 | out: | 367 | out: |
368 | if (status) | 368 | if (status) |
369 | printk("nfsd4: failed to purge old clients from recovery" | 369 | printk("nfsd4: failed to purge old clients from recovery" |
370 | " directory %s\n", rec_dir.path.dentry->d_name.name); | 370 | " directory %s\n", rec_dir.dentry->d_name.name); |
371 | } | 371 | } |
372 | 372 | ||
373 | static int | 373 | static int |
@@ -387,10 +387,10 @@ int | |||
387 | nfsd4_recdir_load(void) { | 387 | nfsd4_recdir_load(void) { |
388 | int status; | 388 | int status; |
389 | 389 | ||
390 | status = nfsd4_list_rec_dir(rec_dir.path.dentry, load_recdir); | 390 | status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir); |
391 | if (status) | 391 | if (status) |
392 | printk("nfsd4: failed loading clients from recovery" | 392 | printk("nfsd4: failed loading clients from recovery" |
393 | " directory %s\n", rec_dir.path.dentry->d_name.name); | 393 | " directory %s\n", rec_dir.dentry->d_name.name); |
394 | return status; | 394 | return status; |
395 | } | 395 | } |
396 | 396 | ||
@@ -412,7 +412,7 @@ nfsd4_init_recdir(char *rec_dirname) | |||
412 | 412 | ||
413 | nfs4_save_user(&uid, &gid); | 413 | nfs4_save_user(&uid, &gid); |
414 | 414 | ||
415 | status = path_lookup(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 415 | status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, |
416 | &rec_dir); | 416 | &rec_dir); |
417 | if (status) | 417 | if (status) |
418 | printk("NFSD: unable to find recovery directory %s\n", | 418 | printk("NFSD: unable to find recovery directory %s\n", |
@@ -429,5 +429,5 @@ nfsd4_shutdown_recdir(void) | |||
429 | if (!rec_dir_init) | 429 | if (!rec_dir_init) |
430 | return; | 430 | return; |
431 | rec_dir_init = 0; | 431 | rec_dir_init = 0; |
432 | path_put(&rec_dir.path); | 432 | path_put(&rec_dir); |
433 | } | 433 | } |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0cc7ff5d5ab5..b0bebc552a11 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -3284,17 +3284,17 @@ int | |||
3284 | nfs4_reset_recoverydir(char *recdir) | 3284 | nfs4_reset_recoverydir(char *recdir) |
3285 | { | 3285 | { |
3286 | int status; | 3286 | int status; |
3287 | struct nameidata nd; | 3287 | struct path path; |
3288 | 3288 | ||
3289 | status = path_lookup(recdir, LOOKUP_FOLLOW, &nd); | 3289 | status = kern_path(recdir, LOOKUP_FOLLOW, &path); |
3290 | if (status) | 3290 | if (status) |
3291 | return status; | 3291 | return status; |
3292 | status = -ENOTDIR; | 3292 | status = -ENOTDIR; |
3293 | if (S_ISDIR(nd.path.dentry->d_inode->i_mode)) { | 3293 | if (S_ISDIR(path.dentry->d_inode->i_mode)) { |
3294 | nfs4_set_recdir(recdir); | 3294 | nfs4_set_recdir(recdir); |
3295 | status = 0; | 3295 | status = 0; |
3296 | } | 3296 | } |
3297 | path_put(&nd.path); | 3297 | path_put(&path); |
3298 | return status; | 3298 | return status; |
3299 | } | 3299 | } |
3300 | 3300 | ||
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 97543df58242..e3f9783fdcf7 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -341,7 +341,7 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) | |||
341 | 341 | ||
342 | static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) | 342 | static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) |
343 | { | 343 | { |
344 | struct nameidata nd; | 344 | struct path path; |
345 | char *fo_path; | 345 | char *fo_path; |
346 | int error; | 346 | int error; |
347 | 347 | ||
@@ -356,13 +356,13 @@ static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) | |||
356 | if (qword_get(&buf, fo_path, size) < 0) | 356 | if (qword_get(&buf, fo_path, size) < 0) |
357 | return -EINVAL; | 357 | return -EINVAL; |
358 | 358 | ||
359 | error = path_lookup(fo_path, 0, &nd); | 359 | error = kern_path(fo_path, 0, &path); |
360 | if (error) | 360 | if (error) |
361 | return error; | 361 | return error; |
362 | 362 | ||
363 | error = nlmsvc_unlock_all_by_sb(nd.path.mnt->mnt_sb); | 363 | error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb); |
364 | 364 | ||
365 | path_put(&nd.path); | 365 | path_put(&path); |
366 | return error; | 366 | return error; |
367 | } | 367 | } |
368 | 368 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 9609eb51d727..0bc56f6d9276 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1818,6 +1818,115 @@ out: | |||
1818 | } | 1818 | } |
1819 | 1819 | ||
1820 | /* | 1820 | /* |
1821 | * We do this buffering because we must not call back into the file | ||
1822 | * system's ->lookup() method from the filldir callback. That may well | ||
1823 | * deadlock a number of file systems. | ||
1824 | * | ||
1825 | * This is based heavily on the implementation of same in XFS. | ||
1826 | */ | ||
1827 | struct buffered_dirent { | ||
1828 | u64 ino; | ||
1829 | loff_t offset; | ||
1830 | int namlen; | ||
1831 | unsigned int d_type; | ||
1832 | char name[]; | ||
1833 | }; | ||
1834 | |||
1835 | struct readdir_data { | ||
1836 | char *dirent; | ||
1837 | size_t used; | ||
1838 | int full; | ||
1839 | }; | ||
1840 | |||
1841 | static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen, | ||
1842 | loff_t offset, u64 ino, unsigned int d_type) | ||
1843 | { | ||
1844 | struct readdir_data *buf = __buf; | ||
1845 | struct buffered_dirent *de = (void *)(buf->dirent + buf->used); | ||
1846 | unsigned int reclen; | ||
1847 | |||
1848 | reclen = ALIGN(sizeof(struct buffered_dirent) + namlen, sizeof(u64)); | ||
1849 | if (buf->used + reclen > PAGE_SIZE) { | ||
1850 | buf->full = 1; | ||
1851 | return -EINVAL; | ||
1852 | } | ||
1853 | |||
1854 | de->namlen = namlen; | ||
1855 | de->offset = offset; | ||
1856 | de->ino = ino; | ||
1857 | de->d_type = d_type; | ||
1858 | memcpy(de->name, name, namlen); | ||
1859 | buf->used += reclen; | ||
1860 | |||
1861 | return 0; | ||
1862 | } | ||
1863 | |||
1864 | static int nfsd_buffered_readdir(struct file *file, filldir_t func, | ||
1865 | struct readdir_cd *cdp, loff_t *offsetp) | ||
1866 | { | ||
1867 | struct readdir_data buf; | ||
1868 | struct buffered_dirent *de; | ||
1869 | int host_err; | ||
1870 | int size; | ||
1871 | loff_t offset; | ||
1872 | |||
1873 | buf.dirent = (void *)__get_free_page(GFP_KERNEL); | ||
1874 | if (!buf.dirent) | ||
1875 | return -ENOMEM; | ||
1876 | |||
1877 | offset = *offsetp; | ||
1878 | cdp->err = nfserr_eof; /* will be cleared on successful read */ | ||
1879 | |||
1880 | while (1) { | ||
1881 | unsigned int reclen; | ||
1882 | |||
1883 | buf.used = 0; | ||
1884 | buf.full = 0; | ||
1885 | |||
1886 | host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf); | ||
1887 | if (buf.full) | ||
1888 | host_err = 0; | ||
1889 | |||
1890 | if (host_err < 0) | ||
1891 | break; | ||
1892 | |||
1893 | size = buf.used; | ||
1894 | |||
1895 | if (!size) | ||
1896 | break; | ||
1897 | |||
1898 | de = (struct buffered_dirent *)buf.dirent; | ||
1899 | while (size > 0) { | ||
1900 | offset = de->offset; | ||
1901 | |||
1902 | if (func(cdp, de->name, de->namlen, de->offset, | ||
1903 | de->ino, de->d_type)) | ||
1904 | goto done; | ||
1905 | |||
1906 | if (cdp->err != nfs_ok) | ||
1907 | goto done; | ||
1908 | |||
1909 | reclen = ALIGN(sizeof(*de) + de->namlen, | ||
1910 | sizeof(u64)); | ||
1911 | size -= reclen; | ||
1912 | de = (struct buffered_dirent *)((char *)de + reclen); | ||
1913 | } | ||
1914 | offset = vfs_llseek(file, 0, SEEK_CUR); | ||
1915 | if (!buf.full) | ||
1916 | break; | ||
1917 | } | ||
1918 | |||
1919 | done: | ||
1920 | free_page((unsigned long)(buf.dirent)); | ||
1921 | |||
1922 | if (host_err) | ||
1923 | return nfserrno(host_err); | ||
1924 | |||
1925 | *offsetp = offset; | ||
1926 | return cdp->err; | ||
1927 | } | ||
1928 | |||
1929 | /* | ||
1821 | * Read entries from a directory. | 1930 | * Read entries from a directory. |
1822 | * The NFSv3/4 verifier we ignore for now. | 1931 | * The NFSv3/4 verifier we ignore for now. |
1823 | */ | 1932 | */ |
@@ -1826,7 +1935,6 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | |||
1826 | struct readdir_cd *cdp, filldir_t func) | 1935 | struct readdir_cd *cdp, filldir_t func) |
1827 | { | 1936 | { |
1828 | __be32 err; | 1937 | __be32 err; |
1829 | int host_err; | ||
1830 | struct file *file; | 1938 | struct file *file; |
1831 | loff_t offset = *offsetp; | 1939 | loff_t offset = *offsetp; |
1832 | 1940 | ||
@@ -1840,21 +1948,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | |||
1840 | goto out_close; | 1948 | goto out_close; |
1841 | } | 1949 | } |
1842 | 1950 | ||
1843 | /* | 1951 | err = nfsd_buffered_readdir(file, func, cdp, offsetp); |
1844 | * Read the directory entries. This silly loop is necessary because | ||
1845 | * readdir() is not guaranteed to fill up the entire buffer, but | ||
1846 | * may choose to do less. | ||
1847 | */ | ||
1848 | |||
1849 | do { | ||
1850 | cdp->err = nfserr_eof; /* will be cleared on successful read */ | ||
1851 | host_err = vfs_readdir(file, func, cdp); | ||
1852 | } while (host_err >=0 && cdp->err == nfs_ok); | ||
1853 | if (host_err) | ||
1854 | err = nfserrno(host_err); | ||
1855 | else | ||
1856 | err = cdp->err; | ||
1857 | *offsetp = vfs_llseek(file, 0, 1); | ||
1858 | 1952 | ||
1859 | if (err == nfserr_eof || err == nfserr_toosmall) | 1953 | if (err == nfserr_eof || err == nfserr_toosmall) |
1860 | err = nfs_ok; /* can still be found in ->err */ | 1954 | err = nfs_ok; /* can still be found in ->err */ |