Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: convert inline_dir early before starting rename

If we hit an error during rename, we'll get two dentries in different
directories.

Chao adds to check the room in inline_dir which can avoid needless
inversion. This should be done by inode_lock(&old_dir).

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

+71 -25
+14
fs/f2fs/dir.c
··· 578 578 goto next; 579 579 } 580 580 581 + bool f2fs_has_enough_room(struct inode *dir, struct page *ipage, 582 + struct fscrypt_name *fname) 583 + { 584 + struct f2fs_dentry_ptr d; 585 + unsigned int bit_pos; 586 + int slots = GET_DENTRY_SLOTS(fname_len(fname)); 587 + 588 + make_dentry_ptr_inline(dir, &d, inline_data_addr(dir, ipage)); 589 + 590 + bit_pos = f2fs_room_for_filename(d.bitmap, slots, d.max); 591 + 592 + return bit_pos < d.max; 593 + } 594 + 581 595 void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, 582 596 const struct qstr *name, f2fs_hash_t name_hash, 583 597 unsigned int bit_pos)
+3
fs/f2fs/f2fs.h
··· 3107 3107 struct page **page); 3108 3108 void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, 3109 3109 struct page *page, struct inode *inode); 3110 + bool f2fs_has_enough_room(struct inode *dir, struct page *ipage, 3111 + struct fscrypt_name *fname); 3110 3112 void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d, 3111 3113 const struct qstr *name, f2fs_hash_t name_hash, 3112 3114 unsigned int bit_pos); ··· 3651 3649 int f2fs_read_inline_data(struct inode *inode, struct page *page); 3652 3650 int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page); 3653 3651 int f2fs_convert_inline_inode(struct inode *inode); 3652 + int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry); 3654 3653 int f2fs_write_inline_data(struct inode *inode, struct page *page); 3655 3654 bool f2fs_recover_inline_data(struct inode *inode, struct page *npage); 3656 3655 struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
+40 -2
fs/f2fs/inline.c
··· 530 530 return err; 531 531 } 532 532 533 - static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, 533 + static int do_convert_inline_dir(struct inode *dir, struct page *ipage, 534 534 void *inline_dentry) 535 535 { 536 536 if (!F2FS_I(dir)->i_dir_level) 537 537 return f2fs_move_inline_dirents(dir, ipage, inline_dentry); 538 538 else 539 539 return f2fs_move_rehashed_dirents(dir, ipage, inline_dentry); 540 + } 541 + 542 + int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry) 543 + { 544 + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); 545 + struct page *ipage; 546 + struct fscrypt_name fname; 547 + void *inline_dentry = NULL; 548 + int err = 0; 549 + 550 + if (!f2fs_has_inline_dentry(dir)) 551 + return 0; 552 + 553 + f2fs_lock_op(sbi); 554 + 555 + err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &fname); 556 + if (err) 557 + goto out; 558 + 559 + ipage = f2fs_get_node_page(sbi, dir->i_ino); 560 + if (IS_ERR(ipage)) { 561 + err = PTR_ERR(ipage); 562 + goto out; 563 + } 564 + 565 + if (f2fs_has_enough_room(dir, ipage, &fname)) { 566 + f2fs_put_page(ipage, 1); 567 + goto out; 568 + } 569 + 570 + inline_dentry = inline_data_addr(dir, ipage); 571 + 572 + err = do_convert_inline_dir(dir, ipage, inline_dentry); 573 + if (!err) 574 + f2fs_put_page(ipage, 1); 575 + out: 576 + f2fs_unlock_op(sbi); 577 + return err; 540 578 } 541 579 542 580 int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, ··· 600 562 601 563 bit_pos = f2fs_room_for_filename(d.bitmap, slots, d.max); 602 564 if (bit_pos >= d.max) { 603 - err = f2fs_convert_inline_dir(dir, ipage, inline_dentry); 565 + err = do_convert_inline_dir(dir, ipage, inline_dentry); 604 566 if (err) 605 567 return err; 606 568 err = -EAGAIN;
+14 -23
fs/f2fs/namei.c
··· 906 906 struct f2fs_dir_entry *old_dir_entry = NULL; 907 907 struct f2fs_dir_entry *old_entry; 908 908 struct f2fs_dir_entry *new_entry; 909 - bool is_old_inline = f2fs_has_inline_dentry(old_dir); 910 909 int err; 911 910 912 911 if (unlikely(f2fs_cp_error(sbi))) ··· 917 918 (!projid_eq(F2FS_I(new_dir)->i_projid, 918 919 F2FS_I(old_dentry->d_inode)->i_projid))) 919 920 return -EXDEV; 921 + 922 + /* 923 + * If new_inode is null, the below renaming flow will 924 + * add a link in old_dir which can conver inline_dir. 925 + * After then, if we failed to get the entry due to other 926 + * reasons like ENOMEM, we had to remove the new entry. 927 + * Instead of adding such the error handling routine, let's 928 + * simply convert first here. 929 + */ 930 + if (old_dir == new_dir && !new_inode) { 931 + err = f2fs_try_convert_inline_dir(old_dir, new_dentry); 932 + if (err) 933 + return err; 934 + } 920 935 921 936 if (flags & RENAME_WHITEOUT) { 922 937 err = f2fs_create_whiteout(old_dir, &whiteout); ··· 1019 1006 1020 1007 if (old_dir_entry) 1021 1008 f2fs_i_links_write(new_dir, true); 1022 - 1023 - /* 1024 - * old entry and new entry can locate in the same inline 1025 - * dentry in inode, when attaching new entry in inline dentry, 1026 - * it could force inline dentry conversion, after that, 1027 - * old_entry and old_page will point to wrong address, in 1028 - * order to avoid this, let's do the check and update here. 1029 - */ 1030 - if (is_old_inline && !f2fs_has_inline_dentry(old_dir)) { 1031 - f2fs_put_page(old_page, 0); 1032 - old_page = NULL; 1033 - 1034 - old_entry = f2fs_find_entry(old_dir, 1035 - &old_dentry->d_name, &old_page); 1036 - if (!old_entry) { 1037 - err = -ENOENT; 1038 - if (IS_ERR(old_page)) 1039 - err = PTR_ERR(old_page); 1040 - f2fs_unlock_op(sbi); 1041 - goto out_dir; 1042 - } 1043 - } 1044 1009 } 1045 1010 1046 1011 down_write(&F2FS_I(old_inode)->i_sem);