diff options
-rw-r--r-- | fs/exportfs/expfs.c | 36 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 67 | ||||
-rw-r--r-- | include/linux/exportfs.h | 44 |
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 | */ |
437 | static int export_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, | 437 | static 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 | ||
497 | int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, | 497 | int 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 | } |
510 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); | 510 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); |
511 | 511 | ||
512 | struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len, | 512 | struct 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 | */ |
289 | static inline int _fh_update(struct dentry *dentry, struct svc_export *exp, | 289 | static 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 | |||
479 | fh_update(struct svc_fh *fhp) | 480 | fh_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; | |||
7 | struct super_block; | 7 | struct super_block; |
8 | struct vfsmount; | 8 | struct 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 | */ | ||
18 | enum 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 | |||
37 | struct 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 | ||
120 | extern int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, | 158 | extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, |
121 | int connectable); | 159 | int *max_len, int connectable); |
122 | extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, | 160 | extern 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 | ||