Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7e01e7a

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: support RENAME_WHITEOUT
As the description of rename in manual, RENAME_WHITEOUT is a special operation that only makes sense for overlay/union type filesystem. When performing rename with RENAME_WHITEOUT, dst will be replace with src, and meanwhile, a 'whiteout' will be create with name of src. A "whiteout" is designed to be a char device with 0,0 device number, it has specially meaning for stackable filesystem. In these filesystems, there are multiple layers exist, and only top of these can be modified. So a whiteout in top layer is used to hide a corresponding file in lower layer, as well removal of whiteout will make the file appear. Now in overlayfs, when we rename a file which is exist in lower layer, it will be copied up to upper if it is not on upper layer yet, and then rename it on upper layer, source file will be whiteouted to hide corresponding file in lower layer at the same time. So in upper layer filesystem, implementation of RENAME_WHITEOUT provide a atomic operation for stackable filesystem to support rename operation. There are multiple ways to implement RENAME_WHITEOUT in log of this commit: 7dcf5c3 ("xfs: add RENAME_WHITEOUT support") which pointed out by Dave Chinner. For now, we just try to follow the way that xfs/ext4 use. Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 381722d commit 7e01e7a

File tree

1 file changed

+100
-53
lines changed

1 file changed

+100
-53
lines changed

fs/f2fs/namei.c

Lines changed: 100 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -510,14 +510,83 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
510510
return err;
511511
}
512512

513+
static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
514+
umode_t mode, struct inode **whiteout)
515+
{
516+
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
517+
struct inode *inode;
518+
int err;
519+
520+
if (!whiteout)
521+
f2fs_balance_fs(sbi);
522+
523+
inode = f2fs_new_inode(dir, mode);
524+
if (IS_ERR(inode))
525+
return PTR_ERR(inode);
526+
527+
if (whiteout) {
528+
init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
529+
inode->i_op = &f2fs_special_inode_operations;
530+
} else {
531+
inode->i_op = &f2fs_file_inode_operations;
532+
inode->i_fop = &f2fs_file_operations;
533+
inode->i_mapping->a_ops = &f2fs_dblock_aops;
534+
}
535+
536+
f2fs_lock_op(sbi);
537+
err = acquire_orphan_inode(sbi);
538+
if (err)
539+
goto out;
540+
541+
err = f2fs_do_tmpfile(inode, dir);
542+
if (err)
543+
goto release_out;
544+
545+
/*
546+
* add this non-linked tmpfile to orphan list, in this way we could
547+
* remove all unused data of tmpfile after abnormal power-off.
548+
*/
549+
add_orphan_inode(sbi, inode->i_ino);
550+
f2fs_unlock_op(sbi);
551+
552+
alloc_nid_done(sbi, inode->i_ino);
553+
554+
if (whiteout) {
555+
inode_dec_link_count(inode);
556+
*whiteout = inode;
557+
} else {
558+
d_tmpfile(dentry, inode);
559+
}
560+
unlock_new_inode(inode);
561+
return 0;
562+
563+
release_out:
564+
release_orphan_inode(sbi);
565+
out:
566+
handle_failed_inode(inode);
567+
return err;
568+
}
569+
570+
static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
571+
{
572+
return __f2fs_tmpfile(dir, dentry, mode, NULL);
573+
}
574+
575+
static int f2fs_create_whiteout(struct inode *dir, struct inode **whiteout)
576+
{
577+
return __f2fs_tmpfile(dir, NULL, S_IFCHR | WHITEOUT_MODE, whiteout);
578+
}
579+
513580
static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
514-
struct inode *new_dir, struct dentry *new_dentry)
581+
struct inode *new_dir, struct dentry *new_dentry,
582+
unsigned int flags)
515583
{
516584
struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);
517585
struct inode *old_inode = d_inode(old_dentry);
518586
struct inode *new_inode = d_inode(new_dentry);
587+
struct inode *whiteout = NULL;
519588
struct page *old_dir_page;
520-
struct page *old_page, *new_page;
589+
struct page *old_page, *new_page = NULL;
521590
struct f2fs_dir_entry *old_dir_entry = NULL;
522591
struct f2fs_dir_entry *old_entry;
523592
struct f2fs_dir_entry *new_entry;
@@ -543,17 +612,23 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
543612
goto out_old;
544613
}
545614

