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