aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/namei.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index ae7088b446d1..90a3cdca3f88 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3147,7 +3147,8 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
3147 return retval; 3147 return retval;
3148} 3148}
3149 3149
3150static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent) 3150static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent,
3151 int force_reread)
3151{ 3152{
3152 int retval; 3153 int retval;
3153 /* 3154 /*
@@ -3159,7 +3160,8 @@ static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
3159 if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino || 3160 if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino ||
3160 ent->de->name_len != ent->dentry->d_name.len || 3161 ent->de->name_len != ent->dentry->d_name.len ||
3161 strncmp(ent->de->name, ent->dentry->d_name.name, 3162 strncmp(ent->de->name, ent->dentry->d_name.name,
3162 ent->de->name_len)) { 3163 ent->de->name_len) ||
3164 force_reread) {
3163 retval = ext4_find_delete_entry(handle, ent->dir, 3165 retval = ext4_find_delete_entry(handle, ent->dir,
3164 &ent->dentry->d_name); 3166 &ent->dentry->d_name);
3165 } else { 3167 } else {
@@ -3210,6 +3212,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3210 .dentry = new_dentry, 3212 .dentry = new_dentry,
3211 .inode = new_dentry->d_inode, 3213 .inode = new_dentry->d_inode,
3212 }; 3214 };
3215 int force_reread;
3213 int retval; 3216 int retval;
3214 3217
3215 dquot_initialize(old.dir); 3218 dquot_initialize(old.dir);
@@ -3271,6 +3274,15 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3271 if (retval) 3274 if (retval)
3272 goto end_rename; 3275 goto end_rename;
3273 } 3276 }
3277 /*
3278 * If we're renaming a file within an inline_data dir and adding or
3279 * setting the new dirent causes a conversion from inline_data to
3280 * extents/blockmap, we need to force the dirent delete code to
3281 * re-read the directory, or else we end up trying to delete a dirent
3282 * from what is now the extent tree root (or a block map).
3283 */
3284 force_reread = (new.dir->i_ino == old.dir->i_ino &&
3285 ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));
3274 if (!new.bh) { 3286 if (!new.bh) {
3275 retval = ext4_add_entry(handle, new.dentry, old.inode); 3287 retval = ext4_add_entry(handle, new.dentry, old.inode);
3276 if (retval) 3288 if (retval)
@@ -3281,6 +3293,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3281 if (retval) 3293 if (retval)
3282 goto end_rename; 3294 goto end_rename;
3283 } 3295 }
3296 if (force_reread)
3297 force_reread = !ext4_test_inode_flag(new.dir,
3298 EXT4_INODE_INLINE_DATA);
3284 3299
3285 /* 3300 /*
3286 * Like most other Unix systems, set the ctime for inodes on a 3301 * Like most other Unix systems, set the ctime for inodes on a
@@ -3292,7 +3307,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3292 /* 3307 /*
3293 * ok, that's it 3308 * ok, that's it
3294 */ 3309 */
3295 ext4_rename_delete(handle, &old); 3310 ext4_rename_delete(handle, &old, force_reread);
3296 3311
3297 if (new.inode) { 3312 if (new.inode) {
3298 ext4_dec_count(handle, new.inode); 3313 ext4_dec_count(handle, new.inode);