diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-09-16 10:35:31 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-10-24 23:34:50 -0400 |
commit | 48bc06e74be178968b53d339dbcb110cd2bb16ea (patch) | |
tree | e3756efb4b2460881fe7f89417f54cdefa8ee7b3 /fs/befs | |
parent | 87dc800be2499128efb3a6f059d75dc8e1e6d503 (diff) |
befs: split symlink iops in two - for short and long symlinks resp.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/befs')
-rw-r--r-- | fs/befs/linuxvfs.c | 61 |
1 files changed, 31 insertions, 30 deletions
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index e9c75e20db32..daa15d6ba450 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
@@ -42,7 +42,7 @@ static void befs_destroy_inode(struct inode *inode); | |||
42 | static int befs_init_inodecache(void); | 42 | static int befs_init_inodecache(void); |
43 | static void befs_destroy_inodecache(void); | 43 | static void befs_destroy_inodecache(void); |
44 | static void *befs_follow_link(struct dentry *, struct nameidata *); | 44 | static void *befs_follow_link(struct dentry *, struct nameidata *); |
45 | static void befs_put_link(struct dentry *, struct nameidata *, void *); | 45 | static void *befs_fast_follow_link(struct dentry *, struct nameidata *); |
46 | static int befs_utf2nls(struct super_block *sb, const char *in, int in_len, | 46 | static int befs_utf2nls(struct super_block *sb, const char *in, int in_len, |
47 | char **out, int *out_len); | 47 | char **out, int *out_len); |
48 | static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, | 48 | static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, |
@@ -79,10 +79,15 @@ static const struct address_space_operations befs_aops = { | |||
79 | .bmap = befs_bmap, | 79 | .bmap = befs_bmap, |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static const struct inode_operations befs_fast_symlink_inode_operations = { | ||
83 | .readlink = generic_readlink, | ||
84 | .follow_link = befs_fast_follow_link, | ||
85 | }; | ||
86 | |||
82 | static const struct inode_operations befs_symlink_inode_operations = { | 87 | static const struct inode_operations befs_symlink_inode_operations = { |
83 | .readlink = generic_readlink, | 88 | .readlink = generic_readlink, |
84 | .follow_link = befs_follow_link, | 89 | .follow_link = befs_follow_link, |
85 | .put_link = befs_put_link, | 90 | .put_link = kfree_put_link, |
86 | }; | 91 | }; |
87 | 92 | ||
88 | /* | 93 | /* |
@@ -411,7 +416,10 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) | |||
411 | inode->i_op = &befs_dir_inode_operations; | 416 | inode->i_op = &befs_dir_inode_operations; |
412 | inode->i_fop = &befs_dir_operations; | 417 | inode->i_fop = &befs_dir_operations; |
413 | } else if (S_ISLNK(inode->i_mode)) { | 418 | } else if (S_ISLNK(inode->i_mode)) { |
414 | inode->i_op = &befs_symlink_inode_operations; | 419 | if (befs_ino->i_flags & BEFS_LONG_SYMLINK) |
420 | inode->i_op = &befs_symlink_inode_operations; | ||
421 | else | ||
422 | inode->i_op = &befs_fast_symlink_inode_operations; | ||
415 | } else { | 423 | } else { |
416 | befs_error(sb, "Inode %lu is not a regular file, " | 424 | befs_error(sb, "Inode %lu is not a regular file, " |
417 | "directory or symlink. THAT IS WRONG! BeFS has no " | 425 | "directory or symlink. THAT IS WRONG! BeFS has no " |
@@ -477,47 +485,40 @@ befs_destroy_inodecache(void) | |||
477 | static void * | 485 | static void * |
478 | befs_follow_link(struct dentry *dentry, struct nameidata *nd) | 486 | befs_follow_link(struct dentry *dentry, struct nameidata *nd) |
479 | { | 487 | { |
488 | struct super_block *sb = dentry->d_sb; | ||
480 | befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); | 489 | befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); |
490 | befs_data_stream *data = &befs_ino->i_data.ds; | ||
491 | befs_off_t len = data->size; | ||
481 | char *link; | 492 | char *link; |
482 | 493 | ||
483 | if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { | 494 | if (len == 0) { |
484 | struct super_block *sb = dentry->d_sb; | 495 | befs_error(sb, "Long symlink with illegal length"); |
485 | befs_data_stream *data = &befs_ino->i_data.ds; | 496 | link = ERR_PTR(-EIO); |
486 | befs_off_t len = data->size; | 497 | } else { |
498 | befs_debug(sb, "Follow long symlink"); | ||
487 | 499 | ||
488 | if (len == 0) { | 500 | link = kmalloc(len, GFP_NOFS); |
489 | befs_error(sb, "Long symlink with illegal length"); | 501 | if (!link) { |
502 | link = ERR_PTR(-ENOMEM); | ||
503 | } else if (befs_read_lsymlink(sb, data, link, len) != len) { | ||
504 | kfree(link); | ||
505 | befs_error(sb, "Failed to read entire long symlink"); | ||
490 | link = ERR_PTR(-EIO); | 506 | link = ERR_PTR(-EIO); |
491 | } else { | 507 | } else { |
492 | befs_debug(sb, "Follow long symlink"); | 508 | link[len - 1] = '\0'; |
493 | |||
494 | link = kmalloc(len, GFP_NOFS); | ||
495 | if (!link) { | ||
496 | link = ERR_PTR(-ENOMEM); | ||
497 | } else if (befs_read_lsymlink(sb, data, link, len) != len) { | ||
498 | kfree(link); | ||
499 | befs_error(sb, "Failed to read entire long symlink"); | ||
500 | link = ERR_PTR(-EIO); | ||
501 | } else { | ||
502 | link[len - 1] = '\0'; | ||
503 | } | ||
504 | } | 509 | } |
505 | } else { | ||
506 | link = befs_ino->i_data.symlink; | ||
507 | } | 510 | } |
508 | |||
509 | nd_set_link(nd, link); | 511 | nd_set_link(nd, link); |
510 | return NULL; | 512 | return NULL; |
511 | } | 513 | } |
512 | 514 | ||
513 | static void befs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) | 515 | |
516 | static void * | ||
517 | befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
514 | { | 518 | { |
515 | befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); | 519 | befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); |
516 | if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { | 520 | nd_set_link(nd, befs_ino->i_data.symlink); |
517 | char *link = nd_get_link(nd); | 521 | return NULL; |
518 | if (!IS_ERR(link)) | ||
519 | kfree(link); | ||
520 | } | ||
521 | } | 522 | } |
522 | 523 | ||
523 | /* | 524 | /* |