diff options
-rw-r--r-- | fs/exportfs/expfs.c | 179 | ||||
-rw-r--r-- | fs/nfsd/export.c | 8 | ||||
-rw-r--r-- | include/linux/exportfs.h | 41 |
3 files changed, 3 insertions, 225 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 99294a23cd54..e68f0279f4b0 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -13,19 +13,6 @@ static int get_name(struct dentry *dentry, char *name, | |||
13 | struct dentry *child); | 13 | struct dentry *child); |
14 | 14 | ||
15 | 15 | ||
16 | static struct dentry *exportfs_get_dentry(struct super_block *sb, void *obj) | ||
17 | { | ||
18 | struct dentry *result = ERR_PTR(-ESTALE); | ||
19 | |||
20 | if (sb->s_export_op->get_dentry) { | ||
21 | result = sb->s_export_op->get_dentry(sb, obj); | ||
22 | if (!result) | ||
23 | result = ERR_PTR(-ESTALE); | ||
24 | } | ||
25 | |||
26 | return result; | ||
27 | } | ||
28 | |||
29 | static int exportfs_get_name(struct dentry *dir, char *name, | 16 | static int exportfs_get_name(struct dentry *dir, char *name, |
30 | struct dentry *child) | 17 | struct dentry *child) |
31 | { | 18 | { |
@@ -214,125 +201,6 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir) | |||
214 | return 0; | 201 | return 0; |
215 | } | 202 | } |
216 | 203 | ||
217 | /** | ||
218 | * find_exported_dentry - helper routine to implement export_operations->decode_fh | ||
219 | * @sb: The &super_block identifying the filesystem | ||
220 | * @obj: An opaque identifier of the object to be found - passed to | ||
221 | * get_inode | ||
222 | * @parent: An optional opqaue identifier of the parent of the object. | ||
223 | * @acceptable: A function used to test possible &dentries to see if they are | ||
224 | * acceptable | ||
225 | * @context: A parameter to @acceptable so that it knows on what basis to | ||
226 | * judge. | ||
227 | * | ||
228 | * find_exported_dentry is the central helper routine to enable file systems | ||
229 | * to provide the decode_fh() export_operation. It's main task is to take | ||
230 | * an &inode, find or create an appropriate &dentry structure, and possibly | ||
231 | * splice this into the dcache in the correct place. | ||
232 | * | ||
233 | * The decode_fh() operation provided by the filesystem should call | ||
234 | * find_exported_dentry() with the same parameters that it received except | ||
235 | * that instead of the file handle fragment, pointers to opaque identifiers | ||
236 | * for the object and optionally its parent are passed. The default decode_fh | ||
237 | * routine passes one pointer to the start of the filehandle fragment, and | ||
238 | * one 8 bytes into the fragment. It is expected that most filesystems will | ||
239 | * take this approach, though the offset to the parent identifier may well be | ||
240 | * different. | ||
241 | * | ||
242 | * find_exported_dentry() will call get_dentry to get an dentry pointer from | ||
243 | * the file system. If any &dentry in the d_alias list is acceptable, it will | ||
244 | * be returned. Otherwise find_exported_dentry() will attempt to splice a new | ||
245 | * &dentry into the dcache using get_name() and get_parent() to find the | ||
246 | * appropriate place. | ||
247 | */ | ||
248 | |||
249 | struct dentry * | ||
250 | find_exported_dentry(struct super_block *sb, void *obj, void *parent, | ||
251 | int (*acceptable)(void *context, struct dentry *de), | ||
252 | void *context) | ||
253 | { | ||
254 | struct dentry *result, *alias; | ||
255 | int err = -ESTALE; | ||
256 | |||
257 | /* | ||
258 | * Attempt to find the inode. | ||
259 | */ | ||
260 | result = exportfs_get_dentry(sb, obj); | ||
261 | if (IS_ERR(result)) | ||
262 | return result; | ||
263 | |||
264 | if (S_ISDIR(result->d_inode->i_mode)) { | ||
265 | if (!(result->d_flags & DCACHE_DISCONNECTED)) { | ||
266 | if (acceptable(context, result)) | ||
267 | return result; | ||
268 | err = -EACCES; | ||
269 | goto err_result; | ||
270 | } | ||
271 | |||
272 | err = reconnect_path(sb, result); | ||
273 | if (err) | ||
274 | goto err_result; | ||
275 | } else { | ||
276 | struct dentry *target_dir, *nresult; | ||
277 | char nbuf[NAME_MAX+1]; | ||
278 | |||
279 | alias = find_acceptable_alias(result, acceptable, context); | ||
280 | if (alias) | ||
281 | return alias; | ||
282 | |||
283 | if (parent == NULL) | ||
284 | goto err_result; | ||
285 | |||
286 | target_dir = exportfs_get_dentry(sb,parent); | ||
287 | if (IS_ERR(target_dir)) { | ||
288 | err = PTR_ERR(target_dir); | ||
289 | goto err_result; | ||
290 | } | ||
291 | |||
292 | err = reconnect_path(sb, target_dir); | ||
293 | if (err) { | ||
294 | dput(target_dir); | ||
295 | goto err_result; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * As we weren't after a directory, have one more step to go. | ||
300 | */ | ||
301 | err = exportfs_get_name(target_dir, nbuf, result); | ||
302 | if (!err) { | ||
303 | mutex_lock(&target_dir->d_inode->i_mutex); | ||
304 | nresult = lookup_one_len(nbuf, target_dir, | ||
305 | strlen(nbuf)); | ||
306 | mutex_unlock(&target_dir->d_inode->i_mutex); | ||
307 | if (!IS_ERR(nresult)) { | ||
308 | if (nresult->d_inode) { | ||
309 | dput(result); | ||
310 | result = nresult; | ||
311 | } else | ||
312 | dput(nresult); | ||
313 | } | ||
314 | } | ||
315 | dput(target_dir); | ||
316 | } | ||
317 | |||
318 | alias = find_acceptable_alias(result, acceptable, context); | ||
319 | if (alias) | ||
320 | return alias; | ||
321 | |||
322 | /* drat - I just cannot find anything acceptable */ | ||
323 | dput(result); | ||
324 | /* It might be justifiable to return ESTALE here, | ||
325 | * but the filehandle at-least looks reasonable good | ||
326 | * and it may just be a permission problem, so returning | ||
327 | * -EACCESS is safer | ||
328 | */ | ||
329 | return ERR_PTR(-EACCES); | ||
330 | |||
331 | err_result: | ||
332 | dput(result); | ||
333 | return ERR_PTR(err); | ||
334 | } | ||
335 | |||
336 | struct getdents_callback { | 204 | struct getdents_callback { |
337 | char *name; /* name that was found. It already points to a | 205 | char *name; /* name that was found. It already points to a |
338 | buffer NAME_MAX+1 is size */ | 206 | buffer NAME_MAX+1 is size */ |
@@ -462,38 +330,6 @@ static int export_encode_fh(struct dentry *dentry, struct fid *fid, | |||
462 | return type; | 330 | return type; |
463 | } | 331 | } |
464 | 332 | ||
465 | |||
466 | /** | ||
467 | * export_decode_fh - default export_operations->decode_fh function | ||
468 | * @sb: The superblock | ||
469 | * @fh: pointer to the file handle fragment | ||
470 | * @fh_len: length of file handle fragment | ||
471 | * @acceptable: function for testing acceptability of dentrys | ||
472 | * @context: context for @acceptable | ||
473 | * | ||
474 | * This is the default decode_fh() function. | ||
475 | * a fileid_type of 1 indicates that the filehandlefragment | ||
476 | * just contains an object identifier understood by get_dentry. | ||
477 | * a fileid_type of 2 says that there is also a directory | ||
478 | * identifier 8 bytes in to the filehandlefragement. | ||
479 | */ | ||
480 | static struct dentry *export_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, | ||
481 | int fileid_type, | ||
482 | int (*acceptable)(void *context, struct dentry *de), | ||
483 | void *context) | ||
484 | { | ||
485 | __u32 parent[2]; | ||
486 | parent[0] = parent[1] = 0; | ||
487 | if (fh_len < 2 || fileid_type > 2) | ||
488 | return NULL; | ||
489 | if (fileid_type == 2) { | ||
490 | if (fh_len > 2) parent[0] = fh[2]; | ||
491 | if (fh_len > 3) parent[1] = fh[3]; | ||
492 | } | ||
493 | return find_exported_dentry(sb, fh, parent, | ||
494 | acceptable, context); | ||
495 | } | ||
496 | |||
497 | int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len, | 333 | int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len, |
498 | int connectable) | 334 | int connectable) |
499 | { | 335 | { |
@@ -518,19 +354,6 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, | |||
518 | int err; | 354 | int err; |
519 | 355 | ||
520 | /* | 356 | /* |
521 | * Old way of doing things. Will go away soon. | ||
522 | */ | ||
523 | if (!nop->fh_to_dentry) { | ||
524 | if (nop->decode_fh) { | ||
525 | return nop->decode_fh(mnt->mnt_sb, fid->raw, fh_len, | ||
526 | fileid_type, acceptable, context); | ||
527 | } else { | ||
528 | return export_decode_fh(mnt->mnt_sb, fid->raw, fh_len, | ||
529 | fileid_type, acceptable, context); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * Try to get any dentry for the given file handle from the filesystem. | 357 | * Try to get any dentry for the given file handle from the filesystem. |
535 | */ | 358 | */ |
536 | result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type); | 359 | result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type); |
@@ -652,6 +475,4 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, | |||
652 | } | 475 | } |
653 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); | 476 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); |
654 | 477 | ||
655 | EXPORT_SYMBOL(find_exported_dentry); | ||
656 | |||
657 | MODULE_LICENSE("GPL"); | 478 | MODULE_LICENSE("GPL"); |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 04b266729802..66d0aeb32a47 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -386,15 +386,13 @@ static int check_export(struct inode *inode, int flags, unsigned char *uuid) | |||
386 | dprintk("exp_export: export of non-dev fs without fsid\n"); | 386 | dprintk("exp_export: export of non-dev fs without fsid\n"); |
387 | return -EINVAL; | 387 | return -EINVAL; |
388 | } | 388 | } |
389 | if (!inode->i_sb->s_export_op) { | 389 | |
390 | if (!inode->i_sb->s_export_op || | ||
391 | !inode->i_sb->s_export_op->fh_to_dentry) { | ||
390 | dprintk("exp_export: export of invalid fs type.\n"); | 392 | dprintk("exp_export: export of invalid fs type.\n"); |
391 | return -EINVAL; | 393 | return -EINVAL; |
392 | } | 394 | } |
393 | 395 | ||
394 | /* Ok, we can export it */; | ||
395 | if (!inode->i_sb->s_export_op->find_exported_dentry) | ||
396 | inode->i_sb->s_export_op->find_exported_dentry = | ||
397 | find_exported_dentry; | ||
398 | return 0; | 396 | return 0; |
399 | 397 | ||
400 | } | 398 | } |
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index b44f6b6871c8..0b4a771b4903 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h | |||
@@ -54,8 +54,6 @@ struct fid { | |||
54 | * @get_name: find the name for a given inode in a given directory | 54 | * @get_name: find the name for a given inode in a given directory |
55 | * @get_parent: find the parent of a given directory | 55 | * @get_parent: find the parent of a given directory |
56 | * @get_dentry: find a dentry for the inode given a file handle sub-fragment | 56 | * @get_dentry: find a dentry for the inode given a file handle sub-fragment |
57 | * @find_exported_dentry: | ||
58 | * set by the exporting module to a standard helper function. | ||
59 | * | 57 | * |
60 | * Description: | 58 | * Description: |
61 | * The export_operations structure provides a means for nfsd to communicate | 59 | * The export_operations structure provides a means for nfsd to communicate |
@@ -82,16 +80,6 @@ struct fid { | |||
82 | * looking for the next. As soon as an acceptable one is found, it should | 80 | * looking for the next. As soon as an acceptable one is found, it should |
83 | * be returned. | 81 | * be returned. |
84 | * | 82 | * |
85 | * decode_fh: | ||
86 | * @decode_fh is given a &struct super_block (@sb), a file handle fragment | ||
87 | * (@fh, @fh_len) and an acceptability testing function (@acceptable, | ||
88 | * @context). It should return a &struct dentry which refers to the same | ||
89 | * file that the file handle fragment refers to, and which passes the | ||
90 | * acceptability test. If it cannot, it should return a %NULL pointer if | ||
91 | * the file was found but no acceptable &dentries were available, or a | ||
92 | * %ERR_PTR error code indicating why it couldn't be found (e.g. %ENOENT or | ||
93 | * %ENOMEM). | ||
94 | * | ||
95 | * encode_fh: | 83 | * encode_fh: |
96 | * @encode_fh should store in the file handle fragment @fh (using at most | 84 | * @encode_fh should store in the file handle fragment @fh (using at most |
97 | * @max_len bytes) information that can be used by @decode_fh to recover the | 85 | * @max_len bytes) information that can be used by @decode_fh to recover the |
@@ -129,30 +117,12 @@ struct fid { | |||
129 | * is also a directory. In the event that it cannot be found, or storage | 117 | * is also a directory. In the event that it cannot be found, or storage |
130 | * space cannot be allocated, a %ERR_PTR should be returned. | 118 | * space cannot be allocated, a %ERR_PTR should be returned. |
131 | * | 119 | * |
132 | * get_dentry: | ||
133 | * Given a &super_block (@sb) and a pointer to a file-system specific inode | ||
134 | * identifier, possibly an inode number, (@inump) get_dentry() should find | ||
135 | * the identified inode and return a dentry for that inode. Any suitable | ||
136 | * dentry can be returned including, if necessary, a new dentry created with | ||
137 | * d_alloc_root. The caller can then find any other extant dentrys by | ||
138 | * following the d_alias links. If a new dentry was created using | ||
139 | * d_alloc_root, DCACHE_NFSD_DISCONNECTED should be set, and the dentry | ||
140 | * should be d_rehash()ed. | ||
141 | * | ||
142 | * If the inode cannot be found, either a %NULL pointer or an %ERR_PTR code | ||
143 | * can be returned. The @inump will be whatever was passed to | ||
144 | * nfsd_find_fh_dentry() in either the @obj or @parent parameters. | ||
145 | * | ||
146 | * Locking rules: | 120 | * Locking rules: |
147 | * get_parent is called with child->d_inode->i_mutex down | 121 | * get_parent is called with child->d_inode->i_mutex down |
148 | * get_name is not (which is possibly inconsistent) | 122 | * get_name is not (which is possibly inconsistent) |
149 | */ | 123 | */ |
150 | 124 | ||
151 | struct export_operations { | 125 | struct export_operations { |
152 | struct dentry *(*decode_fh)(struct super_block *sb, __u32 *fh, | ||
153 | int fh_len, int fh_type, | ||
154 | int (*acceptable)(void *context, struct dentry *de), | ||
155 | void *context); | ||
156 | int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len, | 126 | int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len, |
157 | int connectable); | 127 | int connectable); |
158 | struct dentry * (*fh_to_dentry)(struct super_block *sb, struct fid *fid, | 128 | struct dentry * (*fh_to_dentry)(struct super_block *sb, struct fid *fid, |
@@ -162,19 +132,8 @@ struct export_operations { | |||
162 | int (*get_name)(struct dentry *parent, char *name, | 132 | int (*get_name)(struct dentry *parent, char *name, |
163 | struct dentry *child); | 133 | struct dentry *child); |
164 | struct dentry * (*get_parent)(struct dentry *child); | 134 | struct dentry * (*get_parent)(struct dentry *child); |
165 | struct dentry * (*get_dentry)(struct super_block *sb, void *inump); | ||
166 | |||
167 | /* This is set by the exporting module to a standard helper */ | ||
168 | struct dentry * (*find_exported_dentry)( | ||
169 | struct super_block *sb, void *obj, void *parent, | ||
170 | int (*acceptable)(void *context, struct dentry *de), | ||
171 | void *context); | ||
172 | }; | 135 | }; |
173 | 136 | ||
174 | extern struct dentry *find_exported_dentry(struct super_block *sb, void *obj, | ||
175 | void *parent, int (*acceptable)(void *context, struct dentry *de), | ||
176 | void *context); | ||
177 | |||
178 | extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, | 137 | extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, |
179 | int *max_len, int connectable); | 138 | int *max_len, int connectable); |
180 | extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, | 139 | extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, |