615+
if (flags & RENAME_WHITEOUT) {
616+
err = f2fs_create_whiteout(old_dir, &whiteout);
617+
if (err)
618+
goto out_dir;
619+
}
620+
546621
if (new_inode) {
547622

548623
err = -ENOTEMPTY;
549624
if (old_dir_entry && !f2fs_empty_dir(new_inode))
550-
goto out_dir;
625+
goto out_whiteout;
551626

552627
err = -ENOENT;
553628
new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
554629
&new_page);
555630
if (!new_entry)
556-
goto out_dir;
631+
goto out_whiteout;
557632

558633
f2fs_lock_op(sbi);
559634

@@ -591,7 +666,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
591666
err = f2fs_add_link(new_dentry, old_inode);
592667
if (err) {
593668
f2fs_unlock_op(sbi);
594-
goto out_dir;
669+
goto out_whiteout;
595670
}
596671

597672
if (old_dir_entry) {
@@ -611,8 +686,18 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
611686

612687
f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
613688

689+
if (whiteout) {
690+
whiteout->i_state |= I_LINKABLE;
691+
set_inode_flag(F2FS_I(whiteout), FI_INC_LINK);
692+
err = f2fs_add_link(old_dentry, whiteout);
693+
if (err)
694+
goto put_out_dir;
695+
whiteout->i_state &= ~I_LINKABLE;
696+
iput(whiteout);
697+
}
698+
614699
if (old_dir_entry) {
615-
if (old_dir != new_dir) {
700+
if (old_dir != new_dir && !whiteout) {
616701
f2fs_set_link(old_inode, old_dir_entry,
617702
old_dir_page, new_dir);
618703
update_inode_page(old_inode);
@@ -633,8 +718,13 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
633718

634719
put_out_dir:
635720
f2fs_unlock_op(sbi);
636-
f2fs_dentry_kunmap(new_dir, new_page);
637-
f2fs_put_page(new_page, 0);
721+
if (new_page) {
722+
f2fs_dentry_kunmap(new_dir, new_page);
723+
f2fs_put_page(new_page, 0);
724+
}
725+
out_whiteout:
726+
if (whiteout)
727+
iput(whiteout);
638728
out_dir:
639729
if (old_dir_entry) {
640730
f2fs_dentry_kunmap(old_inode, old_dir_page);
@@ -805,7 +895,7 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
805895
struct inode *new_dir, struct dentry *new_dentry,
806896
unsigned int flags)
807897
{
808-
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
898+
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
809899
return -EINVAL;
810900

811901
if (flags & RENAME_EXCHANGE) {
@@ -816,50 +906,7 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
816906
* VFS has already handled the new dentry existence case,
817907
* here, we just deal with "RENAME_NOREPLACE" as regular rename.
818908
*/
819-
return f2fs_rename(old_dir, old_dentry, new_dir, new_dentry);
820-
}
821-
822-
static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
823-
{
824-
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
825-
struct inode *inode;
826-
int err;
827-
828-
inode = f2fs_new_inode(dir, mode);
829-
if (IS_ERR(inode))
830-
return PTR_ERR(inode);
831-
832-
inode->i_op = &f2fs_file_inode_operations;
833-
inode->i_fop = &f2fs_file_operations;
834-
inode->i_mapping->a_ops = &f2fs_dblock_aops;
835-
836-
f2fs_lock_op(sbi);
837-
err = acquire_orphan_inode(sbi);
838-
if (err)
839-
goto out;
840-
841-
err = f2fs_do_tmpfile(inode, dir);
842-
if (err)
843-
goto release_out;
844-
845-
/*
846-
* add this non-linked tmpfile to orphan list, in this way we could
847-
* remove all unused data of tmpfile after abnormal power-off.
848-
*/
849-
add_orphan_inode(sbi, inode->i_ino);
850-
f2fs_unlock_op(sbi);
851-
852-
alloc_nid_done(sbi, inode->i_ino);
853-
854-
d_tmpfile(dentry, inode);
855-
unlock_new_inode(inode);
856-
return 0;
857-
858-
release_out:
859-
release_orphan_inode(sbi);
860-
out:
861-
handle_failed_inode(inode);
862-
return err;
909+
return f2fs_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
863910
}
864911

865912
#ifdef CONFIG_F2FS_FS_ENCRYPTION

0 commit comments

Comments
 (0)