aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/namei.c95
1 files changed, 78 insertions, 17 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 603e4ebbd0ac..aba86e8ef1ef 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3190,6 +3190,39 @@ static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent)
3190 } 3190 }
3191} 3191}
3192 3192
3193static struct inode *ext4_whiteout_for_rename(struct ext4_renament *ent,
3194 int credits, handle_t **h)
3195{
3196 struct inode *wh;
3197 handle_t *handle;
3198 int retries = 0;
3199
3200 /*
3201 * for inode block, sb block, group summaries,
3202 * and inode bitmap
3203 */
3204 credits += (EXT4_MAXQUOTAS_TRANS_BLOCKS(ent->dir->i_sb) +
3205 EXT4_XATTR_TRANS_BLOCKS + 4);
3206retry:
3207 wh = ext4_new_inode_start_handle(ent->dir, S_IFCHR | WHITEOUT_MODE,
3208 &ent->dentry->d_name, 0, NULL,
3209 EXT4_HT_DIR, credits);
3210
3211 handle = ext4_journal_current_handle();
3212 if (IS_ERR(wh)) {
3213 if (handle)
3214 ext4_journal_stop(handle);
3215 if (PTR_ERR(wh) == -ENOSPC &&
3216 ext4_should_retry_alloc(ent->dir->i_sb, &retries))
3217 goto retry;
3218 } else {
3219 *h = handle;
3220 init_special_inode(wh, wh->i_mode, WHITEOUT_DEV);
3221 wh->i_op = &ext4_special_inode_operations;
3222 }
3223 return wh;
3224}
3225
3193/* 3226/*
3194 * Anybody can rename anything with this: the permission checks are left to the 3227 * Anybody can rename anything with this: the permission checks are left to the
3195 * higher-level routines. 3228 * higher-level routines.
@@ -3199,7 +3232,8 @@ static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent)
3199 * This comes from rename(const char *oldpath, const char *newpath) 3232 * This comes from rename(const char *oldpath, const char *newpath)
3200 */ 3233 */
3201static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, 3234static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3202 struct inode *new_dir, struct dentry *new_dentry) 3235 struct inode *new_dir, struct dentry *new_dentry,
3236 unsigned int flags)
3203{ 3237{
3204 handle_t *handle = NULL; 3238 handle_t *handle = NULL;
3205 struct ext4_renament old = { 3239 struct ext4_renament old = {
@@ -3214,6 +3248,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3214 }; 3248 };
3215 int force_reread; 3249 int force_reread;
3216 int retval; 3250 int retval;
3251 struct inode *whiteout = NULL;
3252 int credits;
3253 u8 old_file_type;
3217 3254
3218 dquot_initialize(old.dir); 3255 dquot_initialize(old.dir);
3219 dquot_initialize(new.dir); 3256 dquot_initialize(new.dir);
@@ -3252,11 +3289,17 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3252 if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) 3289 if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC))
3253 ext4_alloc_da_blocks(old.inode); 3290 ext4_alloc_da_blocks(old.inode);
3254 3291
3255 handle = ext4_journal_start(old.dir, EXT4_HT_DIR, 3292 credits = (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) +
3256 (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + 3293 EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2);
3257 EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); 3294 if (!(flags & RENAME_WHITEOUT)) {
3258 if (IS_ERR(handle)) 3295 handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits);
3259 return PTR_ERR(handle); 3296 if (IS_ERR(handle))
3297 return PTR_ERR(handle);
3298 } else {
3299 whiteout = ext4_whiteout_for_rename(&old, credits, &handle);
3300 if (IS_ERR(whiteout))
3301 return PTR_ERR(whiteout);
3302 }
3260 3303
3261 if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) 3304 if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir))
3262 ext4_handle_sync(handle); 3305 ext4_handle_sync(handle);
@@ -3284,13 +3327,26 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3284 */ 3327 */
3285 force_reread = (new.dir->i_ino == old.dir->i_ino && 3328 force_reread = (new.dir->i_ino == old.dir->i_ino &&
3286 ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); 3329 ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));
3330
3331 old_file_type = old.de->file_type;
3332 if (whiteout) {
3333 /*
3334 * Do this before adding a new entry, so the old entry is sure
3335 * to be still pointing to the valid old entry.
3336 */
3337 retval = ext4_setent(handle, &old, whiteout->i_ino,
3338 EXT4_FT_CHRDEV);
3339 if (retval)
3340 goto end_rename;
3341 ext4_mark_inode_dirty(handle, whiteout);
3342 }
3287 if (!new.bh) { 3343 if (!new.bh) {
3288 retval = ext4_add_entry(handle, new.dentry, old.inode); 3344 retval = ext4_add_entry(handle, new.dentry, old.inode);
3289 if (retval) 3345 if (retval)
3290 goto end_rename; 3346 goto end_rename;
3291 } else { 3347 } else {
3292 retval = ext4_setent(handle, &new, 3348 retval = ext4_setent(handle, &new,
3293 old.inode->i_ino, old.de->file_type); 3349 old.inode->i_ino, old_file_type);
3294 if (retval) 3350 if (retval)
3295 goto end_rename; 3351 goto end_rename;
3296 } 3352 }
@@ -3305,10 +3361,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
3305 old.inode->i_ctime = ext4_current_time(old.inode); 3361 old.inode->i_ctime = ext4_current_time(old.inode);
3306 ext4_mark_inode_dirty(handle, old.inode); 3362 ext4_mark_inode_dirty(handle, old.inode);
3307 3363
3308 /* 3364 if (!whiteout) {
3309 * ok, that's it 3365 /*
3310 */ 3366 * ok, that's it
3311 ext4_rename_delete(handle, &old, force_reread); 3367 */
3368 ext4_rename_delete(handle, &old, force_reread);
3369 }
3312 3370
3313 if (new.inode) { 3371 if (new.inode) {
3314 ext4_dec_count(handle, new.inode); 3372 ext4_dec_count(handle, new.inode);
@@ -3344,6 +3402,12 @@ end_rename:
3344 brelse(old.dir_bh); 3402 brelse(old.dir_bh);
3345 brelse(old.bh); 3403 brelse(old.bh);
3346 brelse(new.bh); 3404 brelse(new.bh);
3405 if (whiteout) {
3406 if (retval)
3407 drop_nlink(whiteout);
3408 unlock_new_inode(whiteout);
3409 iput(whiteout);
3410 }
3347 if (handle) 3411 if (handle)
3348 ext4_journal_stop(handle); 3412 ext4_journal_stop(handle);
3349 return retval; 3413 return retval;
@@ -3476,18 +3540,15 @@ static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry,
3476 struct inode *new_dir, struct dentry *new_dentry, 3540 struct inode *new_dir, struct dentry *new_dentry,
3477 unsigned int flags) 3541 unsigned int flags)
3478{ 3542{
3479 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) 3543 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
3480 return -EINVAL; 3544 return -EINVAL;
3481 3545
3482 if (flags & RENAME_EXCHANGE) { 3546 if (flags & RENAME_EXCHANGE) {
3483 return ext4_cross_rename(old_dir, old_dentry, 3547 return ext4_cross_rename(old_dir, old_dentry,
3484 new_dir, new_dentry); 3548 new_dir, new_dentry);
3485 } 3549 }
3486 /* 3550
3487 * Existence checking was done by the VFS, otherwise "RENAME_NOREPLACE" 3551 return ext4_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
3488 * is equivalent to regular rename.
3489 */
3490 return ext4_rename(old_dir, old_dentry, new_dir, new_dentry);
3491} 3552}
3492 3553
3493/* 3554/*