diff options
Diffstat (limited to 'fs/gfs2/ops_inode.c')
| -rw-r--r-- | fs/gfs2/ops_inode.c | 113 |
1 files changed, 27 insertions, 86 deletions
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 84350e1be66d..4e64352d49de 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
| @@ -976,122 +976,62 @@ out: | |||
| 976 | } | 976 | } |
| 977 | 977 | ||
| 978 | /** | 978 | /** |
| 979 | * gfs2_readlinki - return the contents of a symlink | 979 | * gfs2_follow_link - Follow a symbolic link |
| 980 | * @ip: the symlink's inode | 980 | * @dentry: The dentry of the link |
| 981 | * @buf: a pointer to the buffer to be filled | 981 | * @nd: Data that we pass to vfs_follow_link() |
| 982 | * @len: a pointer to the length of @buf | ||
| 983 | * | 982 | * |
| 984 | * If @buf is too small, a piece of memory is kmalloc()ed and needs | 983 | * This can handle symlinks of any size. |
| 985 | * to be freed by the caller. | ||
| 986 | * | 984 | * |
| 987 | * Returns: errno | 985 | * Returns: 0 on success or error code |
| 988 | */ | 986 | */ |
| 989 | 987 | ||
| 990 | static int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len) | 988 | static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 991 | { | 989 | { |
| 990 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | ||
| 992 | struct gfs2_holder i_gh; | 991 | struct gfs2_holder i_gh; |
| 993 | struct buffer_head *dibh; | 992 | struct buffer_head *dibh; |
| 994 | unsigned int x; | 993 | unsigned int x; |
| 994 | char *buf; | ||
| 995 | int error; | 995 | int error; |
| 996 | 996 | ||
| 997 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); | 997 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); |
| 998 | error = gfs2_glock_nq(&i_gh); | 998 | error = gfs2_glock_nq(&i_gh); |
| 999 | if (error) { | 999 | if (error) { |
| 1000 | gfs2_holder_uninit(&i_gh); | 1000 | gfs2_holder_uninit(&i_gh); |
| 1001 | return error; | 1001 | nd_set_link(nd, ERR_PTR(error)); |
| 1002 | return NULL; | ||
| 1002 | } | 1003 | } |
| 1003 | 1004 | ||
| 1004 | if (!ip->i_disksize) { | 1005 | if (!ip->i_disksize) { |
| 1005 | gfs2_consist_inode(ip); | 1006 | gfs2_consist_inode(ip); |
| 1006 | error = -EIO; | 1007 | buf = ERR_PTR(-EIO); |
| 1007 | goto out; | 1008 | goto out; |
| 1008 | } | 1009 | } |
| 1009 | 1010 | ||
| 1010 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1011 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 1011 | if (error) | 1012 | if (error) { |
| 1013 | buf = ERR_PTR(error); | ||
| 1012 | goto out; | 1014 | goto out; |
| 1013 | |||
| 1014 | x = ip->i_disksize + 1; | ||
| 1015 | if (x > *len) { | ||
| 1016 | *buf = kmalloc(x, GFP_NOFS); | ||
| 1017 | if (!*buf) { | ||
| 1018 | error = -ENOMEM; | ||
| 1019 | goto out_brelse; | ||
| 1020 | } | ||
| 1021 | } | 1015 | } |
| 1022 | 1016 | ||
| 1023 | memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x); | 1017 | x = ip->i_disksize + 1; |
| 1024 | *len = x; | 1018 | buf = kmalloc(x, GFP_NOFS); |
| 1025 | 1019 | if (!buf) | |
| 1026 | out_brelse: | 1020 | buf = ERR_PTR(-ENOMEM); |
| 1021 | else | ||
| 1022 | memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x); | ||
| 1027 | brelse(dibh); | 1023 | brelse(dibh); |
| 1028 | out: | 1024 | out: |
| 1029 | gfs2_glock_dq_uninit(&i_gh); | 1025 | gfs2_glock_dq_uninit(&i_gh); |
| 1030 | return error; | 1026 | nd_set_link(nd, buf); |
| 1031 | } | 1027 | return NULL; |
| 1032 | |||
| 1033 | /** | ||
| 1034 | * gfs2_readlink - Read the value of a symlink | ||
| 1035 | * @dentry: the symlink | ||
| 1036 | * @buf: the buffer to read the symlink data into | ||
| 1037 | * @size: the size of the buffer | ||
| 1038 | * | ||
| 1039 | * Returns: errno | ||
| 1040 | */ | ||
| 1041 | |||
| 1042 | static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, | ||
| 1043 | int user_size) | ||
| 1044 | { | ||
| 1045 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | ||
| 1046 | char array[GFS2_FAST_NAME_SIZE], *buf = array; | ||
| 1047 | unsigned int len = GFS2_FAST_NAME_SIZE; | ||
| 1048 | int error; | ||
| 1049 | |||
| 1050 | error = gfs2_readlinki(ip, &buf, &len); | ||
| 1051 | if (error) | ||
| 1052 | return error; | ||
| 1053 | |||
| 1054 | if (user_size > len - 1) | ||
| 1055 | user_size = len - 1; | ||
| 1056 | |||
| 1057 | if (copy_to_user(user_buf, buf, user_size)) | ||
| 1058 | error = -EFAULT; | ||
| 1059 | else | ||
| 1060 | error = user_size; | ||
| 1061 | |||
| 1062 | if (buf != array) | ||
| 1063 | kfree(buf); | ||
| 1064 | |||
| 1065 | return error; | ||
| 1066 | } | 1028 | } |
| 1067 | 1029 | ||
| 1068 | /** | 1030 | static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) |
| 1069 | * gfs2_follow_link - Follow a symbolic link | ||
| 1070 | * @dentry: The dentry of the link | ||
| 1071 | * @nd: Data that we pass to vfs_follow_link() | ||
| 1072 | * | ||
| 1073 | * This can handle symlinks of any size. It is optimised for symlinks | ||
| 1074 | * under GFS2_FAST_NAME_SIZE. | ||
| 1075 | * | ||
| 1076 | * Returns: 0 on success or error code | ||
| 1077 | */ | ||
| 1078 | |||
| 1079 | static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
| 1080 | { | 1031 | { |
| 1081 | struct gfs2_inode *ip = GFS2_I(dentry->d_inode); | 1032 | char *s = nd_get_link(nd); |
| 1082 | char array[GFS2_FAST_NAME_SIZE], *buf = array; | 1033 | if (!IS_ERR(s)) |
| 1083 | unsigned int len = GFS2_FAST_NAME_SIZE; | 1034 | kfree(s); |
| 1084 | int error; | ||
| 1085 | |||
| 1086 | error = gfs2_readlinki(ip, &buf, &len); | ||
| 1087 | if (!error) { | ||
| 1088 | error = vfs_follow_link(nd, buf); | ||
| 1089 | if (buf != array) | ||
| 1090 | kfree(buf); | ||
| 1091 | } else | ||
| 1092 | path_put(&nd->path); | ||
| 1093 | |||
| 1094 | return ERR_PTR(error); | ||
| 1095 | } | 1035 | } |
| 1096 | 1036 | ||
| 1097 | /** | 1037 | /** |
| @@ -1426,8 +1366,9 @@ const struct inode_operations gfs2_dir_iops = { | |||
| 1426 | }; | 1366 | }; |
| 1427 | 1367 | ||
| 1428 | const struct inode_operations gfs2_symlink_iops = { | 1368 | const struct inode_operations gfs2_symlink_iops = { |
| 1429 | .readlink = gfs2_readlink, | 1369 | .readlink = generic_readlink, |
| 1430 | .follow_link = gfs2_follow_link, | 1370 | .follow_link = gfs2_follow_link, |
| 1371 | .put_link = gfs2_put_link, | ||
| 1431 | .permission = gfs2_permission, | 1372 | .permission = gfs2_permission, |
| 1432 | .setattr = gfs2_setattr, | 1373 | .setattr = gfs2_setattr, |
| 1433 | .getattr = gfs2_getattr, | 1374 | .getattr = gfs2_getattr, |
