f2fs: add roll-forward recovery process for encrypted dentry
Add roll-forward recovery process for encrypted dentry, so the first fsync issued to an encrypted file does not need writing checkpoint. This improves the performance of the following test at thousands of small files: open -> write -> fsync -> close Signed-off-by: Shuoran Liu <liushuoran@huawei.com> Acked-by: Chao Yu <yuchao0@huawei.com> [Jaegeuk Kim: modify kernel message to show encrypted names] Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Родитель
bbf156f7af
Коммит
e7ba108a06
|
@ -215,31 +215,17 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
|||
return de;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an entry in the specified directory with the wanted name.
|
||||
* It returns the page where the entry was found (as a parameter - res_page),
|
||||
* and the entry itself. Page is returned mapped and unlocked.
|
||||
* Entry is guaranteed to be valid.
|
||||
*/
|
||||
struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
|
||||
const struct qstr *child, struct page **res_page)
|
||||
struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
|
||||
struct fscrypt_name *fname, struct page **res_page)
|
||||
{
|
||||
unsigned long npages = dir_blocks(dir);
|
||||
struct f2fs_dir_entry *de = NULL;
|
||||
unsigned int max_depth;
|
||||
unsigned int level;
|
||||
struct fscrypt_name fname;
|
||||
int err;
|
||||
|
||||
err = fscrypt_setup_filename(dir, child, 1, &fname);
|
||||
if (err) {
|
||||
*res_page = ERR_PTR(err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (f2fs_has_inline_dentry(dir)) {
|
||||
*res_page = NULL;
|
||||
de = find_in_inline_dir(dir, &fname, res_page);
|
||||
de = find_in_inline_dir(dir, fname, res_page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -259,11 +245,35 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
|
|||
|
||||
for (level = 0; level < max_depth; level++) {
|
||||
*res_page = NULL;
|
||||
de = find_in_level(dir, level, &fname, res_page);
|
||||
de = find_in_level(dir, level, fname, res_page);
|
||||
if (de || IS_ERR(*res_page))
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return de;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an entry in the specified directory with the wanted name.
|
||||
* It returns the page where the entry was found (as a parameter - res_page),
|
||||
* and the entry itself. Page is returned mapped and unlocked.
|
||||
* Entry is guaranteed to be valid.
|
||||
*/
|
||||
struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
|
||||
const struct qstr *child, struct page **res_page)
|
||||
{
|
||||
struct f2fs_dir_entry *de = NULL;
|
||||
struct fscrypt_name fname;
|
||||
int err;
|
||||
|
||||
err = fscrypt_setup_filename(dir, child, 1, &fname);
|
||||
if (err) {
|
||||
*res_page = ERR_PTR(err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
de = __f2fs_find_entry(dir, &fname, res_page);
|
||||
|
||||
fscrypt_free_filename(&fname);
|
||||
return de;
|
||||
}
|
||||
|
@ -605,6 +615,26 @@ fail:
|
|||
return err;
|
||||
}
|
||||
|
||||
int __f2fs_do_add_link(struct inode *dir, struct fscrypt_name *fname,
|
||||
struct inode *inode, nid_t ino, umode_t mode)
|
||||
{
|
||||
struct qstr new_name;
|
||||
int err = -EAGAIN;
|
||||
|
||||
new_name.name = fname_name(fname);
|
||||
new_name.len = fname_len(fname);
|
||||
|
||||
if (f2fs_has_inline_dentry(dir))
|
||||
err = f2fs_add_inline_entry(dir, &new_name, fname->usr_fname,
|
||||
inode, ino, mode);
|
||||
if (err == -EAGAIN)
|
||||
err = f2fs_add_regular_entry(dir, &new_name, fname->usr_fname,
|
||||
inode, ino, mode);
|
||||
|
||||
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caller should grab and release a rwsem by calling f2fs_lock_op() and
|
||||
* f2fs_unlock_op().
|
||||
|
@ -613,26 +643,15 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
|
|||
struct inode *inode, nid_t ino, umode_t mode)
|
||||
{
|
||||
struct fscrypt_name fname;
|
||||
struct qstr new_name;
|
||||
int err;
|
||||
|
||||
err = fscrypt_setup_filename(dir, name, 0, &fname);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
new_name.name = fname_name(&fname);
|
||||
new_name.len = fname_len(&fname);
|
||||
|
||||
err = -EAGAIN;
|
||||
if (f2fs_has_inline_dentry(dir))
|
||||
err = f2fs_add_inline_entry(dir, &new_name, fname.usr_fname,
|
||||
inode, ino, mode);
|
||||
if (err == -EAGAIN)
|
||||
err = f2fs_add_regular_entry(dir, &new_name, fname.usr_fname,
|
||||
inode, ino, mode);
|
||||
err = __f2fs_do_add_link(dir, &fname, inode, ino, mode);
|
||||
|
||||
fscrypt_free_filename(&fname);
|
||||
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1939,6 +1939,8 @@ struct page *init_inode_metadata(struct inode *, struct inode *,
|
|||
void update_parent_metadata(struct inode *, struct inode *, unsigned int);
|
||||
int room_for_filename(const void *, int, int);
|
||||
void f2fs_drop_nlink(struct inode *, struct inode *);
|
||||
struct f2fs_dir_entry *__f2fs_find_entry(struct inode *, struct fscrypt_name *,
|
||||
struct page **);
|
||||
struct f2fs_dir_entry *f2fs_find_entry(struct inode *, const struct qstr *,
|
||||
struct page **);
|
||||
struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
|
||||
|
@ -1950,6 +1952,8 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *,
|
|||
const struct qstr *, f2fs_hash_t , unsigned int);
|
||||
int f2fs_add_regular_entry(struct inode *, const struct qstr *,
|
||||
const struct qstr *, struct inode *, nid_t, umode_t);
|
||||
int __f2fs_do_add_link(struct inode *, struct fscrypt_name*, struct inode *,
|
||||
nid_t, umode_t);
|
||||
int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t,
|
||||
umode_t);
|
||||
void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *,
|
||||
|
|
|
@ -137,8 +137,6 @@ static inline bool need_do_checkpoint(struct inode *inode)
|
|||
need_cp = true;
|
||||
else if (is_sbi_flag_set(sbi, SBI_NEED_CP))
|
||||
need_cp = true;
|
||||
else if (file_enc_name(inode) && need_dentry_mark(sbi, inode->i_ino))
|
||||
need_cp = true;
|
||||
else if (file_wrong_pino(inode))
|
||||
need_cp = true;
|
||||
else if (!space_for_roll_forward(sbi))
|
||||
|
|
|
@ -96,11 +96,12 @@ static int recover_dentry(struct inode *inode, struct page *ipage,
|
|||
struct f2fs_inode *raw_inode = F2FS_INODE(ipage);
|
||||
nid_t pino = le32_to_cpu(raw_inode->i_pino);
|
||||
struct f2fs_dir_entry *de;
|
||||
struct qstr name;
|
||||
struct fscrypt_name fname;
|
||||
struct page *page;
|
||||
struct inode *dir, *einode;
|
||||
struct fsync_inode_entry *entry;
|
||||
int err = 0;
|
||||
char *name;
|
||||
|
||||
entry = get_fsync_inode(dir_list, pino);
|
||||
if (!entry) {
|
||||
|
@ -120,19 +121,17 @@ static int recover_dentry(struct inode *inode, struct page *ipage,
|
|||
|
||||
dir = entry->inode;
|
||||
|
||||
if (file_enc_name(inode))
|
||||
return 0;
|
||||
memset(&fname, 0, sizeof(struct fscrypt_name));
|
||||
fname.disk_name.len = le32_to_cpu(raw_inode->i_namelen);
|
||||
fname.disk_name.name = raw_inode->i_name;
|
||||
|
||||
name.len = le32_to_cpu(raw_inode->i_namelen);
|
||||
name.name = raw_inode->i_name;
|
||||
|
||||
if (unlikely(name.len > F2FS_NAME_LEN)) {
|
||||
if (unlikely(fname.disk_name.len > F2FS_NAME_LEN)) {
|
||||
WARN_ON(1);
|
||||
err = -ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
retry:
|
||||
de = f2fs_find_entry(dir, &name, &page);
|
||||
de = __f2fs_find_entry(dir, &fname, &page);
|
||||
if (de && inode->i_ino == le32_to_cpu(de->ino))
|
||||
goto out_unmap_put;
|
||||
|
||||
|
@ -156,7 +155,7 @@ retry:
|
|||
} else if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
} else {
|
||||
err = __f2fs_add_link(dir, &name, inode,
|
||||
err = __f2fs_do_add_link(dir, &fname, inode,
|
||||
inode->i_ino, inode->i_mode);
|
||||
}
|
||||
goto out;
|
||||
|
@ -165,9 +164,13 @@ out_unmap_put:
|
|||
f2fs_dentry_kunmap(dir, page);
|
||||
f2fs_put_page(page, 0);
|
||||
out:
|
||||
if (file_enc_name(inode))
|
||||
name = "<encrypted>";
|
||||
else
|
||||
name = raw_inode->i_name;
|
||||
f2fs_msg(inode->i_sb, KERN_NOTICE,
|
||||
"%s: ino = %x, name = %s, dir = %lx, err = %d",
|
||||
__func__, ino_of_node(ipage), raw_inode->i_name,
|
||||
__func__, ino_of_node(ipage), name,
|
||||
IS_ERR(dir) ? 0 : dir->i_ino, err);
|
||||
return err;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче