diff options
Diffstat (limited to 'fs/exportfs/expfs.c')
-rw-r--r-- | fs/exportfs/expfs.c | 128 |
1 files changed, 72 insertions, 56 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index db86006956b0..1e6f556514d6 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -6,11 +6,36 @@ | |||
6 | #include <linux/mount.h> | 6 | #include <linux/mount.h> |
7 | #include <linux/namei.h> | 7 | #include <linux/namei.h> |
8 | 8 | ||
9 | struct export_operations export_op_default; | 9 | #define dprintk(fmt, args...) do{}while(0) |
10 | 10 | ||
11 | #define CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun) | ||
12 | 11 | ||
13 | #define dprintk(fmt, args...) do{}while(0) | 12 | static int get_name(struct dentry *dentry, char *name, |
13 | struct dentry *child); | ||
14 | |||
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, | ||
30 | struct dentry *child) | ||
31 | { | ||
32 | struct export_operations *nop = dir->d_sb->s_export_op; | ||
33 | |||
34 | if (nop->get_name) | ||
35 | return nop->get_name(dir, name, child); | ||
36 | else | ||
37 | return get_name(dir, name, child); | ||
38 | } | ||
14 | 39 | ||
15 | static struct dentry * | 40 | static struct dentry * |
16 | find_acceptable_alias(struct dentry *result, | 41 | find_acceptable_alias(struct dentry *result, |
@@ -78,7 +103,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
78 | { | 103 | { |
79 | struct dentry *result = NULL; | 104 | struct dentry *result = NULL; |
80 | struct dentry *target_dir; | 105 | struct dentry *target_dir; |
81 | int err; | 106 | int err = -ESTALE; |
82 | struct export_operations *nops = sb->s_export_op; | 107 | struct export_operations *nops = sb->s_export_op; |
83 | struct dentry *alias; | 108 | struct dentry *alias; |
84 | int noprogress; | 109 | int noprogress; |
@@ -87,14 +112,10 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
87 | /* | 112 | /* |
88 | * Attempt to find the inode. | 113 | * Attempt to find the inode. |
89 | */ | 114 | */ |
90 | result = CALL(sb->s_export_op,get_dentry)(sb,obj); | 115 | result = exportfs_get_dentry(sb, obj); |
91 | err = -ESTALE; | 116 | if (IS_ERR(result)) |
92 | if (result == NULL) | 117 | return result; |
93 | goto err_out; | 118 | |
94 | if (IS_ERR(result)) { | ||
95 | err = PTR_ERR(result); | ||
96 | goto err_out; | ||
97 | } | ||
98 | if (S_ISDIR(result->d_inode->i_mode) && | 119 | if (S_ISDIR(result->d_inode->i_mode) && |
99 | (result->d_flags & DCACHE_DISCONNECTED)) { | 120 | (result->d_flags & DCACHE_DISCONNECTED)) { |
100 | /* it is an unconnected directory, we must connect it */ | 121 | /* it is an unconnected directory, we must connect it */ |
@@ -122,11 +143,11 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
122 | if (parent == NULL) | 143 | if (parent == NULL) |
123 | goto err_result; | 144 | goto err_result; |
124 | 145 | ||
125 | target_dir = CALL(sb->s_export_op,get_dentry)(sb,parent); | 146 | target_dir = exportfs_get_dentry(sb,parent); |
126 | if (IS_ERR(target_dir)) | 147 | if (IS_ERR(target_dir)) { |
127 | err = PTR_ERR(target_dir); | 148 | err = PTR_ERR(target_dir); |
128 | if (target_dir == NULL || IS_ERR(target_dir)) | ||
129 | goto err_result; | 149 | goto err_result; |
150 | } | ||
130 | } | 151 | } |
131 | /* | 152 | /* |
132 | * Now we need to make sure that target_dir is properly connected. | 153 | * Now we need to make sure that target_dir is properly connected. |
@@ -177,18 +198,27 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
177 | spin_unlock(&pd->d_lock); | 198 | spin_unlock(&pd->d_lock); |
178 | noprogress = 0; | 199 | noprogress = 0; |
179 | } else { | 200 | } else { |
180 | /* we have hit the top of a disconnected path. Try | 201 | /* |
181 | * to find parent and connect | 202 | * We have hit the top of a disconnected path, try to |
182 | * note: racing with some other process renaming a | 203 | * find parent and connect. |
183 | * directory isn't much of a problem here. If someone | 204 | * |
184 | * renames the directory, it will end up properly | 205 | * Racing with some other process renaming a directory |
185 | * connected, which is what we want | 206 | * isn't much of a problem here. If someone renames |
207 | * the directory, it will end up properly connected, | ||
208 | * which is what we want | ||
209 | * | ||
210 | * Getting the parent can't be supported generically, | ||
211 | * the locking is too icky. | ||
212 | * | ||
213 | * Instead we just return EACCES. If server reboots | ||
214 | * or inodes get flushed, you lose | ||
186 | */ | 215 | */ |
187 | struct dentry *ppd; | 216 | struct dentry *ppd = ERR_PTR(-EACCES); |
188 | struct dentry *npd; | 217 | struct dentry *npd; |
189 | 218 | ||
190 | mutex_lock(&pd->d_inode->i_mutex); | 219 | mutex_lock(&pd->d_inode->i_mutex); |
191 | ppd = CALL(nops,get_parent)(pd); | 220 | if (nops->get_parent) |
221 | ppd = nops->get_parent(pd); | ||
192 | mutex_unlock(&pd->d_inode->i_mutex); | 222 | mutex_unlock(&pd->d_inode->i_mutex); |
193 | 223 | ||
194 | if (IS_ERR(ppd)) { | 224 | if (IS_ERR(ppd)) { |
@@ -199,7 +229,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
199 | break; | 229 | break; |
200 | } | 230 | } |
201 | dprintk("find_exported_dentry: find name of %lu in %lu\n", pd->d_inode->i_ino, ppd->d_inode->i_ino); | 231 | dprintk("find_exported_dentry: find name of %lu in %lu\n", pd->d_inode->i_ino, ppd->d_inode->i_ino); |
202 | err = CALL(nops,get_name)(ppd, nbuf, pd); | 232 | err = exportfs_get_name(ppd, nbuf, pd); |
203 | if (err) { | 233 | if (err) { |
204 | dput(ppd); | 234 | dput(ppd); |
205 | dput(pd); | 235 | dput(pd); |
@@ -250,7 +280,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
250 | /* if we weren't after a directory, have one more step to go */ | 280 | /* if we weren't after a directory, have one more step to go */ |
251 | if (result != target_dir) { | 281 | if (result != target_dir) { |
252 | struct dentry *nresult; | 282 | struct dentry *nresult; |
253 | err = CALL(nops,get_name)(target_dir, nbuf, result); | 283 | err = exportfs_get_name(target_dir, nbuf, result); |
254 | if (!err) { | 284 | if (!err) { |
255 | mutex_lock(&target_dir->d_inode->i_mutex); | 285 | mutex_lock(&target_dir->d_inode->i_mutex); |
256 | nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf)); | 286 | nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf)); |
@@ -286,23 +316,9 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
286 | dput(target_dir); | 316 | dput(target_dir); |
287 | err_result: | 317 | err_result: |
288 | dput(result); | 318 | dput(result); |
289 | err_out: | ||
290 | return ERR_PTR(err); | 319 | return ERR_PTR(err); |
291 | } | 320 | } |
292 | 321 | ||
293 | |||
294 | |||
295 | static struct dentry *get_parent(struct dentry *child) | ||
296 | { | ||
297 | /* get_parent cannot be supported generically, the locking | ||
298 | * is too icky. | ||
299 | * instead, we just return EACCES. If server reboots or inodes | ||
300 | * get flushed, you lose | ||
301 | */ | ||
302 | return ERR_PTR(-EACCES); | ||
303 | } | ||
304 | |||
305 | |||
306 | struct getdents_callback { | 322 | struct getdents_callback { |
307 | char *name; /* name that was found. It already points to a | 323 | char *name; /* name that was found. It already points to a |
308 | buffer NAME_MAX+1 is size */ | 324 | buffer NAME_MAX+1 is size */ |
@@ -392,11 +408,6 @@ out: | |||
392 | return error; | 408 | return error; |
393 | } | 409 | } |
394 | 410 | ||
395 | static struct dentry *get_dentry(struct super_block *sb, void *vobjp) | ||
396 | { | ||
397 | return ERR_PTR(-ESTALE); | ||
398 | } | ||
399 | |||
400 | /** | 411 | /** |
401 | * export_encode_fh - default export_operations->encode_fh function | 412 | * export_encode_fh - default export_operations->encode_fh function |
402 | * @dentry: the dentry to encode | 413 | * @dentry: the dentry to encode |
@@ -472,9 +483,15 @@ static struct dentry *export_decode_fh(struct super_block *sb, __u32 *fh, int fh | |||
472 | int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, | 483 | int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, |
473 | int connectable) | 484 | int connectable) |
474 | { | 485 | { |
475 | struct export_operations *nop = dentry->d_sb->s_export_op; | 486 | struct export_operations *nop = dentry->d_sb->s_export_op; |
487 | int error; | ||
476 | 488 | ||
477 | return CALL(nop, encode_fh)(dentry, fh, max_len, connectable); | 489 | if (nop->encode_fh) |
490 | error = nop->encode_fh(dentry, fh, max_len, connectable); | ||
491 | else | ||
492 | error = export_encode_fh(dentry, fh, max_len, connectable); | ||
493 | |||
494 | return error; | ||
478 | } | 495 | } |
479 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); | 496 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); |
480 | 497 | ||
@@ -483,21 +500,20 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len, | |||
483 | void *context) | 500 | void *context) |
484 | { | 501 | { |
485 | struct export_operations *nop = mnt->mnt_sb->s_export_op; | 502 | struct export_operations *nop = mnt->mnt_sb->s_export_op; |
503 | struct dentry *result; | ||
486 | 504 | ||
487 | return CALL(nop, decode_fh)(mnt->mnt_sb, fh, fh_len, fileid_type, | 505 | if (nop->decode_fh) { |
506 | result = nop->decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | ||
488 | acceptable, context); | 507 | acceptable, context); |
508 | } else { | ||
509 | result = export_decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | ||
510 | acceptable, context); | ||
511 | } | ||
512 | |||
513 | return result; | ||
489 | } | 514 | } |
490 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); | 515 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); |
491 | 516 | ||
492 | struct export_operations export_op_default = { | ||
493 | .decode_fh = export_decode_fh, | ||
494 | .encode_fh = export_encode_fh, | ||
495 | |||
496 | .get_name = get_name, | ||
497 | .get_parent = get_parent, | ||
498 | .get_dentry = get_dentry, | ||
499 | }; | ||
500 | |||
501 | EXPORT_SYMBOL(find_exported_dentry); | 517 | EXPORT_SYMBOL(find_exported_dentry); |
502 | 518 | ||
503 | MODULE_LICENSE("GPL"); | 519 | MODULE_LICENSE("GPL"); |