diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-26 14:19:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-26 14:19:18 -0400 |
commit | d1e14f1d63eb15ebe97d1a8544ddc143486b0204 (patch) | |
tree | a73e7c751f23835483f1e8029d04547192611975 /fs/ext4 | |
parent | 2cc91884b6b3f7328680b8ea7563016d3aee3d19 (diff) | |
parent | db6ec212b53abc29a5bb6ac8c810010fc28d5191 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs updates from Al Viro:
"overlayfs merge + leak fix for d_splice_alias() failure exits"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
overlayfs: embed middle into overlay_readdir_data
overlayfs: embed root into overlay_readdir_data
overlayfs: make ovl_cache_entry->name an array instead of pointer
overlayfs: don't hold ->i_mutex over opening the real directory
fix inode leaks on d_splice_alias() failure exits
fs: limit filesystem stacking depth
overlay: overlay filesystem documentation
overlayfs: implement show_options
overlayfs: add statfs support
overlay filesystem
shmem: support RENAME_WHITEOUT
ext4: support RENAME_WHITEOUT
vfs: add RENAME_WHITEOUT
vfs: add whiteout support
vfs: export check_sticky()
vfs: introduce clone_private_mount()
vfs: export __inode_permission() to modules
vfs: export do_splice_direct() to modules
vfs: add i_op->dentry_open()
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/namei.c | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index adb559de23c1..123798c5ac31 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -3148,6 +3148,39 @@ static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent) | |||
3148 | } | 3148 | } |
3149 | } | 3149 | } |
3150 | 3150 | ||
3151 | static struct inode *ext4_whiteout_for_rename(struct ext4_renament *ent, | ||
3152 | int credits, handle_t **h) | ||
3153 | { | ||
3154 | struct inode *wh; | ||
3155 | handle_t *handle; | ||
3156 | int retries = 0; | ||
3157 | |||
3158 | /* | ||
3159 | * for inode block, sb block, group summaries, | ||
3160 | * and inode bitmap | ||
3161 | */ | ||
3162 | credits += (EXT4_MAXQUOTAS_TRANS_BLOCKS(ent->dir->i_sb) + | ||
3163 | EXT4_XATTR_TRANS_BLOCKS + 4); | ||
3164 | retry: | ||
3165 | wh = ext4_new_inode_start_handle(ent->dir, S_IFCHR | WHITEOUT_MODE, | ||
3166 | &ent->dentry->d_name, 0, NULL, | ||
3167 | EXT4_HT_DIR, credits); | ||
3168 | |||
3169 | handle = ext4_journal_current_handle(); | ||
3170 | if (IS_ERR(wh)) { | ||
3171 | if (handle) | ||
3172 | ext4_journal_stop(handle); | ||
3173 | if (PTR_ERR(wh) == -ENOSPC && | ||
3174 | ext4_should_retry_alloc(ent->dir->i_sb, &retries)) | ||
3175 | goto retry; | ||
3176 | } else { | ||
3177 | *h = handle; | ||
3178 | init_special_inode(wh, wh->i_mode, WHITEOUT_DEV); | ||
3179 | wh->i_op = &ext4_special_inode_operations; | ||
3180 | } | ||
3181 | return wh; | ||
3182 | } | ||
3183 | |||
3151 | /* | 3184 | /* |
3152 | * Anybody can rename anything with this: the permission checks are left to the | 3185 | * Anybody can rename anything with this: the permission checks are left to the |
3153 | * higher-level routines. | 3186 | * higher-level routines. |
@@ -3157,7 +3190,8 @@ static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent) | |||
3157 | * This comes from rename(const char *oldpath, const char *newpath) | 3190 | * This comes from rename(const char *oldpath, const char *newpath) |
3158 | */ | 3191 | */ |
3159 | static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | 3192 | static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, |
3160 | struct inode *new_dir, struct dentry *new_dentry) | 3193 | struct inode *new_dir, struct dentry *new_dentry, |
3194 | unsigned int flags) | ||
3161 | { | 3195 | { |
3162 | handle_t *handle = NULL; | 3196 | handle_t *handle = NULL; |
3163 | struct ext4_renament old = { | 3197 | struct ext4_renament old = { |
@@ -3172,6 +3206,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3172 | }; | 3206 | }; |
3173 | int force_reread; | 3207 | int force_reread; |
3174 | int retval; | 3208 | int retval; |
3209 | struct inode *whiteout = NULL; | ||
3210 | int credits; | ||
3211 | u8 old_file_type; | ||
3175 | 3212 | ||
3176 | dquot_initialize(old.dir); | 3213 | dquot_initialize(old.dir); |
3177 | dquot_initialize(new.dir); | 3214 | dquot_initialize(new.dir); |
@@ -3210,11 +3247,17 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3210 | if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) | 3247 | if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) |
3211 | ext4_alloc_da_blocks(old.inode); | 3248 | ext4_alloc_da_blocks(old.inode); |
3212 | 3249 | ||
3213 | handle = ext4_journal_start(old.dir, EXT4_HT_DIR, | 3250 | credits = (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + |
3214 | (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + | 3251 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2); |
3215 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); | 3252 | if (!(flags & RENAME_WHITEOUT)) { |
3216 | if (IS_ERR(handle)) | 3253 | handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits); |
3217 | return PTR_ERR(handle); | 3254 | if (IS_ERR(handle)) |
3255 | return PTR_ERR(handle); | ||
3256 | } else { | ||
3257 | whiteout = ext4_whiteout_for_rename(&old, credits, &handle); | ||
3258 | if (IS_ERR(whiteout)) | ||
3259 | return PTR_ERR(whiteout); | ||
3260 | } | ||
3218 | 3261 | ||
3219 | if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) | 3262 | if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) |
3220 | ext4_handle_sync(handle); | 3263 | ext4_handle_sync(handle); |
@@ -3242,13 +3285,26 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3242 | */ | 3285 | */ |
3243 | force_reread = (new.dir->i_ino == old.dir->i_ino && | 3286 | force_reread = (new.dir->i_ino == old.dir->i_ino && |
3244 | ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); | 3287 | ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); |
3288 | |||
3289 | old_file_type = old.de->file_type; | ||
3290 | if (whiteout) { | ||
3291 | /* | ||
3292 | * Do this before adding a new entry, so the old entry is sure | ||
3293 | * to be still pointing to the valid old entry. | ||
3294 | */ | ||
3295 | retval = ext4_setent(handle, &old, whiteout->i_ino, | ||
3296 | EXT4_FT_CHRDEV); | ||
3297 | if (retval) | ||
3298 | goto end_rename; | ||
3299 | ext4_mark_inode_dirty(handle, whiteout); | ||
3300 | } | ||
3245 | if (!new.bh) { | 3301 | if (!new.bh) { |
3246 | retval = ext4_add_entry(handle, new.dentry, old.inode); | 3302 | retval = ext4_add_entry(handle, new.dentry, old.inode); |
3247 | if (retval) | 3303 | if (retval) |
3248 | goto end_rename; | 3304 | goto end_rename; |
3249 | } else { | 3305 | } else { |
3250 | retval = ext4_setent(handle, &new, | 3306 | retval = ext4_setent(handle, &new, |
3251 | old.inode->i_ino, old.de->file_type); | 3307 | old.inode->i_ino, old_file_type); |
3252 | if (retval) | 3308 | if (retval) |
3253 | goto end_rename; | 3309 | goto end_rename; |
3254 | } | 3310 | } |
@@ -3263,10 +3319,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3263 | old.inode->i_ctime = ext4_current_time(old.inode); | 3319 | old.inode->i_ctime = ext4_current_time(old.inode); |
3264 | ext4_mark_inode_dirty(handle, old.inode); | 3320 | ext4_mark_inode_dirty(handle, old.inode); |
3265 | 3321 | ||
3266 | /* | 3322 | if (!whiteout) { |
3267 | * ok, that's it | 3323 | /* |
3268 | */ | 3324 | * ok, that's it |
3269 | ext4_rename_delete(handle, &old, force_reread); | 3325 | */ |
3326 | ext4_rename_delete(handle, &old, force_reread); | ||
3327 | } | ||
3270 | 3328 | ||
3271 | if (new.inode) { | 3329 | if (new.inode) { |
3272 | ext4_dec_count(handle, new.inode); | 3330 | ext4_dec_count(handle, new.inode); |
@@ -3302,6 +3360,12 @@ end_rename: | |||
3302 | brelse(old.dir_bh); | 3360 | brelse(old.dir_bh); |
3303 | brelse(old.bh); | 3361 | brelse(old.bh); |
3304 | brelse(new.bh); | 3362 | brelse(new.bh); |
3363 | if (whiteout) { | ||
3364 | if (retval) | ||
3365 | drop_nlink(whiteout); | ||
3366 | unlock_new_inode(whiteout); | ||
3367 | iput(whiteout); | ||
3368 | } | ||
3305 | if (handle) | 3369 | if (handle) |
3306 | ext4_journal_stop(handle); | 3370 | ext4_journal_stop(handle); |
3307 | return retval; | 3371 | return retval; |
@@ -3434,18 +3498,15 @@ static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry, | |||
3434 | struct inode *new_dir, struct dentry *new_dentry, | 3498 | struct inode *new_dir, struct dentry *new_dentry, |
3435 | unsigned int flags) | 3499 | unsigned int flags) |
3436 | { | 3500 | { |
3437 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) | 3501 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) |
3438 | return -EINVAL; | 3502 | return -EINVAL; |
3439 | 3503 | ||
3440 | if (flags & RENAME_EXCHANGE) { | 3504 | if (flags & RENAME_EXCHANGE) { |
3441 | return ext4_cross_rename(old_dir, old_dentry, | 3505 | return ext4_cross_rename(old_dir, old_dentry, |
3442 | new_dir, new_dentry); | 3506 | new_dir, new_dentry); |
3443 | } | 3507 | } |
3444 | /* | 3508 | |
3445 | * Existence checking was done by the VFS, otherwise "RENAME_NOREPLACE" | 3509 | return ext4_rename(old_dir, old_dentry, new_dir, new_dentry, flags); |
3446 | * is equivalent to regular rename. | ||
3447 | */ | ||
3448 | return ext4_rename(old_dir, old_dentry, new_dir, new_dentry); | ||
3449 | } | 3510 | } |
3450 | 3511 | ||
3451 | /* | 3512 | /* |