aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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