diff options
Diffstat (limited to 'fs/exportfs')
-rw-r--r-- | fs/exportfs/expfs.c | 360 |
1 files changed, 157 insertions, 203 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 8adb32a9387a..109ab5e44eca 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -1,4 +1,13 @@ | |||
1 | 1 | /* | |
2 | * Copyright (C) Neil Brown 2002 | ||
3 | * Copyright (C) Christoph Hellwig 2007 | ||
4 | * | ||
5 | * This file contains the code mapping from inodes to NFS file handles, | ||
6 | * and for mapping back from file handles to dentries. | ||
7 | * | ||
8 | * For details on why we do all the strange and hairy things in here | ||
9 | * take a look at Documentation/filesystems/Exporting. | ||
10 | */ | ||
2 | #include <linux/exportfs.h> | 11 | #include <linux/exportfs.h> |
3 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
4 | #include <linux/file.h> | 13 | #include <linux/file.h> |
@@ -9,32 +18,19 @@ | |||
9 | #define dprintk(fmt, args...) do{}while(0) | 18 | #define dprintk(fmt, args...) do{}while(0) |
10 | 19 | ||
11 | 20 | ||
12 | static int get_name(struct dentry *dentry, char *name, | 21 | static int get_name(struct vfsmount *mnt, struct dentry *dentry, char *name, |
13 | struct dentry *child); | 22 | struct dentry *child); |
14 | 23 | ||
15 | 24 | ||
16 | static struct dentry *exportfs_get_dentry(struct super_block *sb, void *obj) | 25 | static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir, |
26 | char *name, struct dentry *child) | ||
17 | { | 27 | { |
18 | struct dentry *result = ERR_PTR(-ESTALE); | 28 | const struct export_operations *nop = dir->d_sb->s_export_op; |
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, | ||
30 | struct dentry *child) | ||
31 | { | ||
32 | struct export_operations *nop = dir->d_sb->s_export_op; | ||
33 | 29 | ||
34 | if (nop->get_name) | 30 | if (nop->get_name) |
35 | return nop->get_name(dir, name, child); | 31 | return nop->get_name(dir, name, child); |
36 | else | 32 | else |
37 | return get_name(dir, name, child); | 33 | return get_name(mnt, dir, name, child); |
38 | } | 34 | } |
39 | 35 | ||
40 | /* | 36 | /* |
@@ -98,7 +94,7 @@ find_disconnected_root(struct dentry *dentry) | |||
98 | * It may already be, as the flag isn't always updated when connection happens. | 94 | * It may already be, as the flag isn't always updated when connection happens. |
99 | */ | 95 | */ |
100 | static int | 96 | static int |
101 | reconnect_path(struct super_block *sb, struct dentry *target_dir) | 97 | reconnect_path(struct vfsmount *mnt, struct dentry *target_dir) |
102 | { | 98 | { |
103 | char nbuf[NAME_MAX+1]; | 99 | char nbuf[NAME_MAX+1]; |
104 | int noprogress = 0; | 100 | int noprogress = 0; |
@@ -121,7 +117,7 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir) | |||
121 | pd->d_flags &= ~DCACHE_DISCONNECTED; | 117 | pd->d_flags &= ~DCACHE_DISCONNECTED; |
122 | spin_unlock(&pd->d_lock); | 118 | spin_unlock(&pd->d_lock); |
123 | noprogress = 0; | 119 | noprogress = 0; |
124 | } else if (pd == sb->s_root) { | 120 | } else if (pd == mnt->mnt_sb->s_root) { |
125 | printk(KERN_ERR "export: Eeek filesystem root is not connected, impossible\n"); | 121 | printk(KERN_ERR "export: Eeek filesystem root is not connected, impossible\n"); |
126 | spin_lock(&pd->d_lock); | 122 | spin_lock(&pd->d_lock); |
127 | pd->d_flags &= ~DCACHE_DISCONNECTED; | 123 | pd->d_flags &= ~DCACHE_DISCONNECTED; |
@@ -147,8 +143,8 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir) | |||
147 | struct dentry *npd; | 143 | struct dentry *npd; |
148 | 144 | ||
149 | mutex_lock(&pd->d_inode->i_mutex); | 145 | mutex_lock(&pd->d_inode->i_mutex); |
150 | if (sb->s_export_op->get_parent) | 146 | if (mnt->mnt_sb->s_export_op->get_parent) |
151 | ppd = sb->s_export_op->get_parent(pd); | 147 | ppd = mnt->mnt_sb->s_export_op->get_parent(pd); |
152 | mutex_unlock(&pd->d_inode->i_mutex); | 148 | mutex_unlock(&pd->d_inode->i_mutex); |
153 | 149 | ||
154 | if (IS_ERR(ppd)) { | 150 | if (IS_ERR(ppd)) { |
@@ -161,7 +157,7 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir) | |||
161 | 157 | ||
162 | dprintk("%s: find name of %lu in %lu\n", __FUNCTION__, | 158 | dprintk("%s: find name of %lu in %lu\n", __FUNCTION__, |
163 | pd->d_inode->i_ino, ppd->d_inode->i_ino); | 159 | pd->d_inode->i_ino, ppd->d_inode->i_ino); |
164 | err = exportfs_get_name(ppd, nbuf, pd); | 160 | err = exportfs_get_name(mnt, ppd, nbuf, pd); |
165 | if (err) { | 161 | if (err) { |
166 | dput(ppd); | 162 | dput(ppd); |
167 | dput(pd); | 163 | dput(pd); |
@@ -214,125 +210,6 @@ reconnect_path(struct super_block *sb, struct dentry *target_dir) | |||
214 | return 0; | 210 | return 0; |
215 | } | 211 | } |
216 | 212 | ||
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 { | 213 | struct getdents_callback { |
337 | char *name; /* name that was found. It already points to a | 214 | char *name; /* name that was found. It already points to a |
338 | buffer NAME_MAX+1 is size */ | 215 | buffer NAME_MAX+1 is size */ |
@@ -370,8 +247,8 @@ static int filldir_one(void * __buf, const char * name, int len, | |||
370 | * calls readdir on the parent until it finds an entry with | 247 | * calls readdir on the parent until it finds an entry with |
371 | * the same inode number as the child, and returns that. | 248 | * the same inode number as the child, and returns that. |
372 | */ | 249 | */ |
373 | static int get_name(struct dentry *dentry, char *name, | 250 | static int get_name(struct vfsmount *mnt, struct dentry *dentry, |
374 | struct dentry *child) | 251 | char *name, struct dentry *child) |
375 | { | 252 | { |
376 | struct inode *dir = dentry->d_inode; | 253 | struct inode *dir = dentry->d_inode; |
377 | int error; | 254 | int error; |
@@ -387,7 +264,7 @@ static int get_name(struct dentry *dentry, char *name, | |||
387 | /* | 264 | /* |
388 | * Open the directory ... | 265 | * Open the directory ... |
389 | */ | 266 | */ |
390 | file = dentry_open(dget(dentry), NULL, O_RDONLY); | 267 | file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY); |
391 | error = PTR_ERR(file); | 268 | error = PTR_ERR(file); |
392 | if (IS_ERR(file)) | 269 | if (IS_ERR(file)) |
393 | goto out; | 270 | goto out; |
@@ -434,100 +311,177 @@ out: | |||
434 | * can be used to check that it is still valid. It places them in the | 311 | * 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. | 312 | * filehandle fragment where export_decode_fh expects to find them. |
436 | */ | 313 | */ |
437 | static int export_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, | 314 | static int export_encode_fh(struct dentry *dentry, struct fid *fid, |
438 | int connectable) | 315 | int *max_len, int connectable) |
439 | { | 316 | { |
440 | struct inode * inode = dentry->d_inode; | 317 | struct inode * inode = dentry->d_inode; |
441 | int len = *max_len; | 318 | int len = *max_len; |
442 | int type = 1; | 319 | int type = FILEID_INO32_GEN; |
443 | 320 | ||
444 | if (len < 2 || (connectable && len < 4)) | 321 | if (len < 2 || (connectable && len < 4)) |
445 | return 255; | 322 | return 255; |
446 | 323 | ||
447 | len = 2; | 324 | len = 2; |
448 | fh[0] = inode->i_ino; | 325 | fid->i32.ino = inode->i_ino; |
449 | fh[1] = inode->i_generation; | 326 | fid->i32.gen = inode->i_generation; |
450 | if (connectable && !S_ISDIR(inode->i_mode)) { | 327 | if (connectable && !S_ISDIR(inode->i_mode)) { |
451 | struct inode *parent; | 328 | struct inode *parent; |
452 | 329 | ||
453 | spin_lock(&dentry->d_lock); | 330 | spin_lock(&dentry->d_lock); |
454 | parent = dentry->d_parent->d_inode; | 331 | parent = dentry->d_parent->d_inode; |
455 | fh[2] = parent->i_ino; | 332 | fid->i32.parent_ino = parent->i_ino; |
456 | fh[3] = parent->i_generation; | 333 | fid->i32.parent_gen = parent->i_generation; |
457 | spin_unlock(&dentry->d_lock); | 334 | spin_unlock(&dentry->d_lock); |
458 | len = 4; | 335 | len = 4; |
459 | type = 2; | 336 | type = FILEID_INO32_GEN_PARENT; |
460 | } | 337 | } |
461 | *max_len = len; | 338 | *max_len = len; |
462 | return type; | 339 | return type; |
463 | } | 340 | } |
464 | 341 | ||
465 | 342 | int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len, | |
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, __u32 *fh, int *max_len, | ||
498 | int connectable) | 343 | int connectable) |
499 | { | 344 | { |
500 | struct export_operations *nop = dentry->d_sb->s_export_op; | 345 | const struct export_operations *nop = dentry->d_sb->s_export_op; |
501 | int error; | 346 | int error; |
502 | 347 | ||
503 | if (nop->encode_fh) | 348 | if (nop->encode_fh) |
504 | error = nop->encode_fh(dentry, fh, max_len, connectable); | 349 | error = nop->encode_fh(dentry, fid->raw, max_len, connectable); |
505 | else | 350 | else |
506 | error = export_encode_fh(dentry, fh, max_len, connectable); | 351 | error = export_encode_fh(dentry, fid, max_len, connectable); |
507 | 352 | ||
508 | return error; | 353 | return error; |
509 | } | 354 | } |
510 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); | 355 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); |
511 | 356 | ||
512 | struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len, | 357 | struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, |
513 | int fileid_type, int (*acceptable)(void *, struct dentry *), | 358 | int fh_len, int fileid_type, |
514 | void *context) | 359 | int (*acceptable)(void *, struct dentry *), void *context) |
515 | { | 360 | { |
516 | struct export_operations *nop = mnt->mnt_sb->s_export_op; | 361 | const struct export_operations *nop = mnt->mnt_sb->s_export_op; |
517 | struct dentry *result; | 362 | struct dentry *result, *alias; |
363 | int err; | ||
518 | 364 | ||
519 | if (nop->decode_fh) { | 365 | /* |
520 | result = nop->decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | 366 | * Try to get any dentry for the given file handle from the filesystem. |
521 | acceptable, context); | 367 | */ |
368 | result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type); | ||
369 | if (!result) | ||
370 | result = ERR_PTR(-ESTALE); | ||
371 | if (IS_ERR(result)) | ||
372 | return result; | ||
373 | |||
374 | if (S_ISDIR(result->d_inode->i_mode)) { | ||
375 | /* | ||
376 | * This request is for a directory. | ||
377 | * | ||
378 | * On the positive side there is only one dentry for each | ||
379 | * directory inode. On the negative side this implies that we | ||
380 | * to ensure our dentry is connected all the way up to the | ||
381 | * filesystem root. | ||
382 | */ | ||
383 | if (result->d_flags & DCACHE_DISCONNECTED) { | ||
384 | err = reconnect_path(mnt, result); | ||
385 | if (err) | ||
386 | goto err_result; | ||
387 | } | ||
388 | |||
389 | if (!acceptable(context, result)) { | ||
390 | err = -EACCES; | ||
391 | goto err_result; | ||
392 | } | ||
393 | |||
394 | return result; | ||
522 | } else { | 395 | } else { |
523 | result = export_decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | 396 | /* |
524 | acceptable, context); | 397 | * It's not a directory. Life is a little more complicated. |
398 | */ | ||
399 | struct dentry *target_dir, *nresult; | ||
400 | char nbuf[NAME_MAX+1]; | ||
401 | |||
402 | /* | ||
403 | * See if either the dentry we just got from the filesystem | ||
404 | * or any alias for it is acceptable. This is always true | ||
405 | * if this filesystem is exported without the subtreecheck | ||
406 | * option. If the filesystem is exported with the subtree | ||
407 | * check option there's a fair chance we need to look at | ||
408 | * the parent directory in the file handle and make sure | ||
409 | * it's connected to the filesystem root. | ||
410 | */ | ||
411 | alias = find_acceptable_alias(result, acceptable, context); | ||
412 | if (alias) | ||
413 | return alias; | ||
414 | |||
415 | /* | ||
416 | * Try to extract a dentry for the parent directory from the | ||
417 | * file handle. If this fails we'll have to give up. | ||
418 | */ | ||
419 | err = -ESTALE; | ||
420 | if (!nop->fh_to_parent) | ||
421 | goto err_result; | ||
422 | |||
423 | target_dir = nop->fh_to_parent(mnt->mnt_sb, fid, | ||
424 | fh_len, fileid_type); | ||
425 | if (!target_dir) | ||
426 | goto err_result; | ||
427 | err = PTR_ERR(target_dir); | ||
428 | if (IS_ERR(target_dir)) | ||
429 | goto err_result; | ||
430 | |||
431 | /* | ||
432 | * And as usual we need to make sure the parent directory is | ||
433 | * connected to the filesystem root. The VFS really doesn't | ||
434 | * like disconnected directories.. | ||
435 | */ | ||
436 | err = reconnect_path(mnt, target_dir); | ||
437 | if (err) { | ||
438 | dput(target_dir); | ||
439 | goto err_result; | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * Now that we've got both a well-connected parent and a | ||
444 | * dentry for the inode we're after, make sure that our | ||
445 | * inode is actually connected to the parent. | ||
446 | */ | ||
447 | err = exportfs_get_name(mnt, target_dir, nbuf, result); | ||
448 | if (!err) { | ||
449 | mutex_lock(&target_dir->d_inode->i_mutex); | ||
450 | nresult = lookup_one_len(nbuf, target_dir, | ||
451 | strlen(nbuf)); | ||
452 | mutex_unlock(&target_dir->d_inode->i_mutex); | ||
453 | if (!IS_ERR(nresult)) { | ||
454 | if (nresult->d_inode) { | ||
455 | dput(result); | ||
456 | result = nresult; | ||
457 | } else | ||
458 | dput(nresult); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * At this point we are done with the parent, but it's pinned | ||
464 | * by the child dentry anyway. | ||
465 | */ | ||
466 | dput(target_dir); | ||
467 | |||
468 | /* | ||
469 | * And finally make sure the dentry is actually acceptable | ||
470 | * to NFSD. | ||
471 | */ | ||
472 | alias = find_acceptable_alias(result, acceptable, context); | ||
473 | if (!alias) { | ||
474 | err = -EACCES; | ||
475 | goto err_result; | ||
476 | } | ||
477 | |||
478 | return alias; | ||
525 | } | 479 | } |
526 | 480 | ||
527 | return result; | 481 | err_result: |
482 | dput(result); | ||
483 | return ERR_PTR(err); | ||
528 | } | 484 | } |
529 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); | 485 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); |
530 | 486 | ||
531 | EXPORT_SYMBOL(find_exported_dentry); | ||
532 | |||
533 | MODULE_LICENSE("GPL"); | 487 | MODULE_LICENSE("GPL"); |