aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/namei.c199
1 files changed, 126 insertions, 73 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 87a8a6e613ba..75f1bde43dcc 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3016,6 +3016,125 @@ struct ext4_renament {
3016 int dir_inlined; 3016 int dir_inlined;
3017}; 3017};
3018 3018
3019static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent)
3020{
3021 int retval;
3022
3023 ent->dir_bh = ext4_get_first_dir_block(handle, ent->inode,
3024 &retval, &ent->parent_de,
3025 &ent->dir_inlined);
3026 if (!ent->dir_bh)
3027 return retval;
3028 if (le32_to_cpu(ent->parent_de->inode) != ent->dir->i_ino)
3029 return -EIO;
3030 BUFFER_TRACE(ent->dir_bh, "get_write_access");
3031 return ext4_journal_get_write_access(handle, ent->dir_bh);
3032}
3033
3034static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent,
3035 unsigned dir_ino)
3036{
3037 int retval;
3038
3039 ent->parent_de->inode = cpu_to_le32(dir_ino);
3040 BUFFER_TRACE(ent->dir_bh, "call ext4_handle_dirty_metadata");
3041 if (!ent->dir_inlined) {
3042 if (is_dx(ent->inode)) {
3043 retval = ext4_handle_dirty_dx_node(handle,
3044 ent->inode,
3045 ent->dir_bh);
3046 } else {
3047 retval = ext4_handle_dirty_dirent_node(handle,
3048 ent->inode,
3049 ent->dir_bh);
3050 }
3051 } else {
3052 retval = ext4_mark_inode_dirty(handle, ent->inode);
3053 }
3054 if (retval) {
3055 ext4_std_error(ent->dir->i_sb, retval);
3056 return retval;
3057 }
3058 return 0;
3059}
3060
3061static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
3062 unsigned ino, unsigned file_type)
3063{
3064 int retval;
3065
3066 BUFFER_TRACE(ent->bh, "get write access");
3067 retval = ext4_journal_get_write_access(handle, ent->bh);
3068 if (retval)
3069 return retval;
3070 ent->de->inode = cpu_to_le32(ino);
3071 if (EXT4_HAS_INCOMPAT_FEATURE(ent->dir->i_sb,
3072 EXT4_FEATURE_INCOMPAT_FILETYPE))
3073 ent->de->file_type = file_type;
3074 ent->dir->i_version++;
3075 ent->dir->i_ctime = ent->dir->i_mtime =
3076 ext4_current_time(ent->dir);
3077 ext4_mark_inode_dirty(handle, ent->dir);
3078 BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata");
3079 if (!ent->inlined) {
3080 retval = ext4_handle_dirty_dirent_node(handle,
3081 ent->dir, ent->bh);
3082 if (unlikely(retval)) {
3083 ext4_std_error(ent->dir->i_sb, retval);
3084 return retval;
3085 }
3086 }
3087 brelse(ent->bh);
3088 ent->bh = NULL;
3089
3090 return 0;
3091}
3092
3093static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
3094 const struct qstr *d_name)
3095{
3096 int retval = -ENOENT;
3097 struct buffer_head *bh;
3098 struct ext4_dir_entry_2 *de;
3099
3100 bh = ext4_find_entry(dir, d_name, &de, NULL);
3101 if (bh) {
3102 retval = ext4_delete_entry(handle, dir, de, bh);
3103 brelse(bh);
3104 }
3105 return retval;
3106}
3107
3108static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
3109{
3110 int retval;
3111 /*
3112 * ent->de could have moved from under us during htree split, so make
3113 * sure that we are deleting the right entry. We might also be pointing
3114 * to a stale entry in the unused part of ent->bh so just checking inum
3115 * and the name isn't enough.
3116 */
3117 if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino ||
3118 ent->de->name_len != ent->dentry->d_name.len ||
3119 strncmp(ent->de->name, ent->dentry->d_name.name,
3120 ent->de->name_len)) {
3121 retval = ext4_find_delete_entry(handle, ent->dir,
3122 &ent->dentry->d_name);
3123 } else {
3124 retval = ext4_delete_entry(handle, ent->dir, ent->de, ent->bh);
3125 if (retval == -ENOENT) {
3126 retval = ext4_find_delete_entry(handle, ent->dir,
3127 &ent->dentry->d_name);
3128 }
3129 }
3130
3131 if (retval) {
3132 ext4_warning(ent->dir->i_sb,
3133 "Deleting old file (%lu), %d, error=%d",
3134 ent->dir->i_ino, ent->dir->i_nlink, retval);
3135 }
3136}
3137
3019/* 3138/*
3020 * Anybody can rename anything with this: the permission checks are left to the 3139 * Anybody can rename anything with this: the permission checks are left to the
3021 * higher-level routines. 3140 * higher-level routines.
@@ -3089,16 +3208,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3089 if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir)) 3208 if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir))
3090 goto end_rename; 3209 goto end_rename;
3091 } 3210 }
3092 retval = -EIO; 3211 retval = ext4_rename_dir_prepare(handle, &old);
3093 old.dir_bh = ext4_get_first_dir_block(handle, old.inode,
3094 &retval, &old.parent_de,
3095 &old.dir_inlined);
3096 if (!old.dir_bh)
3097 goto end_rename;
3098 if (le32_to_cpu(old.parent_de->inode) != old.dir->i_ino)
3099 goto end_rename;
3100 BUFFER_TRACE(old.dir_bh, "get_write_access");
3101 retval = ext4_journal_get_write_access(handle, old.dir_bh);
3102 if (retval) 3212 if (retval)
3103 goto end_rename; 3213 goto end_rename;
3104 } 3214 }
@@ -3107,29 +3217,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3107 if (retval) 3217 if (retval)
3108 goto end_rename; 3218 goto end_rename;
3109 } else { 3219 } else {
3110 BUFFER_TRACE(new.bh, "get write access"); 3220 retval = ext4_setent(handle, &new,
3111 retval = ext4_journal_get_write_access(handle, new.bh); 3221 old.inode->i_ino, old.de->file_type);
3112 if (retval) 3222 if (retval)
3113 goto end_rename; 3223 goto end_rename;
3114 new.de->inode = cpu_to_le32(old.inode->i_ino);
3115 if (EXT4_HAS_INCOMPAT_FEATURE(new.dir->i_sb,
3116 EXT4_FEATURE_INCOMPAT_FILETYPE))
3117 new.de->file_type = old.de->file_type;
3118 new.dir->i_version++;
3119 new.dir->i_ctime = new.dir->i_mtime =
3120 ext4_current_time(new.dir);
3121 ext4_mark_inode_dirty(handle, new.dir);
3122 BUFFER_TRACE(new.bh, "call ext4_handle_dirty_metadata");
3123 if (!new.inlined) {
3124 retval = ext4_handle_dirty_dirent_node(handle,
3125 new.dir, new.bh);
3126 if (unlikely(retval)) {
3127 ext4_std_error(new.dir->i_sb, retval);
3128 goto end_rename;
3129 }
3130 }
3131 brelse(new.bh);
3132 new.bh = NULL;
3133 } 3224 }
3134 3225
3135 /* 3226 /*
@@ -3142,31 +3233,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3142 /* 3233 /*
3143 * ok, that's it 3234 * ok, that's it
3144 */ 3235 */
3145 if (le32_to_cpu(old.de->inode) != old.inode->i_ino || 3236 ext4_rename_delete(handle, &old);
3146 old.de->name_len != old.dentry->d_name.len ||
3147 strncmp(old.de->name, old.dentry->d_name.name, old.de->name_len) ||
3148 (retval = ext4_delete_entry(handle, old.dir,
3149 old.de, old.bh)) == -ENOENT) {
3150 /* old.de could have moved from under us during htree split, so
3151 * make sure that we are deleting the right entry. We might
3152 * also be pointing to a stale entry in the unused part of
3153 * old.bh so just checking inum and the name isn't enough. */
3154 struct buffer_head *old_bh2;
3155 struct ext4_dir_entry_2 *old_de2;
3156
3157 old_bh2 = ext4_find_entry(old.dir, &old.dentry->d_name,
3158 &old_de2, NULL);
3159 if (old_bh2) {
3160 retval = ext4_delete_entry(handle, old.dir,
3161 old_de2, old_bh2);
3162 brelse(old_bh2);
3163 }
3164 }
3165 if (retval) {
3166 ext4_warning(old.dir->i_sb,
3167 "Deleting old file (%lu), %d, error=%d",
3168 old.dir->i_ino, old.dir->i_nlink, retval);
3169 }
3170 3237
3171 if (new.inode) { 3238 if (new.inode) {
3172 ext4_dec_count(handle, new.inode); 3239 ext4_dec_count(handle, new.inode);
@@ -3175,24 +3242,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3175 old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir); 3242 old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir);
3176 ext4_update_dx_flag(old.dir); 3243 ext4_update_dx_flag(old.dir);
3177 if (old.dir_bh) { 3244 if (old.dir_bh) {
3178 old.parent_de->inode = cpu_to_le32(new.dir->i_ino); 3245 retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
3179 BUFFER_TRACE(old.dir_bh, "call ext4_handle_dirty_metadata"); 3246 if (retval)
3180 if (!old.dir_inlined) {
3181 if (is_dx(old.inode)) {
3182 retval = ext4_handle_dirty_dx_node(handle,
3183 old.inode,
3184 old.dir_bh);
3185 } else {
3186 retval = ext4_handle_dirty_dirent_node(handle,
3187 old.inode, old.dir_bh);
3188 }
3189 } else {
3190 retval = ext4_mark_inode_dirty(handle, old.inode);
3191 }
3192 if (retval) {
3193 ext4_std_error(old.dir->i_sb, retval);
3194 goto end_rename; 3247 goto end_rename;
3195 } 3248
3196 ext4_dec_count(handle, old.dir); 3249 ext4_dec_count(handle, old.dir);
3197 if (new.inode) { 3250 if (new.inode) {
3198 /* checked empty_dir above, can't have another parent, 3251 /* checked empty_dir above, can't have another parent,