diff options
| -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"); |
