aboutsummaryrefslogtreecommitdiffstats
path: root/fs/befs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-09-16 10:35:31 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-10-24 23:34:50 -0400
commit48bc06e74be178968b53d339dbcb110cd2bb16ea (patch)
treee3756efb4b2460881fe7f89417f54cdefa8ee7b3 /fs/befs
parent87dc800be2499128efb3a6f059d75dc8e1e6d503 (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.c61
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);
42static int befs_init_inodecache(void); 42static int befs_init_inodecache(void);
43static void befs_destroy_inodecache(void); 43static void befs_destroy_inodecache(void);
44static void *befs_follow_link(struct dentry *, struct nameidata *); 44static void *befs_follow_link(struct dentry *, struct nameidata *);
45static void befs_put_link(struct dentry *, struct nameidata *, void *); 45static void *befs_fast_follow_link(struct dentry *, struct nameidata *);
46static int befs_utf2nls(struct super_block *sb, const char *in, int in_len, 46static 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);
48static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, 48static 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
82static const struct inode_operations befs_fast_symlink_inode_operations = {
83 .readlink = generic_readlink,
84 .follow_link = befs_fast_follow_link,
85};
86
82static const struct inode_operations befs_symlink_inode_operations = { 87static 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)
477static void * 485static void *
478befs_follow_link(struct dentry *dentry, struct nameidata *nd) 486befs_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
513static void befs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) 515
516static void *
517befs_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/*