aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2007-10-21 19:42:03 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-22 11:13:19 -0400
commit6e91ea2bb0b6a3ddf6d4faeb54a9c20d4e20bc42 (patch)
tree3f20a72d6c36620d071c485206b39e2e32546fc6
parent00bf4098beb15ca174b54f3af1f1e1908d7d18a3 (diff)
exportfs: add fid type
This patchset is a medium scale rewrite of the export operations interface. The goal is to make the interface less complex, and easier to understand from the filesystem side, aswell as preparing generic support for exporting of 64bit inode numbers. This touches all nfs exporting filesystems, and I've done testing on all of the filesystems I have here locally (xfs, ext2, ext3, reiserfs, jfs) This patch: Add a structured fid type so that we don't have to pass an array of u32 values around everywhere. It's a union of possible layouts. As a start there's only the u32 array and the traditional 32bit inode format, but there will be more in one of my next patchset when I start to document the various filehandle formats we have in lowlevel filesystems better. Also add an enum that gives the various filehandle types human- readable names. Note: Some people might think the struct containing an anonymous union is ugly, but I didn't want to pass around a raw union type. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: Neil Brown <neilb@suse.de> Cc: "J. Bruce Fields" <bfields@fieldses.org> Cc: <linux-ext4@vger.kernel.org> Cc: Dave Kleikamp <shaggy@austin.ibm.com> Cc: Anton Altaparmakov <aia21@cantab.net> Cc: David Chinner <dgc@sgi.com> Cc: Timothy Shimmin <tes@sgi.com> Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Cc: Hugh Dickins <hugh@veritas.com> Cc: Chris Mason <mason@suse.com> Cc: Jeff Mahoney <jeffm@suse.com> Cc: "Vladimir V. Saveliev" <vs@namesys.com> Cc: Steven Whitehouse <swhiteho@redhat.com> Cc: Mark Fasheh <mark.fasheh@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/exportfs/expfs.c36
-rw-r--r--fs/nfsd/nfsfh.c67
-rw-r--r--include/linux/exportfs.h44
3 files changed, 90 insertions, 57 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 8adb32a9387a..813011aad700 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -434,29 +434,29 @@ out:
434 * can be used to check that it is still valid. It places them in the 434 * can be used to check that it is still valid. It places them in the
435 * filehandle fragment where export_decode_fh expects to find them. 435 * filehandle fragment where export_decode_fh expects to find them.
436 */ 436 */
437static int export_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, 437static int export_encode_fh(struct dentry *dentry, struct fid *fid,
438 int connectable) 438 int *max_len, int connectable)
439{ 439{
440 struct inode * inode = dentry->d_inode; 440 struct inode * inode = dentry->d_inode;
441 int len = *max_len; 441 int len = *max_len;
442 int type = 1; 442 int type = FILEID_INO32_GEN;
443 443
444 if (len < 2 || (connectable && len < 4)) 444 if (len < 2 || (connectable && len < 4))
445 return 255; 445 return 255;
446 446
447 len = 2; 447 len = 2;
448 fh[0] = inode->i_ino; 448 fid->i32.ino = inode->i_ino;
449 fh[1] = inode->i_generation; 449 fid->i32.gen = inode->i_generation;
450 if (connectable && !S_ISDIR(inode->i_mode)) { 450 if (connectable && !S_ISDIR(inode->i_mode)) {
451 struct inode *parent; 451 struct inode *parent;
452 452
453 spin_lock(&dentry->d_lock); 453 spin_lock(&dentry->d_lock);
454 parent = dentry->d_parent->d_inode; 454 parent = dentry->d_parent->d_inode;
455 fh[2] = parent->i_ino; 455 fid->i32.parent_ino = parent->i_ino;
456 fh[3] = parent->i_generation; 456 fid->i32.parent_gen = parent->i_generation;
457 spin_unlock(&dentry->d_lock); 457 spin_unlock(&dentry->d_lock);
458 len = 4; 458 len = 4;
459 type = 2; 459 type = FILEID_INO32_GEN_PARENT;
460 } 460 }
461 *max_len = len; 461 *max_len = len;
462 return type; 462 return type;
@@ -494,34 +494,34 @@ static struct dentry *export_decode_fh(struct super_block *sb, __u32 *fh, int fh
494 acceptable, context); 494 acceptable, context);
495} 495}
496 496
497int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, 497int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
498 int connectable) 498 int connectable)
499{ 499{
500 struct export_operations *nop = dentry->d_sb->s_export_op; 500 struct export_operations *nop = dentry->d_sb->s_export_op;
501 int error; 501 int error;
502 502
503 if (nop->encode_fh) 503 if (nop->encode_fh)
504 error = nop->encode_fh(dentry, fh, max_len, connectable); 504 error = nop->encode_fh(dentry, fid->raw, max_len, connectable);
505 else 505 else
506 error = export_encode_fh(dentry, fh, max_len, connectable); 506 error = export_encode_fh(dentry, fid, max_len, connectable);
507 507
508 return error; 508 return error;
509} 509}
510EXPORT_SYMBOL_GPL(exportfs_encode_fh); 510EXPORT_SYMBOL_GPL(exportfs_encode_fh);
511 511
512struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len, 512struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
513 int fileid_type, int (*acceptable)(void *, struct dentry *), 513 int fh_len, int fileid_type,
514 void *context) 514 int (*acceptable)(void *, struct dentry *), void *context)
515{ 515{
516 struct export_operations *nop = mnt->mnt_sb->s_export_op; 516 struct export_operations *nop = mnt->mnt_sb->s_export_op;
517 struct dentry *result; 517 struct dentry *result;
518 518
519 if (nop->decode_fh) { 519 if (nop->decode_fh) {
520 result = nop->decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, 520 result = nop->decode_fh(mnt->mnt_sb, fid->raw, fh_len,
521 acceptable, context); 521 fileid_type, acceptable, context);
522 } else { 522 } else {
523 result = export_decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, 523 result = export_decode_fh(mnt->mnt_sb, fid->raw, fh_len,
524 acceptable, context); 524 fileid_type, acceptable, context);
525 } 525 }
526 526
527 return result; 527 return result;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 7011d62acfc8..4f712e970584 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -115,8 +115,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
115 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); 115 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
116 116
117 if (!fhp->fh_dentry) { 117 if (!fhp->fh_dentry) {
118 __u32 *datap=NULL; 118 struct fid *fid = NULL, sfid;
119 __u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */
120 int fileid_type; 119 int fileid_type;
121 int data_left = fh->fh_size/4; 120 int data_left = fh->fh_size/4;
122 121
@@ -128,7 +127,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
128 127
129 if (fh->fh_version == 1) { 128 if (fh->fh_version == 1) {
130 int len; 129 int len;
131 datap = fh->fh_auth;
132 if (--data_left<0) goto out; 130 if (--data_left<0) goto out;
133 switch (fh->fh_auth_type) { 131 switch (fh->fh_auth_type) {
134 case 0: break; 132 case 0: break;
@@ -144,9 +142,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
144 fh->fh_fsid[1] = fh->fh_fsid[2]; 142 fh->fh_fsid[1] = fh->fh_fsid[2];
145 } 143 }
146 if ((data_left -= len)<0) goto out; 144 if ((data_left -= len)<0) goto out;
147 exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap); 145 exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
148 datap += len; 146 fh->fh_auth);
147 fid = (struct fid *)(fh->fh_auth + len);
149 } else { 148 } else {
149 __u32 tfh[2];
150 dev_t xdev; 150 dev_t xdev;
151 ino_t xino; 151 ino_t xino;
152 if (fh->fh_size != NFS_FHSIZE) 152 if (fh->fh_size != NFS_FHSIZE)
@@ -190,22 +190,22 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
190 error = nfserr_badhandle; 190 error = nfserr_badhandle;
191 191
192 if (fh->fh_version != 1) { 192 if (fh->fh_version != 1) {
193 tfh[0] = fh->ofh_ino; 193 sfid.i32.ino = fh->ofh_ino;
194 tfh[1] = fh->ofh_generation; 194 sfid.i32.gen = fh->ofh_generation;
195 tfh[2] = fh->ofh_dirino; 195 sfid.i32.parent_ino = fh->ofh_dirino;
196 datap = tfh; 196 fid = &sfid;
197 data_left = 3; 197 data_left = 3;
198 if (fh->ofh_dirino == 0) 198 if (fh->ofh_dirino == 0)
199 fileid_type = 1; 199 fileid_type = FILEID_INO32_GEN;
200 else 200 else
201 fileid_type = 2; 201 fileid_type = FILEID_INO32_GEN_PARENT;
202 } else 202 } else
203 fileid_type = fh->fh_fileid_type; 203 fileid_type = fh->fh_fileid_type;
204 204
205 if (fileid_type == 0) 205 if (fileid_type == FILEID_ROOT)
206 dentry = dget(exp->ex_dentry); 206 dentry = dget(exp->ex_dentry);
207 else { 207 else {
208 dentry = exportfs_decode_fh(exp->ex_mnt, datap, 208 dentry = exportfs_decode_fh(exp->ex_mnt, fid,
209 data_left, fileid_type, 209 data_left, fileid_type,
210 nfsd_acceptable, exp); 210 nfsd_acceptable, exp);
211 } 211 }
@@ -286,16 +286,21 @@ out:
286 * an inode. In this case a call to fh_update should be made 286 * an inode. In this case a call to fh_update should be made
287 * before the fh goes out on the wire ... 287 * before the fh goes out on the wire ...
288 */ 288 */
289static inline int _fh_update(struct dentry *dentry, struct svc_export *exp, 289static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
290 __u32 *datap, int *maxsize) 290 struct dentry *dentry)
291{ 291{
292 if (dentry == exp->ex_dentry) { 292 if (dentry != exp->ex_dentry) {
293 *maxsize = 0; 293 struct fid *fid = (struct fid *)
294 return 0; 294 (fhp->fh_handle.fh_auth + fhp->fh_handle.fh_size/4 - 1);
295 } 295 int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
296 int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
296 297
297 return exportfs_encode_fh(dentry, datap, maxsize, 298 fhp->fh_handle.fh_fileid_type =
298 !(exp->ex_flags & NFSEXP_NOSUBTREECHECK)); 299 exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck);
300 fhp->fh_handle.fh_size += maxsize * 4;
301 } else {
302 fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
303 }
299} 304}
300 305
301/* 306/*
@@ -457,12 +462,8 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
457 datap += len/4; 462 datap += len/4;
458 fhp->fh_handle.fh_size = 4 + len; 463 fhp->fh_handle.fh_size = 4 + len;
459 464
460 if (inode) { 465 if (inode)
461 int size = (fhp->fh_maxsize-len-4)/4; 466 _fh_update(fhp, exp, dentry);
462 fhp->fh_handle.fh_fileid_type =
463 _fh_update(dentry, exp, datap, &size);
464 fhp->fh_handle.fh_size += size*4;
465 }
466 if (fhp->fh_handle.fh_fileid_type == 255) 467 if (fhp->fh_handle.fh_fileid_type == 255)
467 return nfserr_opnotsupp; 468 return nfserr_opnotsupp;
468 } 469 }
@@ -479,7 +480,6 @@ __be32
479fh_update(struct svc_fh *fhp) 480fh_update(struct svc_fh *fhp)
480{ 481{
481 struct dentry *dentry; 482 struct dentry *dentry;
482 __u32 *datap;
483 483
484 if (!fhp->fh_dentry) 484 if (!fhp->fh_dentry)
485 goto out_bad; 485 goto out_bad;
@@ -490,15 +490,10 @@ fh_update(struct svc_fh *fhp)
490 if (fhp->fh_handle.fh_version != 1) { 490 if (fhp->fh_handle.fh_version != 1) {
491 _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); 491 _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
492 } else { 492 } else {
493 int size; 493 if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
494 if (fhp->fh_handle.fh_fileid_type != 0)
495 goto out; 494 goto out;
496 datap = fhp->fh_handle.fh_auth+ 495
497 fhp->fh_handle.fh_size/4 -1; 496 _fh_update(fhp, fhp->fh_export, dentry);
498 size = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
499 fhp->fh_handle.fh_fileid_type =
500 _fh_update(dentry, fhp->fh_export, datap, &size);
501 fhp->fh_handle.fh_size += size*4;
502 if (fhp->fh_handle.fh_fileid_type == 255) 497 if (fhp->fh_handle.fh_fileid_type == 255)
503 return nfserr_opnotsupp; 498 return nfserr_opnotsupp;
504 } 499 }
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 8872fe8392d6..06178a1336ff 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -7,6 +7,44 @@ struct dentry;
7struct super_block; 7struct super_block;
8struct vfsmount; 8struct vfsmount;
9 9
10/*
11 * The fileid_type identifies how the file within the filesystem is encoded.
12 * In theory this is freely set and parsed by the filesystem, but we try to
13 * stick to conventions so we can share some generic code and don't confuse
14 * sniffers like ethereal/wireshark.
15 *
16 * The filesystem must not use the value '0' or '0xff'.
17 */
18enum fid_type {
19 /*
20 * The root, or export point, of the filesystem.
21 * (Never actually passed down to the filesystem.
22 */
23 FILEID_ROOT = 0,
24
25 /*
26 * 32bit inode number, 32 bit generation number.
27 */
28 FILEID_INO32_GEN = 1,
29
30 /*
31 * 32bit inode number, 32 bit generation number,
32 * 32 bit parent directory inode number.
33 */
34 FILEID_INO32_GEN_PARENT = 2,
35};
36
37struct fid {
38 union {
39 struct {
40 u32 ino;
41 u32 gen;
42 u32 parent_ino;
43 u32 parent_gen;
44 } i32;
45 __u32 raw[6];
46 };
47};
10 48
11/** 49/**
12 * struct export_operations - for nfsd to communicate with file systems 50 * struct export_operations - for nfsd to communicate with file systems
@@ -117,9 +155,9 @@ extern struct dentry *find_exported_dentry(struct super_block *sb, void *obj,
117 void *parent, int (*acceptable)(void *context, struct dentry *de), 155 void *parent, int (*acceptable)(void *context, struct dentry *de),
118 void *context); 156 void *context);
119 157
120extern int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, 158extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
121 int connectable); 159 int *max_len, int connectable);
122extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, 160extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
123 int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *), 161 int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *),
124 void *context); 162 void *context);
125 163