diff options
author | NeilBrown <neilb@suse.de> | 2007-02-14 03:33:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-14 11:09:53 -0500 |
commit | af6a4e280e3ff453653f39190b57b345ff0bec16 (patch) | |
tree | 4895c90613737db7354f43431ed10a55dc0c98f0 | |
parent | 982aedfd091e6d9831216f8519f12242091be4fd (diff) |
[PATCH] knfsd: add some new fsid types
Add support for using a filesystem UUID to identify and export point in the
filehandle.
For NFSv2, this UUID is xor-ed down to 4 or 8 bytes so that it doesn't take up
too much room. For NFSv3+, we use the full 16 bytes, and possibly also a
64bit inode number for exports beneath the root of a filesystem.
When generating an fsid to return in 'stat' information, use the UUID (hashed
down to size) if it is available and a small 'fsid' was not specifically
provided.
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/nfsd/export.c | 106 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 31 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 10 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 88 | ||||
-rw-r--r-- | fs/nfsd/nfsxdr.c | 19 | ||||
-rw-r--r-- | include/linux/nfsd/export.h | 7 | ||||
-rw-r--r-- | include/linux/nfsd/nfsd.h | 12 | ||||
-rw-r--r-- | include/linux/nfsd/nfsfh.h | 99 |
8 files changed, 242 insertions, 130 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 49c310b84923..bb3c314e2479 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -190,18 +190,17 @@ static int expkey_show(struct seq_file *m, | |||
190 | struct cache_head *h) | 190 | struct cache_head *h) |
191 | { | 191 | { |
192 | struct svc_expkey *ek ; | 192 | struct svc_expkey *ek ; |
193 | int i; | ||
193 | 194 | ||
194 | if (h ==NULL) { | 195 | if (h ==NULL) { |
195 | seq_puts(m, "#domain fsidtype fsid [path]\n"); | 196 | seq_puts(m, "#domain fsidtype fsid [path]\n"); |
196 | return 0; | 197 | return 0; |
197 | } | 198 | } |
198 | ek = container_of(h, struct svc_expkey, h); | 199 | ek = container_of(h, struct svc_expkey, h); |
199 | seq_printf(m, "%s %d 0x%08x", ek->ek_client->name, | 200 | seq_printf(m, "%s %d 0x", ek->ek_client->name, |
200 | ek->ek_fsidtype, ek->ek_fsid[0]); | 201 | ek->ek_fsidtype); |
201 | if (ek->ek_fsidtype != 1) | 202 | for (i=0; i < key_len(ek->ek_fsidtype)/4; i++) |
202 | seq_printf(m, "%08x", ek->ek_fsid[1]); | 203 | seq_printf(m, "%08x", ek->ek_fsid[i]); |
203 | if (ek->ek_fsidtype == 2) | ||
204 | seq_printf(m, "%08x", ek->ek_fsid[2]); | ||
205 | if (test_bit(CACHE_VALID, &h->flags) && | 204 | if (test_bit(CACHE_VALID, &h->flags) && |
206 | !test_bit(CACHE_NEGATIVE, &h->flags)) { | 205 | !test_bit(CACHE_NEGATIVE, &h->flags)) { |
207 | seq_printf(m, " "); | 206 | seq_printf(m, " "); |
@@ -232,9 +231,8 @@ static inline void expkey_init(struct cache_head *cnew, | |||
232 | kref_get(&item->ek_client->ref); | 231 | kref_get(&item->ek_client->ref); |
233 | new->ek_client = item->ek_client; | 232 | new->ek_client = item->ek_client; |
234 | new->ek_fsidtype = item->ek_fsidtype; | 233 | new->ek_fsidtype = item->ek_fsidtype; |
235 | new->ek_fsid[0] = item->ek_fsid[0]; | 234 | |
236 | new->ek_fsid[1] = item->ek_fsid[1]; | 235 | memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid)); |
237 | new->ek_fsid[2] = item->ek_fsid[2]; | ||
238 | } | 236 | } |
239 | 237 | ||
240 | static inline void expkey_update(struct cache_head *cnew, | 238 | static inline void expkey_update(struct cache_head *cnew, |
@@ -363,7 +361,7 @@ static struct svc_export *svc_export_update(struct svc_export *new, | |||
363 | struct svc_export *old); | 361 | struct svc_export *old); |
364 | static struct svc_export *svc_export_lookup(struct svc_export *); | 362 | static struct svc_export *svc_export_lookup(struct svc_export *); |
365 | 363 | ||
366 | static int check_export(struct inode *inode, int flags) | 364 | static int check_export(struct inode *inode, int flags, unsigned char *uuid) |
367 | { | 365 | { |
368 | 366 | ||
369 | /* We currently export only dirs and regular files. | 367 | /* We currently export only dirs and regular files. |
@@ -376,12 +374,13 @@ static int check_export(struct inode *inode, int flags) | |||
376 | /* There are two requirements on a filesystem to be exportable. | 374 | /* There are two requirements on a filesystem to be exportable. |
377 | * 1: We must be able to identify the filesystem from a number. | 375 | * 1: We must be able to identify the filesystem from a number. |
378 | * either a device number (so FS_REQUIRES_DEV needed) | 376 | * either a device number (so FS_REQUIRES_DEV needed) |
379 | * or an FSID number (so NFSEXP_FSID needed). | 377 | * or an FSID number (so NFSEXP_FSID or ->uuid is needed). |
380 | * 2: We must be able to find an inode from a filehandle. | 378 | * 2: We must be able to find an inode from a filehandle. |
381 | * This means that s_export_op must be set. | 379 | * This means that s_export_op must be set. |
382 | */ | 380 | */ |
383 | if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && | 381 | if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && |
384 | !(flags & NFSEXP_FSID)) { | 382 | !(flags & NFSEXP_FSID) && |
383 | uuid == NULL) { | ||
385 | dprintk("exp_export: export of non-dev fs without fsid\n"); | 384 | dprintk("exp_export: export of non-dev fs without fsid\n"); |
386 | return -EINVAL; | 385 | return -EINVAL; |
387 | } | 386 | } |
@@ -406,10 +405,6 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) | |||
406 | int len; | 405 | int len; |
407 | int migrated, i, err; | 406 | int migrated, i, err; |
408 | 407 | ||
409 | len = qword_get(mesg, buf, PAGE_SIZE); | ||
410 | if (len != 5 || memcmp(buf, "fsloc", 5)) | ||
411 | return 0; | ||
412 | |||
413 | /* listsize */ | 408 | /* listsize */ |
414 | err = get_int(mesg, &fsloc->locations_count); | 409 | err = get_int(mesg, &fsloc->locations_count); |
415 | if (err) | 410 | if (err) |
@@ -520,6 +515,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
520 | exp.ex_fslocs.locations_count = 0; | 515 | exp.ex_fslocs.locations_count = 0; |
521 | exp.ex_fslocs.migrated = 0; | 516 | exp.ex_fslocs.migrated = 0; |
522 | 517 | ||
518 | exp.ex_uuid = NULL; | ||
519 | |||
523 | /* flags */ | 520 | /* flags */ |
524 | err = get_int(&mesg, &an_int); | 521 | err = get_int(&mesg, &an_int); |
525 | if (err == -ENOENT) | 522 | if (err == -ENOENT) |
@@ -543,12 +540,33 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
543 | if (err) goto out; | 540 | if (err) goto out; |
544 | exp.ex_fsid = an_int; | 541 | exp.ex_fsid = an_int; |
545 | 542 | ||
546 | err = check_export(nd.dentry->d_inode, exp.ex_flags); | 543 | while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) { |
547 | if (err) goto out; | 544 | if (strcmp(buf, "fsloc") == 0) |
545 | err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); | ||
546 | else if (strcmp(buf, "uuid") == 0) { | ||
547 | /* expect a 16 byte uuid encoded as \xXXXX... */ | ||
548 | len = qword_get(&mesg, buf, PAGE_SIZE); | ||
549 | if (len != 16) | ||
550 | err = -EINVAL; | ||
551 | else { | ||
552 | exp.ex_uuid = | ||
553 | kmemdup(buf, 16, GFP_KERNEL); | ||
554 | if (exp.ex_uuid == NULL) | ||
555 | err = -ENOMEM; | ||
556 | } | ||
557 | } else | ||
558 | /* quietly ignore unknown words and anything | ||
559 | * following. Newer user-space can try to set | ||
560 | * new values, then see what the result was. | ||
561 | */ | ||
562 | break; | ||
563 | if (err) | ||
564 | goto out; | ||
565 | } | ||
548 | 566 | ||
549 | err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); | 567 | err = check_export(nd.dentry->d_inode, exp.ex_flags, |
550 | if (err) | 568 | exp.ex_uuid); |
551 | goto out; | 569 | if (err) goto out; |
552 | } | 570 | } |
553 | 571 | ||
554 | expp = svc_export_lookup(&exp); | 572 | expp = svc_export_lookup(&exp); |
@@ -562,6 +580,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
562 | else | 580 | else |
563 | exp_put(expp); | 581 | exp_put(expp); |
564 | out: | 582 | out: |
583 | nfsd4_fslocs_free(&exp.ex_fslocs); | ||
584 | kfree(exp.ex_uuid); | ||
565 | kfree(exp.ex_path); | 585 | kfree(exp.ex_path); |
566 | if (nd.dentry) | 586 | if (nd.dentry) |
567 | path_release(&nd); | 587 | path_release(&nd); |
@@ -591,9 +611,19 @@ static int svc_export_show(struct seq_file *m, | |||
591 | seq_escape(m, exp->ex_client->name, " \t\n\\"); | 611 | seq_escape(m, exp->ex_client->name, " \t\n\\"); |
592 | seq_putc(m, '('); | 612 | seq_putc(m, '('); |
593 | if (test_bit(CACHE_VALID, &h->flags) && | 613 | if (test_bit(CACHE_VALID, &h->flags) && |
594 | !test_bit(CACHE_NEGATIVE, &h->flags)) | 614 | !test_bit(CACHE_NEGATIVE, &h->flags)) { |
595 | exp_flags(m, exp->ex_flags, exp->ex_fsid, | 615 | exp_flags(m, exp->ex_flags, exp->ex_fsid, |
596 | exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); | 616 | exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); |
617 | if (exp->ex_uuid) { | ||
618 | int i; | ||
619 | seq_puts(m, ",uuid="); | ||
620 | for (i=0; i<16; i++) { | ||
621 | if ((i&3) == 0 && i) | ||
622 | seq_putc(m, ':'); | ||
623 | seq_printf(m, "%02x", exp->ex_uuid[i]); | ||
624 | } | ||
625 | } | ||
626 | } | ||
597 | seq_puts(m, ")\n"); | 627 | seq_puts(m, ")\n"); |
598 | return 0; | 628 | return 0; |
599 | } | 629 | } |
@@ -630,6 +660,8 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) | |||
630 | new->ex_anon_uid = item->ex_anon_uid; | 660 | new->ex_anon_uid = item->ex_anon_uid; |
631 | new->ex_anon_gid = item->ex_anon_gid; | 661 | new->ex_anon_gid = item->ex_anon_gid; |
632 | new->ex_fsid = item->ex_fsid; | 662 | new->ex_fsid = item->ex_fsid; |
663 | new->ex_uuid = item->ex_uuid; | ||
664 | item->ex_uuid = NULL; | ||
633 | new->ex_path = item->ex_path; | 665 | new->ex_path = item->ex_path; |
634 | item->ex_path = NULL; | 666 | item->ex_path = NULL; |
635 | new->ex_fslocs.locations = item->ex_fslocs.locations; | 667 | new->ex_fslocs.locations = item->ex_fslocs.locations; |
@@ -752,11 +784,11 @@ exp_get_key(svc_client *clp, dev_t dev, ino_t ino) | |||
752 | u32 fsidv[3]; | 784 | u32 fsidv[3]; |
753 | 785 | ||
754 | if (old_valid_dev(dev)) { | 786 | if (old_valid_dev(dev)) { |
755 | mk_fsid_v0(fsidv, dev, ino); | 787 | mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL); |
756 | return exp_find_key(clp, 0, fsidv, NULL); | 788 | return exp_find_key(clp, FSID_DEV, fsidv, NULL); |
757 | } | 789 | } |
758 | mk_fsid_v3(fsidv, dev, ino); | 790 | mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL); |
759 | return exp_find_key(clp, 3, fsidv, NULL); | 791 | return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL); |
760 | } | 792 | } |
761 | 793 | ||
762 | /* | 794 | /* |
@@ -767,9 +799,9 @@ exp_get_fsid_key(svc_client *clp, int fsid) | |||
767 | { | 799 | { |
768 | u32 fsidv[2]; | 800 | u32 fsidv[2]; |
769 | 801 | ||
770 | mk_fsid_v1(fsidv, fsid); | 802 | mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL); |
771 | 803 | ||
772 | return exp_find_key(clp, 1, fsidv, NULL); | 804 | return exp_find_key(clp, FSID_NUM, fsidv, NULL); |
773 | } | 805 | } |
774 | 806 | ||
775 | svc_export * | 807 | svc_export * |
@@ -883,8 +915,8 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) | |||
883 | if ((exp->ex_flags & NFSEXP_FSID) == 0) | 915 | if ((exp->ex_flags & NFSEXP_FSID) == 0) |
884 | return 0; | 916 | return 0; |
885 | 917 | ||
886 | mk_fsid_v1(fsid, exp->ex_fsid); | 918 | mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL); |
887 | return exp_set_key(clp, 1, fsid, exp); | 919 | return exp_set_key(clp, FSID_NUM, fsid, exp); |
888 | } | 920 | } |
889 | 921 | ||
890 | static int exp_hash(struct auth_domain *clp, struct svc_export *exp) | 922 | static int exp_hash(struct auth_domain *clp, struct svc_export *exp) |
@@ -894,11 +926,11 @@ static int exp_hash(struct auth_domain *clp, struct svc_export *exp) | |||
894 | dev_t dev = inode->i_sb->s_dev; | 926 | dev_t dev = inode->i_sb->s_dev; |
895 | 927 | ||
896 | if (old_valid_dev(dev)) { | 928 | if (old_valid_dev(dev)) { |
897 | mk_fsid_v0(fsid, dev, inode->i_ino); | 929 | mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL); |
898 | return exp_set_key(clp, 0, fsid, exp); | 930 | return exp_set_key(clp, FSID_DEV, fsid, exp); |
899 | } | 931 | } |
900 | mk_fsid_v3(fsid, dev, inode->i_ino); | 932 | mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL); |
901 | return exp_set_key(clp, 3, fsid, exp); | 933 | return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp); |
902 | } | 934 | } |
903 | 935 | ||
904 | static void exp_unhash(struct svc_export *exp) | 936 | static void exp_unhash(struct svc_export *exp) |
@@ -977,7 +1009,7 @@ exp_export(struct nfsctl_export *nxp) | |||
977 | goto finish; | 1009 | goto finish; |
978 | } | 1010 | } |
979 | 1011 | ||
980 | err = check_export(nd.dentry->d_inode, nxp->ex_flags); | 1012 | err = check_export(nd.dentry->d_inode, nxp->ex_flags, NULL); |
981 | if (err) goto finish; | 1013 | if (err) goto finish; |
982 | 1014 | ||
983 | err = -ENOMEM; | 1015 | err = -ENOMEM; |
@@ -1170,9 +1202,9 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |||
1170 | __be32 rv; | 1202 | __be32 rv; |
1171 | u32 fsidv[2]; | 1203 | u32 fsidv[2]; |
1172 | 1204 | ||
1173 | mk_fsid_v1(fsidv, 0); | 1205 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); |
1174 | 1206 | ||
1175 | exp = exp_find(clp, 1, fsidv, creq); | 1207 | exp = exp_find(clp, FSID_NUM, fsidv, creq); |
1176 | if (IS_ERR(exp)) | 1208 | if (IS_ERR(exp)) |
1177 | return nfserrno(PTR_ERR(exp)); | 1209 | return nfserrno(PTR_ERR(exp)); |
1178 | if (exp == NULL) | 1210 | if (exp == NULL) |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index e695660921ec..6f677988c71d 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -149,6 +149,27 @@ decode_sattr3(__be32 *p, struct iattr *iap) | |||
149 | return p; | 149 | return p; |
150 | } | 150 | } |
151 | 151 | ||
152 | static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) | ||
153 | { | ||
154 | u64 f; | ||
155 | switch(fsid_source(fhp)) { | ||
156 | default: | ||
157 | case FSIDSOURCE_DEV: | ||
158 | p = xdr_encode_hyper(p, (u64)huge_encode_dev | ||
159 | (fhp->fh_dentry->d_inode->i_sb->s_dev)); | ||
160 | break; | ||
161 | case FSIDSOURCE_FSID: | ||
162 | p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); | ||
163 | break; | ||
164 | case FSIDSOURCE_UUID: | ||
165 | f = ((u64*)fhp->fh_export->ex_uuid)[0]; | ||
166 | f ^= ((u64*)fhp->fh_export->ex_uuid)[1]; | ||
167 | p = xdr_encode_hyper(p, f); | ||
168 | break; | ||
169 | } | ||
170 | return p; | ||
171 | } | ||
172 | |||
152 | static __be32 * | 173 | static __be32 * |
153 | encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, | 174 | encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, |
154 | struct kstat *stat) | 175 | struct kstat *stat) |
@@ -169,10 +190,7 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, | |||
169 | p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); | 190 | p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); |
170 | *p++ = htonl((u32) MAJOR(stat->rdev)); | 191 | *p++ = htonl((u32) MAJOR(stat->rdev)); |
171 | *p++ = htonl((u32) MINOR(stat->rdev)); | 192 | *p++ = htonl((u32) MINOR(stat->rdev)); |
172 | if (is_fsid(fhp, rqstp->rq_reffh)) | 193 | p = encode_fsid(p, fhp); |
173 | p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); | ||
174 | else | ||
175 | p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev)); | ||
176 | p = xdr_encode_hyper(p, (u64) stat->ino); | 194 | p = xdr_encode_hyper(p, (u64) stat->ino); |
177 | p = encode_time3(p, &stat->atime); | 195 | p = encode_time3(p, &stat->atime); |
178 | lease_get_mtime(dentry->d_inode, &time); | 196 | lease_get_mtime(dentry->d_inode, &time); |
@@ -203,10 +221,7 @@ encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) | |||
203 | p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); | 221 | p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); |
204 | *p++ = fhp->fh_post_rdev[0]; | 222 | *p++ = fhp->fh_post_rdev[0]; |
205 | *p++ = fhp->fh_post_rdev[1]; | 223 | *p++ = fhp->fh_post_rdev[1]; |
206 | if (is_fsid(fhp, rqstp->rq_reffh)) | 224 | p = encode_fsid(p, fhp); |
207 | p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); | ||
208 | else | ||
209 | p = xdr_encode_hyper(p, (u64)huge_encode_dev(inode->i_sb->s_dev)); | ||
210 | p = xdr_encode_hyper(p, (u64) inode->i_ino); | 225 | p = xdr_encode_hyper(p, (u64) inode->i_ino); |
211 | p = encode_time3(p, &fhp->fh_post_atime); | 226 | p = encode_time3(p, &fhp->fh_post_atime); |
212 | p = encode_time3(p, &fhp->fh_post_mtime); | 227 | p = encode_time3(p, &fhp->fh_post_mtime); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 18aa9440df14..0efba557fb55 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1563,14 +1563,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1563 | if (exp->ex_fslocs.migrated) { | 1563 | if (exp->ex_fslocs.migrated) { |
1564 | WRITE64(NFS4_REFERRAL_FSID_MAJOR); | 1564 | WRITE64(NFS4_REFERRAL_FSID_MAJOR); |
1565 | WRITE64(NFS4_REFERRAL_FSID_MINOR); | 1565 | WRITE64(NFS4_REFERRAL_FSID_MINOR); |
1566 | } else if (is_fsid(fhp, rqstp->rq_reffh)) { | 1566 | } else switch(fsid_source(fhp)) { |
1567 | case FSIDSOURCE_FSID: | ||
1567 | WRITE64((u64)exp->ex_fsid); | 1568 | WRITE64((u64)exp->ex_fsid); |
1568 | WRITE64((u64)0); | 1569 | WRITE64((u64)0); |
1569 | } else { | 1570 | break; |
1571 | case FSIDSOURCE_DEV: | ||
1570 | WRITE32(0); | 1572 | WRITE32(0); |
1571 | WRITE32(MAJOR(stat.dev)); | 1573 | WRITE32(MAJOR(stat.dev)); |
1572 | WRITE32(0); | 1574 | WRITE32(0); |
1573 | WRITE32(MINOR(stat.dev)); | 1575 | WRITE32(MINOR(stat.dev)); |
1576 | break; | ||
1577 | case FSIDSOURCE_UUID: | ||
1578 | WRITEMEM(exp->ex_uuid, 16); | ||
1579 | break; | ||
1574 | } | 1580 | } |
1575 | } | 1581 | } |
1576 | if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { | 1582 | if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) { |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 12c5e7421374..286bc4d356f4 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -119,9 +119,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
119 | 119 | ||
120 | dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); | 120 | dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); |
121 | 121 | ||
122 | /* keep this filehandle for possible reference when encoding attributes */ | ||
123 | rqstp->rq_reffh = fh; | ||
124 | |||
125 | if (!fhp->fh_dentry) { | 122 | if (!fhp->fh_dentry) { |
126 | __u32 *datap=NULL; | 123 | __u32 *datap=NULL; |
127 | __u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */ | 124 | __u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */ |
@@ -146,10 +143,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
146 | } | 143 | } |
147 | len = key_len(fh->fh_fsid_type) / 4; | 144 | len = key_len(fh->fh_fsid_type) / 4; |
148 | if (len == 0) goto out; | 145 | if (len == 0) goto out; |
149 | if (fh->fh_fsid_type == 2) { | 146 | if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { |
150 | /* deprecated, convert to type 3 */ | 147 | /* deprecated, convert to type 3 */ |
151 | len = 3; | 148 | len = key_len(FSID_ENCODE_DEV)/4; |
152 | fh->fh_fsid_type = 3; | 149 | fh->fh_fsid_type = FSID_ENCODE_DEV; |
153 | fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); | 150 | fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); |
154 | fh->fh_fsid[1] = fh->fh_fsid[2]; | 151 | fh->fh_fsid[1] = fh->fh_fsid[2]; |
155 | } | 152 | } |
@@ -164,8 +161,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
164 | /* assume old filehandle format */ | 161 | /* assume old filehandle format */ |
165 | xdev = old_decode_dev(fh->ofh_xdev); | 162 | xdev = old_decode_dev(fh->ofh_xdev); |
166 | xino = u32_to_ino_t(fh->ofh_xino); | 163 | xino = u32_to_ino_t(fh->ofh_xino); |
167 | mk_fsid_v0(tfh, xdev, xino); | 164 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); |
168 | exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle); | 165 | exp = exp_find(rqstp->rq_client, FSID_DEV, tfh, |
166 | &rqstp->rq_chandle); | ||
169 | } | 167 | } |
170 | 168 | ||
171 | if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN | 169 | if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN |
@@ -334,6 +332,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
334 | struct dentry *parent = dentry->d_parent; | 332 | struct dentry *parent = dentry->d_parent; |
335 | __u32 *datap; | 333 | __u32 *datap; |
336 | dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev; | 334 | dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev; |
335 | int root_export = (exp->ex_dentry == exp->ex_dentry->d_sb->s_root); | ||
337 | 336 | ||
338 | dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", | 337 | dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", |
339 | MAJOR(ex_dev), MINOR(ex_dev), | 338 | MAJOR(ex_dev), MINOR(ex_dev), |
@@ -348,19 +347,31 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
348 | if (ref_fh && ref_fh->fh_export == exp) { | 347 | if (ref_fh && ref_fh->fh_export == exp) { |
349 | version = ref_fh->fh_handle.fh_version; | 348 | version = ref_fh->fh_handle.fh_version; |
350 | if (version == 0xca) | 349 | if (version == 0xca) |
351 | fsid_type = 0; | 350 | fsid_type = FSID_DEV; |
352 | else | 351 | else |
353 | fsid_type = ref_fh->fh_handle.fh_fsid_type; | 352 | fsid_type = ref_fh->fh_handle.fh_fsid_type; |
354 | /* We know this version/type works for this export | 353 | /* We know this version/type works for this export |
355 | * so there is no need for further checks. | 354 | * so there is no need for further checks. |
356 | */ | 355 | */ |
356 | } else if (exp->ex_uuid) { | ||
357 | if (fhp->fh_maxsize >= 64) { | ||
358 | if (root_export) | ||
359 | fsid_type = FSID_UUID16; | ||
360 | else | ||
361 | fsid_type = FSID_UUID16_INUM; | ||
362 | } else { | ||
363 | if (root_export) | ||
364 | fsid_type = FSID_UUID8; | ||
365 | else | ||
366 | fsid_type = FSID_UUID4_INUM; | ||
367 | } | ||
357 | } else if (exp->ex_flags & NFSEXP_FSID) | 368 | } else if (exp->ex_flags & NFSEXP_FSID) |
358 | fsid_type = 1; | 369 | fsid_type = FSID_NUM; |
359 | else if (!old_valid_dev(ex_dev)) | 370 | else if (!old_valid_dev(ex_dev)) |
360 | /* for newer device numbers, we must use a newer fsid format */ | 371 | /* for newer device numbers, we must use a newer fsid format */ |
361 | fsid_type = 3; | 372 | fsid_type = FSID_ENCODE_DEV; |
362 | else | 373 | else |
363 | fsid_type = 0; | 374 | fsid_type = FSID_DEV; |
364 | 375 | ||
365 | if (ref_fh == fhp) | 376 | if (ref_fh == fhp) |
366 | fh_put(ref_fh); | 377 | fh_put(ref_fh); |
@@ -396,36 +407,10 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
396 | fhp->fh_handle.fh_auth_type = 0; | 407 | fhp->fh_handle.fh_auth_type = 0; |
397 | datap = fhp->fh_handle.fh_auth+0; | 408 | datap = fhp->fh_handle.fh_auth+0; |
398 | fhp->fh_handle.fh_fsid_type = fsid_type; | 409 | fhp->fh_handle.fh_fsid_type = fsid_type; |
399 | switch (fsid_type) { | 410 | mk_fsid(fsid_type, datap, ex_dev, |
400 | case 0: | 411 | exp->ex_dentry->d_inode->i_ino, |
401 | /* | 412 | exp->ex_fsid, exp->ex_uuid); |
402 | * fsid_type 0: | 413 | |
403 | * 2byte major, 2byte minor, 4byte inode | ||
404 | */ | ||
405 | mk_fsid_v0(datap, ex_dev, | ||
406 | exp->ex_dentry->d_inode->i_ino); | ||
407 | break; | ||
408 | case 1: | ||
409 | /* fsid_type 1 == 4 bytes filesystem id */ | ||
410 | mk_fsid_v1(datap, exp->ex_fsid); | ||
411 | break; | ||
412 | case 2: | ||
413 | /* | ||
414 | * fsid_type 2: | ||
415 | * 4byte major, 4byte minor, 4byte inode | ||
416 | */ | ||
417 | mk_fsid_v2(datap, ex_dev, | ||
418 | exp->ex_dentry->d_inode->i_ino); | ||
419 | break; | ||
420 | case 3: | ||
421 | /* | ||
422 | * fsid_type 3: | ||
423 | * 4byte devicenumber, 4byte inode | ||
424 | */ | ||
425 | mk_fsid_v3(datap, ex_dev, | ||
426 | exp->ex_dentry->d_inode->i_ino); | ||
427 | break; | ||
428 | } | ||
429 | len = key_len(fsid_type); | 414 | len = key_len(fsid_type); |
430 | datap += len/4; | 415 | datap += len/4; |
431 | fhp->fh_handle.fh_size = 4 + len; | 416 | fhp->fh_handle.fh_size = 4 + len; |
@@ -530,3 +515,22 @@ char * SVCFH_fmt(struct svc_fh *fhp) | |||
530 | fh->fh_base.fh_pad[5]); | 515 | fh->fh_base.fh_pad[5]); |
531 | return buf; | 516 | return buf; |
532 | } | 517 | } |
518 | |||
519 | enum fsid_source fsid_source(struct svc_fh *fhp) | ||
520 | { | ||
521 | if (fhp->fh_handle.fh_version != 1) | ||
522 | return FSIDSOURCE_DEV; | ||
523 | switch(fhp->fh_handle.fh_fsid_type) { | ||
524 | case FSID_DEV: | ||
525 | case FSID_ENCODE_DEV: | ||
526 | case FSID_MAJOR_MINOR: | ||
527 | return FSIDSOURCE_DEV; | ||
528 | case FSID_NUM: | ||
529 | return FSIDSOURCE_FSID; | ||
530 | default: | ||
531 | if (fhp->fh_export->ex_flags & NFSEXP_FSID) | ||
532 | return FSIDSOURCE_FSID; | ||
533 | else | ||
534 | return FSIDSOURCE_UUID; | ||
535 | } | ||
536 | } | ||
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 6555c50d9006..0c24b9e24fe8 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -153,6 +153,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, | |||
153 | struct dentry *dentry = fhp->fh_dentry; | 153 | struct dentry *dentry = fhp->fh_dentry; |
154 | int type; | 154 | int type; |
155 | struct timespec time; | 155 | struct timespec time; |
156 | u32 f; | ||
156 | 157 | ||
157 | type = (stat->mode & S_IFMT); | 158 | type = (stat->mode & S_IFMT); |
158 | 159 | ||
@@ -173,10 +174,22 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, | |||
173 | else | 174 | else |
174 | *p++ = htonl(0xffffffff); | 175 | *p++ = htonl(0xffffffff); |
175 | *p++ = htonl((u32) stat->blocks); | 176 | *p++ = htonl((u32) stat->blocks); |
176 | if (is_fsid(fhp, rqstp->rq_reffh)) | 177 | switch (fsid_source(fhp)) { |
177 | *p++ = htonl((u32) fhp->fh_export->ex_fsid); | 178 | default: |
178 | else | 179 | case FSIDSOURCE_DEV: |
179 | *p++ = htonl(new_encode_dev(stat->dev)); | 180 | *p++ = htonl(new_encode_dev(stat->dev)); |
181 | break; | ||
182 | case FSIDSOURCE_FSID: | ||
183 | *p++ = htonl((u32) fhp->fh_export->ex_fsid); | ||
184 | break; | ||
185 | case FSIDSOURCE_UUID: | ||
186 | f = ((u32*)fhp->fh_export->ex_uuid)[0]; | ||
187 | f ^= ((u32*)fhp->fh_export->ex_uuid)[1]; | ||
188 | f ^= ((u32*)fhp->fh_export->ex_uuid)[2]; | ||
189 | f ^= ((u32*)fhp->fh_export->ex_uuid)[3]; | ||
190 | *p++ = htonl(f); | ||
191 | break; | ||
192 | } | ||
180 | *p++ = htonl((u32) stat->ino); | 193 | *p++ = htonl((u32) stat->ino); |
181 | *p++ = htonl((u32) stat->atime.tv_sec); | 194 | *p++ = htonl((u32) stat->atime.tv_sec); |
182 | *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0); | 195 | *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0); |
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 045e38cdbe64..9f62d6182d32 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h | |||
@@ -74,19 +74,20 @@ struct svc_export { | |||
74 | uid_t ex_anon_uid; | 74 | uid_t ex_anon_uid; |
75 | gid_t ex_anon_gid; | 75 | gid_t ex_anon_gid; |
76 | int ex_fsid; | 76 | int ex_fsid; |
77 | unsigned char * ex_uuid; /* 16 byte fsid */ | ||
77 | struct nfsd4_fs_locations ex_fslocs; | 78 | struct nfsd4_fs_locations ex_fslocs; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | /* an "export key" (expkey) maps a filehandlefragement to an | 81 | /* an "export key" (expkey) maps a filehandlefragement to an |
81 | * svc_export for a given client. There can be two per export, one | 82 | * svc_export for a given client. There can be several per export, |
82 | * for type 0 (dev/ino), one for type 1 (fsid) | 83 | * for the different fsid types. |
83 | */ | 84 | */ |
84 | struct svc_expkey { | 85 | struct svc_expkey { |
85 | struct cache_head h; | 86 | struct cache_head h; |
86 | 87 | ||
87 | struct auth_domain * ek_client; | 88 | struct auth_domain * ek_client; |
88 | int ek_fsidtype; | 89 | int ek_fsidtype; |
89 | u32 ek_fsid[3]; | 90 | u32 ek_fsid[6]; |
90 | 91 | ||
91 | struct vfsmount * ek_mnt; | 92 | struct vfsmount * ek_mnt; |
92 | struct dentry * ek_dentry; | 93 | struct dentry * ek_dentry; |
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 4b7c4b568f6d..72feac581aa3 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h | |||
@@ -254,18 +254,6 @@ void nfsd_lockd_shutdown(void); | |||
254 | */ | 254 | */ |
255 | extern struct timeval nfssvc_boot; | 255 | extern struct timeval nfssvc_boot; |
256 | 256 | ||
257 | static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh) | ||
258 | { | ||
259 | if (fh->fh_export->ex_flags & NFSEXP_FSID) { | ||
260 | struct vfsmount *mnt = fh->fh_export->ex_mnt; | ||
261 | if (!old_valid_dev(mnt->mnt_sb->s_dev) || | ||
262 | (reffh->fh_version == 1 && reffh->fh_fsid_type == 1)) | ||
263 | return 1; | ||
264 | } | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | |||
269 | #ifdef CONFIG_NFSD_V4 | 257 | #ifdef CONFIG_NFSD_V4 |
270 | 258 | ||
271 | /* before processing a COMPOUND operation, we have to check that there | 259 | /* before processing a COMPOUND operation, we have to check that there |
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index d9c6c382165d..11e568ee0eeb 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h | |||
@@ -165,38 +165,91 @@ typedef struct svc_fh { | |||
165 | 165 | ||
166 | } svc_fh; | 166 | } svc_fh; |
167 | 167 | ||
168 | static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino) | 168 | enum nfsd_fsid { |
169 | { | 169 | FSID_DEV = 0, |
170 | fsidv[0] = htonl((MAJOR(dev)<<16) | | 170 | FSID_NUM, |
171 | MINOR(dev)); | 171 | FSID_MAJOR_MINOR, |
172 | fsidv[1] = ino_t_to_u32(ino); | 172 | FSID_ENCODE_DEV, |
173 | } | 173 | FSID_UUID4_INUM, |
174 | FSID_UUID8, | ||
175 | FSID_UUID16, | ||
176 | FSID_UUID16_INUM, | ||
177 | }; | ||
174 | 178 | ||
175 | static inline void mk_fsid_v1(u32 *fsidv, u32 fsid) | 179 | enum fsid_source { |
176 | { | 180 | FSIDSOURCE_DEV, |
177 | fsidv[0] = fsid; | 181 | FSIDSOURCE_FSID, |
178 | } | 182 | FSIDSOURCE_UUID, |
183 | }; | ||
184 | extern enum fsid_source fsid_source(struct svc_fh *fhp); | ||
179 | 185 | ||
180 | static inline void mk_fsid_v2(u32 *fsidv, dev_t dev, ino_t ino) | ||
181 | { | ||
182 | fsidv[0] = htonl(MAJOR(dev)); | ||
183 | fsidv[1] = htonl(MINOR(dev)); | ||
184 | fsidv[2] = ino_t_to_u32(ino); | ||
185 | } | ||
186 | 186 | ||
187 | static inline void mk_fsid_v3(u32 *fsidv, dev_t dev, ino_t ino) | 187 | /* This might look a little large to "inline" but in all calls except |
188 | * one, 'vers' is constant so moste of the function disappears. | ||
189 | */ | ||
190 | static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino, | ||
191 | u32 fsid, unsigned char *uuid) | ||
188 | { | 192 | { |
189 | fsidv[0] = new_encode_dev(dev); | 193 | u32 *up; |
190 | fsidv[1] = ino_t_to_u32(ino); | 194 | switch(vers) { |
195 | case FSID_DEV: | ||
196 | fsidv[0] = htonl((MAJOR(dev)<<16) | | ||
197 | MINOR(dev)); | ||
198 | fsidv[1] = ino_t_to_u32(ino); | ||
199 | break; | ||
200 | case FSID_NUM: | ||
201 | fsidv[0] = fsid; | ||
202 | break; | ||
203 | case FSID_MAJOR_MINOR: | ||
204 | fsidv[0] = htonl(MAJOR(dev)); | ||
205 | fsidv[1] = htonl(MINOR(dev)); | ||
206 | fsidv[2] = ino_t_to_u32(ino); | ||
207 | break; | ||
208 | |||
209 | case FSID_ENCODE_DEV: | ||
210 | fsidv[0] = new_encode_dev(dev); | ||
211 | fsidv[1] = ino_t_to_u32(ino); | ||
212 | break; | ||
213 | |||
214 | case FSID_UUID4_INUM: | ||
215 | /* 4 byte fsid and inode number */ | ||
216 | up = (u32*)uuid; | ||
217 | fsidv[0] = ino_t_to_u32(ino); | ||
218 | fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3]; | ||
219 | break; | ||
220 | |||
221 | case FSID_UUID8: | ||
222 | /* 8 byte fsid */ | ||
223 | up = (u32*)uuid; | ||
224 | fsidv[0] = up[0] ^ up[2]; | ||
225 | fsidv[1] = up[1] ^ up[3]; | ||
226 | break; | ||
227 | |||
228 | case FSID_UUID16: | ||
229 | /* 16 byte fsid - NFSv3+ only */ | ||
230 | memcpy(fsidv, uuid, 16); | ||
231 | break; | ||
232 | |||
233 | case FSID_UUID16_INUM: | ||
234 | /* 8 byte inode and 16 byte fsid */ | ||
235 | *(u64*)fsidv = (u64)ino; | ||
236 | memcpy(fsidv+2, uuid, 16); | ||
237 | break; | ||
238 | default: BUG(); | ||
239 | } | ||
191 | } | 240 | } |
192 | 241 | ||
193 | static inline int key_len(int type) | 242 | static inline int key_len(int type) |
194 | { | 243 | { |
195 | switch(type) { | 244 | switch(type) { |
196 | case 0: return 8; | 245 | case FSID_DEV: return 8; |
197 | case 1: return 4; | 246 | case FSID_NUM: return 4; |
198 | case 2: return 12; | 247 | case FSID_MAJOR_MINOR: return 12; |
199 | case 3: return 8; | 248 | case FSID_ENCODE_DEV: return 8; |
249 | case FSID_UUID4_INUM: return 8; | ||
250 | case FSID_UUID8: return 8; | ||
251 | case FSID_UUID16: return 16; | ||
252 | case FSID_UUID16_INUM: return 24; | ||
200 | default: return 0; | 253 | default: return 0; |
201 | } | 254 | } |
202 | } | 255 | } |