aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2007-02-14 03:33:12 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-14 11:09:53 -0500
commitaf6a4e280e3ff453653f39190b57b345ff0bec16 (patch)
tree4895c90613737db7354f43431ed10a55dc0c98f0
parent982aedfd091e6d9831216f8519f12242091be4fd (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.c106
-rw-r--r--fs/nfsd/nfs3xdr.c31
-rw-r--r--fs/nfsd/nfs4xdr.c10
-rw-r--r--fs/nfsd/nfsfh.c88
-rw-r--r--fs/nfsd/nfsxdr.c19
-rw-r--r--include/linux/nfsd/export.h7
-rw-r--r--include/linux/nfsd/nfsd.h12
-rw-r--r--include/linux/nfsd/nfsfh.h99
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
240static inline void expkey_update(struct cache_head *cnew, 238static 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);
364static struct svc_export *svc_export_lookup(struct svc_export *); 362static struct svc_export *svc_export_lookup(struct svc_export *);
365 363
366static int check_export(struct inode *inode, int flags) 364static 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
775svc_export * 807svc_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
890static int exp_hash(struct auth_domain *clp, struct svc_export *exp) 922static 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
904static void exp_unhash(struct svc_export *exp) 936static 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
152static __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
152static __be32 * 173static __be32 *
153encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, 174encode_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
519enum 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 */
84struct svc_expkey { 85struct 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 */
255extern struct timeval nfssvc_boot; 255extern struct timeval nfssvc_boot;
256 256
257static 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
168static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino) 168enum 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
175static inline void mk_fsid_v1(u32 *fsidv, u32 fsid) 179enum fsid_source {
176{ 180 FSIDSOURCE_DEV,
177 fsidv[0] = fsid; 181 FSIDSOURCE_FSID,
178} 182 FSIDSOURCE_UUID,
183};
184extern enum fsid_source fsid_source(struct svc_fh *fhp);
179 185
180static 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
187static 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 */
190static 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
193static inline int key_len(int type) 242static 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}