mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge tag 'for-f2fs-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim: "The major change in this version is mitigating cpu overheads on write paths by replacing redundant inode page updates with mark_inode_dirty calls. And we tried to reduce lock contentions as well to improve filesystem scalability. Other feature is setting F2FS automatically when detecting host-managed SMR. Enhancements: - ioctl to move a range of data between files - inject orphan inode errors - avoid flush commands congestion - support lazytime Bug fixes: - return proper results for some dentry operations - fix deadlock in add_link failure - disable extent_cache for fcollapse/finsert" * tag 'for-f2fs-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (68 commits) f2fs: clean up coding style and redundancy f2fs: get victim segment again after new cp f2fs: handle error case with f2fs_bug_on f2fs: avoid data race when deciding checkpoin in f2fs_sync_file f2fs: support an ioctl to move a range of data blocks f2fs: fix to report error number of f2fs_find_entry f2fs: avoid memory allocation failure due to a long length f2fs: reset default idle interval value f2fs: use blk_plug in all the possible paths f2fs: fix to avoid data update racing between GC and DIO f2fs: add maximum prefree segments f2fs: disable extent_cache for fcollapse/finsert inodes f2fs: refactor __exchange_data_block for speed up f2fs: fix ERR_PTR returned by bio f2fs: avoid mark_inode_dirty f2fs: move i_size_write in f2fs_write_end f2fs: fix to avoid redundant discard during fstrim f2fs: avoid mismatching block range for discard f2fs: fix incorrect f_bfree calculation in ->statfs f2fs: use percpu_rw_semaphore ...
This commit is contained in:
@@ -109,7 +109,9 @@ background_gc=%s Turn on/off cleaning operations, namely garbage
|
||||
disable_roll_forward Disable the roll-forward recovery routine
|
||||
norecovery Disable the roll-forward recovery routine, mounted read-
|
||||
only (i.e., -o ro,disable_roll_forward)
|
||||
discard Issue discard/TRIM commands when a segment is cleaned.
|
||||
discard/nodiscard Enable/disable real-time discard in f2fs, if discard is
|
||||
enabled, f2fs will issue discard/TRIM commands when a
|
||||
segment is cleaned.
|
||||
no_heap Disable heap-style segment allocation which finds free
|
||||
segments for data from the beginning of main area, while
|
||||
for node from the end of main area.
|
||||
@@ -151,6 +153,9 @@ noinline_data Disable the inline data feature, inline data feature is
|
||||
enabled by default.
|
||||
data_flush Enable data flushing before checkpoint in order to
|
||||
persist data of regular and symlink.
|
||||
mode=%s Control block allocation mode which supports "adaptive"
|
||||
and "lfs". In "lfs" mode, there should be no random
|
||||
writes towards main area.
|
||||
|
||||
================================================================================
|
||||
DEBUGFS ENTRIES
|
||||
|
||||
@@ -201,7 +201,6 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
|
||||
static int __f2fs_set_acl(struct inode *inode, int type,
|
||||
struct posix_acl *acl, struct page *ipage)
|
||||
{
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
int name_index;
|
||||
void *value = NULL;
|
||||
size_t size = 0;
|
||||
@@ -214,7 +213,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
|
||||
error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||||
if (error < 0)
|
||||
return error;
|
||||
set_acl_inode(fi, inode->i_mode);
|
||||
set_acl_inode(inode, inode->i_mode);
|
||||
if (error == 0)
|
||||
acl = NULL;
|
||||
}
|
||||
@@ -233,7 +232,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
|
||||
if (acl) {
|
||||
value = f2fs_acl_to_disk(acl, &size);
|
||||
if (IS_ERR(value)) {
|
||||
clear_inode_flag(fi, FI_ACL_MODE);
|
||||
clear_inode_flag(inode, FI_ACL_MODE);
|
||||
return (int)PTR_ERR(value);
|
||||
}
|
||||
}
|
||||
@@ -244,7 +243,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
|
||||
if (!error)
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
clear_inode_flag(fi, FI_ACL_MODE);
|
||||
clear_inode_flag(inode, FI_ACL_MODE);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -385,6 +384,8 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
f2fs_mark_inode_dirty_sync(inode);
|
||||
|
||||
if (default_acl) {
|
||||
error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
|
||||
ipage);
|
||||
|
||||
@@ -37,7 +37,7 @@ struct f2fs_acl_header {
|
||||
#ifdef CONFIG_F2FS_FS_POSIX_ACL
|
||||
|
||||
extern struct posix_acl *f2fs_get_acl(struct inode *, int);
|
||||
extern int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
|
||||
extern int f2fs_set_acl(struct inode *, struct posix_acl *, int);
|
||||
extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
|
||||
struct page *);
|
||||
#else
|
||||
|
||||
@@ -48,7 +48,8 @@ repeat:
|
||||
goto repeat;
|
||||
}
|
||||
f2fs_wait_on_page_writeback(page, META, true);
|
||||
SetPageUptodate(page);
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -266,6 +267,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
|
||||
struct blk_plug plug;
|
||||
long diff, written;
|
||||
|
||||
/* collect a number of dirty meta pages and write together */
|
||||
@@ -278,7 +280,9 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
|
||||
/* if mounting is failed, skip writing node pages */
|
||||
mutex_lock(&sbi->cp_mutex);
|
||||
diff = nr_pages_to_write(sbi, META, wbc);
|
||||
blk_start_plug(&plug);
|
||||
written = sync_meta_pages(sbi, META, wbc->nr_to_write);
|
||||
blk_finish_plug(&plug);
|
||||
mutex_unlock(&sbi->cp_mutex);
|
||||
wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
|
||||
return 0;
|
||||
@@ -366,9 +370,10 @@ static int f2fs_set_meta_page_dirty(struct page *page)
|
||||
{
|
||||
trace_f2fs_set_page_dirty(page, META);
|
||||
|
||||
SetPageUptodate(page);
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
f2fs_set_page_dirty_nobuffers(page);
|
||||
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
|
||||
SetPagePrivate(page);
|
||||
f2fs_trace_pid(page);
|
||||
@@ -510,10 +515,11 @@ void release_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
spin_unlock(&im->ino_lock);
|
||||
}
|
||||
|
||||
void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
void add_orphan_inode(struct inode *inode)
|
||||
{
|
||||
/* add new orphan ino entry into list */
|
||||
__add_ino_entry(sbi, ino, ORPHAN_INO);
|
||||
__add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO);
|
||||
update_inode_page(inode);
|
||||
}
|
||||
|
||||
void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
@@ -761,28 +767,25 @@ fail_no_cp:
|
||||
static void __add_dirty_inode(struct inode *inode, enum inode_type type)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
|
||||
|
||||
if (is_inode_flag_set(fi, flag))
|
||||
if (is_inode_flag_set(inode, flag))
|
||||
return;
|
||||
|
||||
set_inode_flag(fi, flag);
|
||||
list_add_tail(&fi->dirty_list, &sbi->inode_list[type]);
|
||||
set_inode_flag(inode, flag);
|
||||
list_add_tail(&F2FS_I(inode)->dirty_list, &sbi->inode_list[type]);
|
||||
stat_inc_dirty_inode(sbi, type);
|
||||
}
|
||||
|
||||
static void __remove_dirty_inode(struct inode *inode, enum inode_type type)
|
||||
{
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
|
||||
|
||||
if (get_dirty_pages(inode) ||
|
||||
!is_inode_flag_set(F2FS_I(inode), flag))
|
||||
if (get_dirty_pages(inode) || !is_inode_flag_set(inode, flag))
|
||||
return;
|
||||
|
||||
list_del_init(&fi->dirty_list);
|
||||
clear_inode_flag(fi, flag);
|
||||
list_del_init(&F2FS_I(inode)->dirty_list);
|
||||
clear_inode_flag(inode, flag);
|
||||
stat_dec_dirty_inode(F2FS_I_SB(inode), type);
|
||||
}
|
||||
|
||||
@@ -795,13 +798,12 @@ void update_dirty_page(struct inode *inode, struct page *page)
|
||||
!S_ISLNK(inode->i_mode))
|
||||
return;
|
||||
|
||||
if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH)) {
|
||||
spin_lock(&sbi->inode_lock[type]);
|
||||
spin_lock(&sbi->inode_lock[type]);
|
||||
if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH))
|
||||
__add_dirty_inode(inode, type);
|
||||
spin_unlock(&sbi->inode_lock[type]);
|
||||
}
|
||||
|
||||
inode_inc_dirty_pages(inode);
|
||||
spin_unlock(&sbi->inode_lock[type]);
|
||||
|
||||
SetPagePrivate(page);
|
||||
f2fs_trace_pid(page);
|
||||
}
|
||||
@@ -864,6 +866,34 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct list_head *head = &sbi->inode_list[DIRTY_META];
|
||||
struct inode *inode;
|
||||
struct f2fs_inode_info *fi;
|
||||
s64 total = get_pages(sbi, F2FS_DIRTY_IMETA);
|
||||
|
||||
while (total--) {
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
|
||||
spin_lock(&sbi->inode_lock[DIRTY_META]);
|
||||
if (list_empty(head)) {
|
||||
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||
return 0;
|
||||
}
|
||||
fi = list_entry(head->next, struct f2fs_inode_info,
|
||||
gdirty_list);
|
||||
inode = igrab(&fi->vfs_inode);
|
||||
spin_unlock(&sbi->inode_lock[DIRTY_META]);
|
||||
if (inode) {
|
||||
update_inode_page(inode);
|
||||
iput(inode);
|
||||
}
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Freeze all the FS-operations for checkpoint.
|
||||
*/
|
||||
@@ -890,6 +920,14 @@ retry_flush_dents:
|
||||
goto retry_flush_dents;
|
||||
}
|
||||
|
||||
if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
|
||||
f2fs_unlock_all(sbi);
|
||||
err = f2fs_sync_inode_meta(sbi);
|
||||
if (err)
|
||||
goto out;
|
||||
goto retry_flush_dents;
|
||||
}
|
||||
|
||||
/*
|
||||
* POR: we should ensure that there are no dirty node pages
|
||||
* until finishing nat/sit flush.
|
||||
@@ -914,6 +952,8 @@ out:
|
||||
static void unblock_operations(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
up_write(&sbi->node_write);
|
||||
|
||||
build_free_nids(sbi);
|
||||
f2fs_unlock_all(sbi);
|
||||
}
|
||||
|
||||
@@ -954,7 +994,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
* This avoids to conduct wrong roll-forward operations and uses
|
||||
* metapages, so should be called prior to sync_meta_pages below.
|
||||
*/
|
||||
if (discard_next_dnode(sbi, discard_blk))
|
||||
if (!test_opt(sbi, LFS) && discard_next_dnode(sbi, discard_blk))
|
||||
invalidate = true;
|
||||
|
||||
/* Flush all the NAT/SIT pages */
|
||||
|
||||
315
fs/f2fs/data.c
315
fs/f2fs/data.c
File diff suppressed because it is too large
Load Diff
@@ -47,6 +47,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
|
||||
si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA);
|
||||
si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
|
||||
si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
|
||||
si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
|
||||
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
|
||||
si->wb_bios = atomic_read(&sbi->nr_wb_bios);
|
||||
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
|
||||
@@ -304,8 +305,8 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
si->inmem_pages, si->wb_bios);
|
||||
seq_printf(s, " - nodes: %4lld in %4d\n",
|
||||
si->ndirty_node, si->node_pages);
|
||||
seq_printf(s, " - dents: %4lld in dirs:%4d\n",
|
||||
si->ndirty_dent, si->ndirty_dirs);
|
||||
seq_printf(s, " - dents: %4lld in dirs:%4d (%4d)\n",
|
||||
si->ndirty_dent, si->ndirty_dirs, si->ndirty_all);
|
||||
seq_printf(s, " - datas: %4lld in files:%4d\n",
|
||||
si->ndirty_data, si->ndirty_files);
|
||||
seq_printf(s, " - meta: %4lld in %4d\n",
|
||||
|
||||
123
fs/f2fs/dir.c
123
fs/f2fs/dir.c
@@ -185,8 +185,13 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
/* no need to allocate new dentry pages to all the indices */
|
||||
dentry_page = find_data_page(dir, bidx);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
room = true;
|
||||
continue;
|
||||
if (PTR_ERR(dentry_page) == -ENOENT) {
|
||||
room = true;
|
||||
continue;
|
||||
} else {
|
||||
*res_page = dentry_page;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
de = find_in_block(dentry_page, fname, namehash, &max_slots,
|
||||
@@ -223,19 +228,22 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
|
||||
struct fscrypt_name fname;
|
||||
int err;
|
||||
|
||||
*res_page = NULL;
|
||||
|
||||
err = fscrypt_setup_filename(dir, child, 1, &fname);
|
||||
if (err)
|
||||
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);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (npages == 0)
|
||||
if (npages == 0) {
|
||||
*res_page = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
max_depth = F2FS_I(dir)->i_current_depth;
|
||||
if (unlikely(max_depth > MAX_DIR_HASH_DEPTH)) {
|
||||
@@ -243,13 +251,13 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
|
||||
"Corrupted max_depth of %lu: %u",
|
||||
dir->i_ino, max_depth);
|
||||
max_depth = MAX_DIR_HASH_DEPTH;
|
||||
F2FS_I(dir)->i_current_depth = max_depth;
|
||||
mark_inode_dirty(dir);
|
||||
f2fs_i_depth_write(dir, max_depth);
|
||||
}
|
||||
|
||||
for (level = 0; level < max_depth; level++) {
|
||||
*res_page = NULL;
|
||||
de = find_in_level(dir, level, &fname, res_page);
|
||||
if (de)
|
||||
if (de || IS_ERR(*res_page))
|
||||
break;
|
||||
}
|
||||
out:
|
||||
@@ -259,35 +267,22 @@ out:
|
||||
|
||||
struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p)
|
||||
{
|
||||
struct page *page;
|
||||
struct f2fs_dir_entry *de;
|
||||
struct f2fs_dentry_block *dentry_blk;
|
||||
struct qstr dotdot = QSTR_INIT("..", 2);
|
||||
|
||||
if (f2fs_has_inline_dentry(dir))
|
||||
return f2fs_parent_inline_dir(dir, p);
|
||||
|
||||
page = get_lock_data_page(dir, 0, false);
|
||||
if (IS_ERR(page))
|
||||
return NULL;
|
||||
|
||||
dentry_blk = kmap(page);
|
||||
de = &dentry_blk->dentry[1];
|
||||
*p = page;
|
||||
unlock_page(page);
|
||||
return de;
|
||||
return f2fs_find_entry(dir, &dotdot, p);
|
||||
}
|
||||
|
||||
ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
|
||||
ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr,
|
||||
struct page **page)
|
||||
{
|
||||
ino_t res = 0;
|
||||
struct f2fs_dir_entry *de;
|
||||
struct page *page;
|
||||
|
||||
de = f2fs_find_entry(dir, qstr, &page);
|
||||
de = f2fs_find_entry(dir, qstr, page);
|
||||
if (de) {
|
||||
res = le32_to_cpu(de->ino);
|
||||
f2fs_dentry_kunmap(dir, page);
|
||||
f2fs_put_page(page, 0);
|
||||
f2fs_dentry_kunmap(dir, *page);
|
||||
f2fs_put_page(*page, 0);
|
||||
}
|
||||
|
||||
return res;
|
||||
@@ -303,9 +298,9 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
|
||||
set_de_type(de, inode->i_mode);
|
||||
f2fs_dentry_kunmap(dir, page);
|
||||
set_page_dirty(page);
|
||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||||
mark_inode_dirty(dir);
|
||||
|
||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||||
f2fs_mark_inode_dirty_sync(dir);
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
|
||||
@@ -385,7 +380,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
struct page *page;
|
||||
int err;
|
||||
|
||||
if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
|
||||
if (is_inode_flag_set(inode, FI_NEW_INODE)) {
|
||||
page = new_inode_page(inode);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
@@ -429,7 +424,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
* This file should be checkpointed during fsync.
|
||||
* We lost i_pino from now on.
|
||||
*/
|
||||
if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
|
||||
if (is_inode_flag_set(inode, FI_INC_LINK)) {
|
||||
file_lost_pino(inode);
|
||||
/*
|
||||
* If link the tmpfile to alias through linkat path,
|
||||
@@ -437,14 +432,11 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
*/
|
||||
if (inode->i_nlink == 0)
|
||||
remove_orphan_inode(F2FS_I_SB(dir), inode->i_ino);
|
||||
inc_nlink(inode);
|
||||
f2fs_i_links_write(inode, true);
|
||||
}
|
||||
return page;
|
||||
|
||||
put_error:
|
||||
/* truncate empty dir pages */
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
|
||||
clear_nlink(inode);
|
||||
update_inode(inode, page);
|
||||
f2fs_put_page(page, 1);
|
||||
@@ -454,23 +446,19 @@ put_error:
|
||||
void update_parent_metadata(struct inode *dir, struct inode *inode,
|
||||
unsigned int current_depth)
|
||||
{
|
||||
if (inode && is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
inc_nlink(dir);
|
||||
set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
|
||||
}
|
||||
clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
|
||||
if (inode && is_inode_flag_set(inode, FI_NEW_INODE)) {
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
f2fs_i_links_write(dir, true);
|
||||
clear_inode_flag(inode, FI_NEW_INODE);
|
||||
}
|
||||
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||||
mark_inode_dirty(dir);
|
||||
f2fs_mark_inode_dirty_sync(dir);
|
||||
|
||||
if (F2FS_I(dir)->i_current_depth != current_depth) {
|
||||
F2FS_I(dir)->i_current_depth = current_depth;
|
||||
set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
|
||||
}
|
||||
if (F2FS_I(dir)->i_current_depth != current_depth)
|
||||
f2fs_i_depth_write(dir, current_depth);
|
||||
|
||||
if (inode && is_inode_flag_set(F2FS_I(inode), FI_INC_LINK))
|
||||
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
|
||||
if (inode && is_inode_flag_set(inode, FI_INC_LINK))
|
||||
clear_inode_flag(inode, FI_INC_LINK);
|
||||
}
|
||||
|
||||
int room_for_filename(const void *bitmap, int slots, int max_slots)
|
||||
@@ -596,9 +584,7 @@ add_dentry:
|
||||
set_page_dirty(dentry_page);
|
||||
|
||||
if (inode) {
|
||||
/* we don't need to mark_inode_dirty now */
|
||||
F2FS_I(inode)->i_pino = dir->i_ino;
|
||||
update_inode(inode, page);
|
||||
f2fs_i_pino_write(inode, dir->i_ino);
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
|
||||
@@ -607,10 +593,6 @@ fail:
|
||||
if (inode)
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
|
||||
if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
|
||||
update_inode_page(dir);
|
||||
clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
|
||||
}
|
||||
kunmap(dentry_page);
|
||||
f2fs_put_page(dentry_page, 1);
|
||||
|
||||
@@ -657,42 +639,34 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
|
||||
err = PTR_ERR(page);
|
||||
goto fail;
|
||||
}
|
||||
/* we don't need to mark_inode_dirty now */
|
||||
update_inode(inode, page);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
|
||||
clear_inode_flag(inode, FI_NEW_INODE);
|
||||
fail:
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
||||
return err;
|
||||
}
|
||||
|
||||
void f2fs_drop_nlink(struct inode *dir, struct inode *inode, struct page *page)
|
||||
void f2fs_drop_nlink(struct inode *dir, struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
|
||||
|
||||
down_write(&F2FS_I(inode)->i_sem);
|
||||
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
drop_nlink(dir);
|
||||
if (page)
|
||||
update_inode(dir, page);
|
||||
else
|
||||
update_inode_page(dir);
|
||||
}
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
f2fs_i_links_write(dir, false);
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
|
||||
drop_nlink(inode);
|
||||
f2fs_i_links_write(inode, false);
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
drop_nlink(inode);
|
||||
i_size_write(inode, 0);
|
||||
f2fs_i_links_write(inode, false);
|
||||
f2fs_i_size_write(inode, 0);
|
||||
}
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
update_inode_page(inode);
|
||||
|
||||
if (inode->i_nlink == 0)
|
||||
add_orphan_inode(sbi, inode->i_ino);
|
||||
add_orphan_inode(inode);
|
||||
else
|
||||
release_orphan_inode(sbi);
|
||||
}
|
||||
@@ -730,9 +704,10 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
set_page_dirty(page);
|
||||
|
||||
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
|
||||
f2fs_mark_inode_dirty_sync(dir);
|
||||
|
||||
if (inode)
|
||||
f2fs_drop_nlink(dir, inode, NULL);
|
||||
f2fs_drop_nlink(dir, inode);
|
||||
|
||||
if (bit_pos == NR_DENTRY_IN_BLOCK &&
|
||||
!truncate_hole(dir, page->index, page->index + 1)) {
|
||||
|
||||
@@ -170,8 +170,10 @@ static void __drop_largest_extent(struct inode *inode,
|
||||
{
|
||||
struct extent_info *largest = &F2FS_I(inode)->extent_tree->largest;
|
||||
|
||||
if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs)
|
||||
if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) {
|
||||
largest->len = 0;
|
||||
f2fs_mark_inode_dirty_sync(inode);
|
||||
}
|
||||
}
|
||||
|
||||
/* return true, if inode page is changed */
|
||||
@@ -335,11 +337,12 @@ lookup_neighbors:
|
||||
return en;
|
||||
}
|
||||
|
||||
static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi,
|
||||
static struct extent_node *__try_merge_extent_node(struct inode *inode,
|
||||
struct extent_tree *et, struct extent_info *ei,
|
||||
struct extent_node *prev_ex,
|
||||
struct extent_node *next_ex)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct extent_node *en = NULL;
|
||||
|
||||
if (prev_ex && __is_back_mergeable(ei, &prev_ex->ei)) {
|
||||
@@ -360,7 +363,7 @@ static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi,
|
||||
if (!en)
|
||||
return NULL;
|
||||
|
||||
__try_update_largest_extent(et, en);
|
||||
__try_update_largest_extent(inode, et, en);
|
||||
|
||||
spin_lock(&sbi->extent_lock);
|
||||
if (!list_empty(&en->list)) {
|
||||
@@ -371,11 +374,12 @@ static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi,
|
||||
return en;
|
||||
}
|
||||
|
||||
static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi,
|
||||
static struct extent_node *__insert_extent_tree(struct inode *inode,
|
||||
struct extent_tree *et, struct extent_info *ei,
|
||||
struct rb_node **insert_p,
|
||||
struct rb_node *insert_parent)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct rb_node **p = &et->root.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct extent_node *en = NULL;
|
||||
@@ -402,7 +406,7 @@ do_insert:
|
||||
if (!en)
|
||||
return NULL;
|
||||
|
||||
__try_update_largest_extent(et, en);
|
||||
__try_update_largest_extent(inode, et, en);
|
||||
|
||||
/* update in global extent list */
|
||||
spin_lock(&sbi->extent_lock);
|
||||
@@ -431,7 +435,7 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
|
||||
|
||||
write_lock(&et->lock);
|
||||
|
||||
if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) {
|
||||
if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
|
||||
write_unlock(&et->lock);
|
||||
return false;
|
||||
}
|
||||
@@ -473,7 +477,7 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
|
||||
set_extent_info(&ei, end,
|
||||
end - dei.fofs + dei.blk,
|
||||
org_end - end);
|
||||
en1 = __insert_extent_tree(sbi, et, &ei,
|
||||
en1 = __insert_extent_tree(inode, et, &ei,
|
||||
NULL, NULL);
|
||||
next_en = en1;
|
||||
} else {
|
||||
@@ -494,7 +498,7 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
|
||||
}
|
||||
|
||||
if (parts)
|
||||
__try_update_largest_extent(et, en);
|
||||
__try_update_largest_extent(inode, et, en);
|
||||
else
|
||||
__release_extent_node(sbi, et, en);
|
||||
|
||||
@@ -514,20 +518,20 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
|
||||
if (blkaddr) {
|
||||
|
||||
set_extent_info(&ei, fofs, blkaddr, len);
|
||||
if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
|
||||
__insert_extent_tree(sbi, et, &ei,
|
||||
if (!__try_merge_extent_node(inode, et, &ei, prev_en, next_en))
|
||||
__insert_extent_tree(inode, et, &ei,
|
||||
insert_p, insert_parent);
|
||||
|
||||
/* give up extent_cache, if split and small updates happen */
|
||||
if (dei.len >= 1 &&
|
||||
prev.len < F2FS_MIN_EXTENT_LEN &&
|
||||
et->largest.len < F2FS_MIN_EXTENT_LEN) {
|
||||
et->largest.len = 0;
|
||||
set_inode_flag(F2FS_I(inode), FI_NO_EXTENT);
|
||||
__drop_largest_extent(inode, 0, UINT_MAX);
|
||||
set_inode_flag(inode, FI_NO_EXTENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT))
|
||||
if (is_inode_flag_set(inode, FI_NO_EXTENT))
|
||||
__free_extent_tree(sbi, et);
|
||||
|
||||
write_unlock(&et->lock);
|
||||
@@ -627,6 +631,19 @@ unsigned int f2fs_destroy_extent_node(struct inode *inode)
|
||||
return node_cnt;
|
||||
}
|
||||
|
||||
void f2fs_drop_extent_tree(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct extent_tree *et = F2FS_I(inode)->extent_tree;
|
||||
|
||||
set_inode_flag(inode, FI_NO_EXTENT);
|
||||
|
||||
write_lock(&et->lock);
|
||||
__free_extent_tree(sbi, et);
|
||||
__drop_largest_extent(inode, 0, UINT_MAX);
|
||||
write_unlock(&et->lock);
|
||||
}
|
||||
|
||||
void f2fs_destroy_extent_tree(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
@@ -685,9 +702,7 @@ void f2fs_update_extent_cache(struct dnode_of_data *dn)
|
||||
|
||||
fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
|
||||
dn->ofs_in_node;
|
||||
|
||||
if (f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, 1))
|
||||
sync_inode_page(dn);
|
||||
f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, 1);
|
||||
}
|
||||
|
||||
void f2fs_update_extent_cache_range(struct dnode_of_data *dn,
|
||||
@@ -697,8 +712,7 @@ void f2fs_update_extent_cache_range(struct dnode_of_data *dn,
|
||||
if (!f2fs_may_extent_tree(dn->inode))
|
||||
return;
|
||||
|
||||
if (f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, len))
|
||||
sync_inode_page(dn);
|
||||
f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, len);
|
||||
}
|
||||
|
||||
void init_extent_cache_info(struct f2fs_sb_info *sbi)
|
||||
|
||||
290
fs/f2fs/f2fs.h
290
fs/f2fs/f2fs.h
File diff suppressed because it is too large
Load Diff
501
fs/f2fs/file.c
501
fs/f2fs/file.c
File diff suppressed because it is too large
Load Diff
52
fs/f2fs/gc.c
52
fs/f2fs/gc.c
@@ -594,11 +594,11 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
|
||||
/* write page */
|
||||
lock_page(fio.encrypted_page);
|
||||
|
||||
if (unlikely(!PageUptodate(fio.encrypted_page))) {
|
||||
if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) {
|
||||
err = -EIO;
|
||||
goto put_page_out;
|
||||
}
|
||||
if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) {
|
||||
if (unlikely(!PageUptodate(fio.encrypted_page))) {
|
||||
err = -EIO;
|
||||
goto put_page_out;
|
||||
}
|
||||
@@ -619,9 +619,9 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
|
||||
f2fs_submit_page_mbio(&fio);
|
||||
|
||||
f2fs_update_data_blkaddr(&dn, newaddr);
|
||||
set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
|
||||
set_inode_flag(inode, FI_APPEND_WRITE);
|
||||
if (page->index == 0)
|
||||
set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
|
||||
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
|
||||
put_page_out:
|
||||
f2fs_put_page(fio.encrypted_page, 1);
|
||||
recover_block:
|
||||
@@ -656,12 +656,23 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
|
||||
.page = page,
|
||||
.encrypted_page = NULL,
|
||||
};
|
||||
bool is_dirty = PageDirty(page);
|
||||
int err;
|
||||
|
||||
retry:
|
||||
set_page_dirty(page);
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
if (clear_page_dirty_for_io(page))
|
||||
inode_dec_dirty_pages(inode);
|
||||
|
||||
set_cold_data(page);
|
||||
do_write_data_page(&fio);
|
||||
|
||||
err = do_write_data_page(&fio);
|
||||
if (err == -ENOMEM && is_dirty) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
clear_cold_data(page);
|
||||
}
|
||||
out:
|
||||
@@ -748,12 +759,32 @@ next_step:
|
||||
/* phase 3 */
|
||||
inode = find_gc_inode(gc_list, dni.ino);
|
||||
if (inode) {
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
bool locked = false;
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
if (!down_write_trylock(&fi->dio_rwsem[READ]))
|
||||
continue;
|
||||
if (!down_write_trylock(
|
||||
&fi->dio_rwsem[WRITE])) {
|
||||
up_write(&fi->dio_rwsem[READ]);
|
||||
continue;
|
||||
}
|
||||
locked = true;
|
||||
}
|
||||
|
||||
start_bidx = start_bidx_of_node(nofs, inode)
|
||||
+ ofs_in_node;
|
||||
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
|
||||
move_encrypted_block(inode, start_bidx);
|
||||
else
|
||||
move_data_page(inode, start_bidx, gc_type);
|
||||
|
||||
if (locked) {
|
||||
up_write(&fi->dio_rwsem[WRITE]);
|
||||
up_write(&fi->dio_rwsem[READ]);
|
||||
}
|
||||
|
||||
stat_inc_data_blk_count(sbi, 1, gc_type);
|
||||
}
|
||||
}
|
||||
@@ -802,6 +833,10 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
|
||||
blk_start_plug(&plug);
|
||||
|
||||
for (segno = start_segno; segno < end_segno; segno++) {
|
||||
|
||||
if (get_valid_blocks(sbi, segno, 1) == 0)
|
||||
continue;
|
||||
|
||||
/* find segment summary of victim */
|
||||
sum_page = find_get_page(META_MAPPING(sbi),
|
||||
GET_SUM_BLOCK(sbi, segno));
|
||||
@@ -877,10 +912,13 @@ gc_more:
|
||||
* enough free sections, we should flush dent/node blocks and do
|
||||
* garbage collections.
|
||||
*/
|
||||
if (__get_victim(sbi, &segno, gc_type) || prefree_segments(sbi))
|
||||
if (__get_victim(sbi, &segno, gc_type) ||
|
||||
prefree_segments(sbi)) {
|
||||
write_checkpoint(sbi, &cpc);
|
||||
else if (has_not_enough_free_secs(sbi, 0))
|
||||
segno = NULL_SEGNO;
|
||||
} else if (has_not_enough_free_secs(sbi, 0)) {
|
||||
write_checkpoint(sbi, &cpc);
|
||||
}
|
||||
}
|
||||
|
||||
if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type))
|
||||
|
||||
@@ -59,7 +59,8 @@ void read_inline_data(struct page *page, struct page *ipage)
|
||||
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
|
||||
flush_dcache_page(page);
|
||||
kunmap_atomic(dst_addr);
|
||||
SetPageUptodate(page);
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
|
||||
bool truncate_inline_inode(struct page *ipage, u64 from)
|
||||
@@ -73,7 +74,7 @@ bool truncate_inline_inode(struct page *ipage, u64 from)
|
||||
|
||||
f2fs_wait_on_page_writeback(ipage, NODE, true);
|
||||
memset(addr + from, 0, MAX_INLINE_DATA - from);
|
||||
|
||||
set_page_dirty(ipage);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -97,7 +98,8 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
|
||||
else
|
||||
read_inline_data(page, ipage);
|
||||
|
||||
SetPageUptodate(page);
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
f2fs_put_page(ipage, 1);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
@@ -139,7 +141,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
inode_dec_dirty_pages(dn->inode);
|
||||
|
||||
/* this converted inline_data should be recovered. */
|
||||
set_inode_flag(F2FS_I(dn->inode), FI_APPEND_WRITE);
|
||||
set_inode_flag(dn->inode, FI_APPEND_WRITE);
|
||||
|
||||
/* clear inline data and flag after data writeback */
|
||||
truncate_inline_inode(dn->inode_page, 0);
|
||||
@@ -147,7 +149,6 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
clear_out:
|
||||
stat_dec_inline_inode(dn->inode);
|
||||
f2fs_clear_inline_inode(dn->inode);
|
||||
sync_inode_page(dn);
|
||||
f2fs_put_dnode(dn);
|
||||
return 0;
|
||||
}
|
||||
@@ -213,11 +214,11 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
|
||||
dst_addr = inline_data_addr(dn.inode_page);
|
||||
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
|
||||
kunmap_atomic(src_addr);
|
||||
set_page_dirty(dn.inode_page);
|
||||
|
||||
set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
|
||||
set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
|
||||
set_inode_flag(inode, FI_APPEND_WRITE);
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
|
||||
sync_inode_page(&dn);
|
||||
clear_inline_node(dn.inode_page);
|
||||
f2fs_put_dnode(&dn);
|
||||
return 0;
|
||||
@@ -253,10 +254,10 @@ process_inline:
|
||||
dst_addr = inline_data_addr(ipage);
|
||||
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
|
||||
|
||||
set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
|
||||
set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
|
||||
set_inode_flag(inode, FI_INLINE_DATA);
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
|
||||
update_inode(inode, ipage);
|
||||
set_page_dirty(ipage);
|
||||
f2fs_put_page(ipage, 1);
|
||||
return true;
|
||||
}
|
||||
@@ -267,7 +268,6 @@ process_inline:
|
||||
if (!truncate_inline_inode(ipage, 0))
|
||||
return false;
|
||||
f2fs_clear_inline_inode(inode);
|
||||
update_inode(inode, ipage);
|
||||
f2fs_put_page(ipage, 1);
|
||||
} else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) {
|
||||
if (truncate_blocks(inode, 0, false))
|
||||
@@ -289,8 +289,10 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
|
||||
f2fs_hash_t namehash;
|
||||
|
||||
ipage = get_node_page(sbi, dir->i_ino);
|
||||
if (IS_ERR(ipage))
|
||||
if (IS_ERR(ipage)) {
|
||||
*res_page = ipage;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
namehash = f2fs_dentry_hash(&name);
|
||||
|
||||
@@ -307,25 +309,6 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
|
||||
return de;
|
||||
}
|
||||
|
||||
struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *dir,
|
||||
struct page **p)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
|
||||
struct page *ipage;
|
||||
struct f2fs_dir_entry *de;
|
||||
struct f2fs_inline_dentry *dentry_blk;
|
||||
|
||||
ipage = get_node_page(sbi, dir->i_ino);
|
||||
if (IS_ERR(ipage))
|
||||
return NULL;
|
||||
|
||||
dentry_blk = inline_data_addr(ipage);
|
||||
de = &dentry_blk->dentry[1];
|
||||
*p = ipage;
|
||||
unlock_page(ipage);
|
||||
return de;
|
||||
}
|
||||
|
||||
int make_empty_inline_dir(struct inode *inode, struct inode *parent,
|
||||
struct page *ipage)
|
||||
{
|
||||
@@ -340,10 +323,8 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent,
|
||||
set_page_dirty(ipage);
|
||||
|
||||
/* update i_size to MAX_INLINE_DATA */
|
||||
if (i_size_read(inode) < MAX_INLINE_DATA) {
|
||||
i_size_write(inode, MAX_INLINE_DATA);
|
||||
set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR);
|
||||
}
|
||||
if (i_size_read(inode) < MAX_INLINE_DATA)
|
||||
f2fs_i_size_write(inode, MAX_INLINE_DATA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -392,22 +373,19 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
|
||||
NR_INLINE_DENTRY * F2FS_SLOT_LEN);
|
||||
|
||||
kunmap_atomic(dentry_blk);
|
||||
SetPageUptodate(page);
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
set_page_dirty(page);
|
||||
|
||||
/* clear inline dir and flag after data writeback */
|
||||
truncate_inline_inode(ipage, 0);
|
||||
|
||||
stat_dec_inline_dir(dir);
|
||||
clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY);
|
||||
clear_inode_flag(dir, FI_INLINE_DENTRY);
|
||||
|
||||
F2FS_I(dir)->i_current_depth = 1;
|
||||
if (i_size_read(dir) < PAGE_SIZE) {
|
||||
i_size_write(dir, PAGE_SIZE);
|
||||
set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
|
||||
}
|
||||
|
||||
sync_inode_page(&dn);
|
||||
f2fs_i_depth_write(dir, 1);
|
||||
if (i_size_read(dir) < PAGE_SIZE)
|
||||
f2fs_i_size_write(dir, PAGE_SIZE);
|
||||
out:
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
@@ -465,7 +443,6 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
|
||||
struct f2fs_inline_dentry *inline_dentry)
|
||||
{
|
||||
struct f2fs_inline_dentry *backup_dentry;
|
||||
struct f2fs_inode_info *fi = F2FS_I(dir);
|
||||
int err;
|
||||
|
||||
backup_dentry = f2fs_kmalloc(sizeof(struct f2fs_inline_dentry),
|
||||
@@ -487,16 +464,15 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
|
||||
lock_page(ipage);
|
||||
|
||||
stat_dec_inline_dir(dir);
|
||||
clear_inode_flag(fi, FI_INLINE_DENTRY);
|
||||
update_inode(dir, ipage);
|
||||
clear_inode_flag(dir, FI_INLINE_DENTRY);
|
||||
kfree(backup_dentry);
|
||||
return 0;
|
||||
recover:
|
||||
lock_page(ipage);
|
||||
memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA);
|
||||
fi->i_current_depth = 0;
|
||||
i_size_write(dir, MAX_INLINE_DATA);
|
||||
update_inode(dir, ipage);
|
||||
f2fs_i_depth_write(dir, 0);
|
||||
f2fs_i_size_write(dir, MAX_INLINE_DATA);
|
||||
set_page_dirty(ipage);
|
||||
f2fs_put_page(ipage, 1);
|
||||
|
||||
kfree(backup_dentry);
|
||||
@@ -560,8 +536,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
|
||||
|
||||
/* we don't need to mark_inode_dirty now */
|
||||
if (inode) {
|
||||
F2FS_I(inode)->i_pino = dir->i_ino;
|
||||
update_inode(inode, page);
|
||||
f2fs_i_pino_write(inode, dir->i_ino);
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
|
||||
@@ -569,11 +544,6 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
|
||||
fail:
|
||||
if (inode)
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
|
||||
if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
|
||||
update_inode(dir, ipage);
|
||||
clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
|
||||
}
|
||||
out:
|
||||
f2fs_put_page(ipage, 1);
|
||||
return err;
|
||||
@@ -597,13 +567,13 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
&inline_dentry->dentry_bitmap);
|
||||
|
||||
set_page_dirty(page);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
|
||||
f2fs_mark_inode_dirty_sync(dir);
|
||||
|
||||
if (inode)
|
||||
f2fs_drop_nlink(dir, inode, page);
|
||||
|
||||
f2fs_put_page(page, 1);
|
||||
f2fs_drop_nlink(dir, inode);
|
||||
}
|
||||
|
||||
bool f2fs_empty_inline_dir(struct inode *dir)
|
||||
|
||||
@@ -18,6 +18,13 @@
|
||||
|
||||
#include <trace/events/f2fs.h>
|
||||
|
||||
void f2fs_mark_inode_dirty_sync(struct inode *inode)
|
||||
{
|
||||
if (f2fs_inode_dirtied(inode))
|
||||
return;
|
||||
mark_inode_dirty_sync(inode);
|
||||
}
|
||||
|
||||
void f2fs_set_inode_flags(struct inode *inode)
|
||||
{
|
||||
unsigned int flags = F2FS_I(inode)->i_flags;
|
||||
@@ -35,6 +42,7 @@ void f2fs_set_inode_flags(struct inode *inode)
|
||||
new_fl |= S_DIRSYNC;
|
||||
inode_set_flags(inode, new_fl,
|
||||
S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
|
||||
f2fs_mark_inode_dirty_sync(inode);
|
||||
}
|
||||
|
||||
static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
|
||||
@@ -85,8 +93,8 @@ static void __recover_inline_status(struct inode *inode, struct page *ipage)
|
||||
if (*start++) {
|
||||
f2fs_wait_on_page_writeback(ipage, NODE, true);
|
||||
|
||||
set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
|
||||
set_raw_inline(F2FS_I(inode), F2FS_INODE(ipage));
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
set_raw_inline(inode, F2FS_INODE(ipage));
|
||||
set_page_dirty(ipage);
|
||||
return;
|
||||
}
|
||||
@@ -141,7 +149,7 @@ static int do_read_inode(struct inode *inode)
|
||||
if (f2fs_init_extent_tree(inode, &ri->i_ext))
|
||||
set_page_dirty(node_page);
|
||||
|
||||
get_inline_info(fi, ri);
|
||||
get_inline_info(inode, ri);
|
||||
|
||||
/* check data exist */
|
||||
if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
|
||||
@@ -151,7 +159,10 @@ static int do_read_inode(struct inode *inode)
|
||||
__get_inode_rdev(inode, ri);
|
||||
|
||||
if (__written_first_block(ri))
|
||||
set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
|
||||
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
|
||||
|
||||
if (!need_inode_block_update(sbi, inode->i_ino))
|
||||
fi->last_disk_size = inode->i_size;
|
||||
|
||||
f2fs_put_page(node_page, 1);
|
||||
|
||||
@@ -227,6 +238,8 @@ int update_inode(struct inode *inode, struct page *node_page)
|
||||
{
|
||||
struct f2fs_inode *ri;
|
||||
|
||||
f2fs_inode_synced(inode);
|
||||
|
||||
f2fs_wait_on_page_writeback(node_page, NODE, true);
|
||||
|
||||
ri = F2FS_INODE(node_page);
|
||||
@@ -244,7 +257,7 @@ int update_inode(struct inode *inode, struct page *node_page)
|
||||
&ri->i_ext);
|
||||
else
|
||||
memset(&ri->i_ext, 0, sizeof(ri->i_ext));
|
||||
set_raw_inline(F2FS_I(inode), ri);
|
||||
set_raw_inline(inode, ri);
|
||||
|
||||
ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
|
||||
ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
|
||||
@@ -261,7 +274,6 @@ int update_inode(struct inode *inode, struct page *node_page)
|
||||
|
||||
__set_inode_rdev(inode, ri);
|
||||
set_cold_node(inode, node_page);
|
||||
clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
|
||||
|
||||
/* deleted inode */
|
||||
if (inode->i_nlink == 0)
|
||||
@@ -285,6 +297,7 @@ retry:
|
||||
} else if (err != -ENOENT) {
|
||||
f2fs_stop_checkpoint(sbi, false);
|
||||
}
|
||||
f2fs_inode_synced(inode);
|
||||
return 0;
|
||||
}
|
||||
ret = update_inode(inode, node_page);
|
||||
@@ -300,7 +313,7 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
inode->i_ino == F2FS_META_INO(sbi))
|
||||
return 0;
|
||||
|
||||
if (!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_INODE))
|
||||
if (!is_inode_flag_set(inode, FI_DIRTY_INODE))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -318,8 +331,7 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
void f2fs_evict_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
nid_t xnid = fi->i_xattr_nid;
|
||||
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
|
||||
int err = 0;
|
||||
|
||||
/* some remained atomic pages should discarded */
|
||||
@@ -341,12 +353,17 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
if (inode->i_nlink || is_bad_inode(inode))
|
||||
goto no_delete;
|
||||
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
if (time_to_inject(FAULT_EVICT_INODE))
|
||||
goto no_delete;
|
||||
#endif
|
||||
|
||||
sb_start_intwrite(inode->i_sb);
|
||||
set_inode_flag(fi, FI_NO_ALLOC);
|
||||
set_inode_flag(inode, FI_NO_ALLOC);
|
||||
i_size_write(inode, 0);
|
||||
retry:
|
||||
if (F2FS_HAS_BLOCKS(inode))
|
||||
err = f2fs_truncate(inode, true);
|
||||
err = f2fs_truncate(inode);
|
||||
|
||||
if (!err) {
|
||||
f2fs_lock_op(sbi);
|
||||
@@ -360,6 +377,8 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (err)
|
||||
update_inode_page(inode);
|
||||
sb_end_intwrite(inode->i_sb);
|
||||
no_delete:
|
||||
stat_dec_inline_xattr(inode);
|
||||
@@ -369,13 +388,13 @@ no_delete:
|
||||
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
|
||||
if (xnid)
|
||||
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
|
||||
if (is_inode_flag_set(fi, FI_APPEND_WRITE))
|
||||
if (is_inode_flag_set(inode, FI_APPEND_WRITE))
|
||||
add_ino_entry(sbi, inode->i_ino, APPEND_INO);
|
||||
if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
|
||||
if (is_inode_flag_set(inode, FI_UPDATE_WRITE))
|
||||
add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
||||
if (is_inode_flag_set(fi, FI_FREE_NID)) {
|
||||
if (is_inode_flag_set(inode, FI_FREE_NID)) {
|
||||
alloc_nid_failed(sbi, inode->i_ino);
|
||||
clear_inode_flag(fi, FI_FREE_NID);
|
||||
clear_inode_flag(inode, FI_FREE_NID);
|
||||
}
|
||||
f2fs_bug_on(sbi, err &&
|
||||
!exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
|
||||
@@ -407,11 +426,11 @@ void handle_failed_inode(struct inode *inode)
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"Too many orphan inodes, run fsck to fix.");
|
||||
} else {
|
||||
add_orphan_inode(sbi, inode->i_ino);
|
||||
add_orphan_inode(inode);
|
||||
}
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
} else {
|
||||
set_inode_flag(F2FS_I(inode), FI_FREE_NID);
|
||||
set_inode_flag(inode, FI_FREE_NID);
|
||||
}
|
||||
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
147
fs/f2fs/namei.c
147
fs/f2fs/namei.c
@@ -60,10 +60,14 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode))
|
||||
f2fs_set_encrypted_inode(inode);
|
||||
|
||||
set_inode_flag(inode, FI_NEW_INODE);
|
||||
|
||||
if (test_opt(sbi, INLINE_XATTR))
|
||||
set_inode_flag(inode, FI_INLINE_XATTR);
|
||||
if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
|
||||
set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
|
||||
set_inode_flag(inode, FI_INLINE_DATA);
|
||||
if (f2fs_may_inline_dentry(inode))
|
||||
set_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
|
||||
set_inode_flag(inode, FI_INLINE_DENTRY);
|
||||
|
||||
f2fs_init_extent_tree(inode, NULL);
|
||||
|
||||
@@ -72,14 +76,13 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
stat_inc_inline_dir(inode);
|
||||
|
||||
trace_f2fs_new_inode(inode, 0);
|
||||
mark_inode_dirty(inode);
|
||||
return inode;
|
||||
|
||||
fail:
|
||||
trace_f2fs_new_inode(inode, err);
|
||||
make_bad_inode(inode);
|
||||
if (nid_free)
|
||||
set_inode_flag(F2FS_I(inode), FI_FREE_NID);
|
||||
set_inode_flag(inode, FI_FREE_NID);
|
||||
iput(inode);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
@@ -177,7 +180,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
ihold(inode);
|
||||
|
||||
set_inode_flag(F2FS_I(inode), FI_INC_LINK);
|
||||
set_inode_flag(inode, FI_INC_LINK);
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
if (err)
|
||||
@@ -190,7 +193,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
f2fs_sync_fs(sbi->sb, 1);
|
||||
return 0;
|
||||
out:
|
||||
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
|
||||
clear_inode_flag(inode, FI_INC_LINK);
|
||||
iput(inode);
|
||||
f2fs_unlock_op(sbi);
|
||||
return err;
|
||||
@@ -199,9 +202,13 @@ out:
|
||||
struct dentry *f2fs_get_parent(struct dentry *child)
|
||||
{
|
||||
struct qstr dotdot = QSTR_INIT("..", 2);
|
||||
unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot);
|
||||
if (!ino)
|
||||
struct page *page;
|
||||
unsigned long ino = f2fs_inode_by_name(d_inode(child), &dotdot, &page);
|
||||
if (!ino) {
|
||||
if (IS_ERR(page))
|
||||
return ERR_CAST(page);
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
return d_obtain_alias(f2fs_iget(child->d_sb, ino));
|
||||
}
|
||||
|
||||
@@ -229,6 +236,9 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
|
||||
if (de) {
|
||||
f2fs_dentry_kunmap(dir, page);
|
||||
f2fs_put_page(page, 0);
|
||||
} else if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
goto out;
|
||||
} else {
|
||||
err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR);
|
||||
if (err)
|
||||
@@ -239,14 +249,14 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
|
||||
if (de) {
|
||||
f2fs_dentry_kunmap(dir, page);
|
||||
f2fs_put_page(page, 0);
|
||||
} else if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
} else {
|
||||
err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR);
|
||||
}
|
||||
out:
|
||||
if (!err) {
|
||||
clear_inode_flag(F2FS_I(dir), FI_INLINE_DOTS);
|
||||
mark_inode_dirty(dir);
|
||||
}
|
||||
if (!err)
|
||||
clear_inode_flag(dir, FI_INLINE_DOTS);
|
||||
|
||||
f2fs_unlock_op(sbi);
|
||||
return err;
|
||||
@@ -281,8 +291,11 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
de = f2fs_find_entry(dir, &dentry->d_name, &page);
|
||||
if (!de)
|
||||
if (!de) {
|
||||
if (IS_ERR(page))
|
||||
return (struct dentry *)page;
|
||||
return d_splice_alias(inode, dentry);
|
||||
}
|
||||
|
||||
ino = le32_to_cpu(de->ino);
|
||||
f2fs_dentry_kunmap(dir, page);
|
||||
@@ -329,8 +342,11 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
trace_f2fs_unlink_enter(dir, dentry);
|
||||
|
||||
de = f2fs_find_entry(dir, &dentry->d_name, &page);
|
||||
if (!de)
|
||||
if (!de) {
|
||||
if (IS_ERR(page))
|
||||
err = PTR_ERR(page);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
@@ -345,9 +361,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
f2fs_delete_entry(de, page, dir, inode);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
/* In order to evict this inode, we set it dirty */
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
if (IS_DIRSYNC(dir))
|
||||
f2fs_sync_fs(sbi->sb, 1);
|
||||
fail:
|
||||
@@ -492,7 +505,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
set_inode_flag(F2FS_I(inode), FI_INC_LINK);
|
||||
set_inode_flag(inode, FI_INC_LINK);
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
if (err)
|
||||
@@ -509,7 +522,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
return 0;
|
||||
|
||||
out_fail:
|
||||
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
|
||||
clear_inode_flag(inode, FI_INC_LINK);
|
||||
handle_failed_inode(inode);
|
||||
return err;
|
||||
}
|
||||
@@ -592,17 +605,17 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
* add this non-linked tmpfile to orphan list, in this way we could
|
||||
* remove all unused data of tmpfile after abnormal power-off.
|
||||
*/
|
||||
add_orphan_inode(sbi, inode->i_ino);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
add_orphan_inode(inode);
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
|
||||
if (whiteout) {
|
||||
inode_dec_link_count(inode);
|
||||
f2fs_i_links_write(inode, false);
|
||||
*whiteout = inode;
|
||||
} else {
|
||||
d_tmpfile(dentry, inode);
|
||||
}
|
||||
/* link_count was changed by d_tmpfile as well. */
|
||||
f2fs_unlock_op(sbi);
|
||||
unlock_new_inode(inode);
|
||||
return 0;
|
||||
|
||||
@@ -652,14 +665,19 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
}
|
||||
|
||||
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
|
||||
if (!old_entry)
|
||||
if (!old_entry) {
|
||||
if (IS_ERR(old_page))
|
||||
err = PTR_ERR(old_page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (S_ISDIR(old_inode->i_mode)) {
|
||||
err = -EIO;
|
||||
old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
|
||||
if (!old_dir_entry)
|
||||
if (!old_dir_entry) {
|
||||
if (IS_ERR(old_dir_page))
|
||||
err = PTR_ERR(old_dir_page);
|
||||
goto out_old;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & RENAME_WHITEOUT) {
|
||||
@@ -677,8 +695,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
err = -ENOENT;
|
||||
new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
|
||||
&new_page);
|
||||
if (!new_entry)
|
||||
if (!new_entry) {
|
||||
if (IS_ERR(new_page))
|
||||
err = PTR_ERR(new_page);
|
||||
goto out_whiteout;
|
||||
}
|
||||
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
@@ -700,19 +721,14 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
new_inode->i_ctime = CURRENT_TIME;
|
||||
down_write(&F2FS_I(new_inode)->i_sem);
|
||||
if (old_dir_entry)
|
||||
drop_nlink(new_inode);
|
||||
drop_nlink(new_inode);
|
||||
f2fs_i_links_write(new_inode, false);
|
||||
f2fs_i_links_write(new_inode, false);
|
||||
up_write(&F2FS_I(new_inode)->i_sem);
|
||||
|
||||
mark_inode_dirty(new_inode);
|
||||
|
||||
if (!new_inode->i_nlink)
|
||||
add_orphan_inode(sbi, new_inode->i_ino);
|
||||
add_orphan_inode(new_inode);
|
||||
else
|
||||
release_orphan_inode(sbi);
|
||||
|
||||
update_inode_page(old_inode);
|
||||
update_inode_page(new_inode);
|
||||
} else {
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
@@ -724,10 +740,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
goto out_whiteout;
|
||||
}
|
||||
|
||||
if (old_dir_entry) {
|
||||
inc_nlink(new_dir);
|
||||
update_inode_page(new_dir);
|
||||
}
|
||||
if (old_dir_entry)
|
||||
f2fs_i_links_write(new_dir, true);
|
||||
|
||||
/*
|
||||
* old entry and new entry can locate in the same inline
|
||||
@@ -743,7 +757,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
old_entry = f2fs_find_entry(old_dir,
|
||||
&old_dentry->d_name, &old_page);
|
||||
if (!old_entry) {
|
||||
err = -EIO;
|
||||
err = -ENOENT;
|
||||
if (IS_ERR(old_page))
|
||||
err = PTR_ERR(old_page);
|
||||
f2fs_unlock_op(sbi);
|
||||
goto out_whiteout;
|
||||
}
|
||||
@@ -757,13 +773,13 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
up_write(&F2FS_I(old_inode)->i_sem);
|
||||
|
||||
old_inode->i_ctime = CURRENT_TIME;
|
||||
mark_inode_dirty(old_inode);
|
||||
f2fs_mark_inode_dirty_sync(old_inode);
|
||||
|
||||
f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
|
||||
|
||||
if (whiteout) {
|
||||
whiteout->i_state |= I_LINKABLE;
|
||||
set_inode_flag(F2FS_I(whiteout), FI_INC_LINK);
|
||||
set_inode_flag(whiteout, FI_INC_LINK);
|
||||
err = f2fs_add_link(old_dentry, whiteout);
|
||||
if (err)
|
||||
goto put_out_dir;
|
||||
@@ -775,14 +791,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
if (old_dir != new_dir && !whiteout) {
|
||||
f2fs_set_link(old_inode, old_dir_entry,
|
||||
old_dir_page, new_dir);
|
||||
update_inode_page(old_inode);
|
||||
} else {
|
||||
f2fs_dentry_kunmap(old_inode, old_dir_page);
|
||||
f2fs_put_page(old_dir_page, 0);
|
||||
}
|
||||
drop_nlink(old_dir);
|
||||
mark_inode_dirty(old_dir);
|
||||
update_inode_page(old_dir);
|
||||
f2fs_i_links_write(old_dir, false);
|
||||
}
|
||||
|
||||
f2fs_unlock_op(sbi);
|
||||
@@ -832,29 +845,39 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
return -EPERM;
|
||||
|
||||
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
|
||||
if (!old_entry)
|
||||
if (!old_entry) {
|
||||
if (IS_ERR(old_page))
|
||||
err = PTR_ERR(old_page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name, &new_page);
|
||||
if (!new_entry)
|
||||
if (!new_entry) {
|
||||
if (IS_ERR(new_page))
|
||||
err = PTR_ERR(new_page);
|
||||
goto out_old;
|
||||
}
|
||||
|
||||
/* prepare for updating ".." directory entry info later */
|
||||
if (old_dir != new_dir) {
|
||||
if (S_ISDIR(old_inode->i_mode)) {
|
||||
err = -EIO;
|
||||
old_dir_entry = f2fs_parent_dir(old_inode,
|
||||
&old_dir_page);
|
||||
if (!old_dir_entry)
|
||||
if (!old_dir_entry) {
|
||||
if (IS_ERR(old_dir_page))
|
||||
err = PTR_ERR(old_dir_page);
|
||||
goto out_new;
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISDIR(new_inode->i_mode)) {
|
||||
err = -EIO;
|
||||
new_dir_entry = f2fs_parent_dir(new_inode,
|
||||
&new_dir_page);
|
||||
if (!new_dir_entry)
|
||||
if (!new_dir_entry) {
|
||||
if (IS_ERR(new_dir_page))
|
||||
err = PTR_ERR(new_dir_page);
|
||||
goto out_old_dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,19 +927,13 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
file_lost_pino(old_inode);
|
||||
up_write(&F2FS_I(old_inode)->i_sem);
|
||||
|
||||
update_inode_page(old_inode);
|
||||
|
||||
old_dir->i_ctime = CURRENT_TIME;
|
||||
if (old_nlink) {
|
||||
down_write(&F2FS_I(old_dir)->i_sem);
|
||||
if (old_nlink < 0)
|
||||
drop_nlink(old_dir);
|
||||
else
|
||||
inc_nlink(old_dir);
|
||||
f2fs_i_links_write(old_dir, old_nlink > 0);
|
||||
up_write(&F2FS_I(old_dir)->i_sem);
|
||||
}
|
||||
mark_inode_dirty(old_dir);
|
||||
update_inode_page(old_dir);
|
||||
f2fs_mark_inode_dirty_sync(old_dir);
|
||||
|
||||
/* update directory entry info of new dir inode */
|
||||
f2fs_set_link(new_dir, new_entry, new_page, old_inode);
|
||||
@@ -925,19 +942,13 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
file_lost_pino(new_inode);
|
||||
up_write(&F2FS_I(new_inode)->i_sem);
|
||||
|
||||
update_inode_page(new_inode);
|
||||
|
||||
new_dir->i_ctime = CURRENT_TIME;
|
||||
if (new_nlink) {
|
||||
down_write(&F2FS_I(new_dir)->i_sem);
|
||||
if (new_nlink < 0)
|
||||
drop_nlink(new_dir);
|
||||
else
|
||||
inc_nlink(new_dir);
|
||||
f2fs_i_links_write(new_dir, new_nlink > 0);
|
||||
up_write(&F2FS_I(new_dir)->i_sem);
|
||||
}
|
||||
mark_inode_dirty(new_dir);
|
||||
update_inode_page(new_dir);
|
||||
f2fs_mark_inode_dirty_sync(new_dir);
|
||||
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
|
||||
144
fs/f2fs/node.c
144
fs/f2fs/node.c
@@ -52,6 +52,10 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
|
||||
mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >>
|
||||
PAGE_SHIFT;
|
||||
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
|
||||
if (excess_cached_nats(sbi))
|
||||
res = false;
|
||||
if (nm_i->nat_cnt > DEF_NAT_CACHE_THRESHOLD)
|
||||
res = false;
|
||||
} else if (type == DIRTY_DENTS) {
|
||||
if (sbi->sb->s_bdi->wb.dirty_exceeded)
|
||||
return false;
|
||||
@@ -202,14 +206,14 @@ int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
struct nat_entry *e;
|
||||
bool need = false;
|
||||
|
||||
down_read(&nm_i->nat_tree_lock);
|
||||
percpu_down_read(&nm_i->nat_tree_lock);
|
||||
e = __lookup_nat_cache(nm_i, nid);
|
||||
if (e) {
|
||||
if (!get_nat_flag(e, IS_CHECKPOINTED) &&
|
||||
!get_nat_flag(e, HAS_FSYNCED_INODE))
|
||||
need = true;
|
||||
}
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
percpu_up_read(&nm_i->nat_tree_lock);
|
||||
return need;
|
||||
}
|
||||
|
||||
@@ -219,11 +223,11 @@ bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
struct nat_entry *e;
|
||||
bool is_cp = true;
|
||||
|
||||
down_read(&nm_i->nat_tree_lock);
|
||||
percpu_down_read(&nm_i->nat_tree_lock);
|
||||
e = __lookup_nat_cache(nm_i, nid);
|
||||
if (e && !get_nat_flag(e, IS_CHECKPOINTED))
|
||||
is_cp = false;
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
percpu_up_read(&nm_i->nat_tree_lock);
|
||||
return is_cp;
|
||||
}
|
||||
|
||||
@@ -233,13 +237,13 @@ bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
struct nat_entry *e;
|
||||
bool need_update = true;
|
||||
|
||||
down_read(&nm_i->nat_tree_lock);
|
||||
percpu_down_read(&nm_i->nat_tree_lock);
|
||||
e = __lookup_nat_cache(nm_i, ino);
|
||||
if (e && get_nat_flag(e, HAS_LAST_FSYNC) &&
|
||||
(get_nat_flag(e, IS_CHECKPOINTED) ||
|
||||
get_nat_flag(e, HAS_FSYNCED_INODE)))
|
||||
need_update = false;
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
percpu_up_read(&nm_i->nat_tree_lock);
|
||||
return need_update;
|
||||
}
|
||||
|
||||
@@ -280,7 +284,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct nat_entry *e;
|
||||
|
||||
down_write(&nm_i->nat_tree_lock);
|
||||
percpu_down_write(&nm_i->nat_tree_lock);
|
||||
e = __lookup_nat_cache(nm_i, ni->nid);
|
||||
if (!e) {
|
||||
e = grab_nat_entry(nm_i, ni->nid);
|
||||
@@ -330,7 +334,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
set_nat_flag(e, HAS_FSYNCED_INODE, true);
|
||||
set_nat_flag(e, HAS_LAST_FSYNC, fsync_done);
|
||||
}
|
||||
up_write(&nm_i->nat_tree_lock);
|
||||
percpu_up_write(&nm_i->nat_tree_lock);
|
||||
}
|
||||
|
||||
int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
@@ -338,8 +342,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
int nr = nr_shrink;
|
||||
|
||||
if (!down_write_trylock(&nm_i->nat_tree_lock))
|
||||
return 0;
|
||||
percpu_down_write(&nm_i->nat_tree_lock);
|
||||
|
||||
while (nr_shrink && !list_empty(&nm_i->nat_entries)) {
|
||||
struct nat_entry *ne;
|
||||
@@ -348,7 +351,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
__del_from_nat_cache(nm_i, ne);
|
||||
nr_shrink--;
|
||||
}
|
||||
up_write(&nm_i->nat_tree_lock);
|
||||
percpu_up_write(&nm_i->nat_tree_lock);
|
||||
return nr - nr_shrink;
|
||||
}
|
||||
|
||||
@@ -370,13 +373,13 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
|
||||
ni->nid = nid;
|
||||
|
||||
/* Check nat cache */
|
||||
down_read(&nm_i->nat_tree_lock);
|
||||
percpu_down_read(&nm_i->nat_tree_lock);
|
||||
e = __lookup_nat_cache(nm_i, nid);
|
||||
if (e) {
|
||||
ni->ino = nat_get_ino(e);
|
||||
ni->blk_addr = nat_get_blkaddr(e);
|
||||
ni->version = nat_get_version(e);
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
percpu_up_read(&nm_i->nat_tree_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -400,11 +403,11 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
|
||||
node_info_from_raw_nat(ni, &ne);
|
||||
f2fs_put_page(page, 1);
|
||||
cache:
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
percpu_up_read(&nm_i->nat_tree_lock);
|
||||
/* cache nat entry */
|
||||
down_write(&nm_i->nat_tree_lock);
|
||||
percpu_down_write(&nm_i->nat_tree_lock);
|
||||
cache_nat_entry(sbi, nid, &ne);
|
||||
up_write(&nm_i->nat_tree_lock);
|
||||
percpu_up_write(&nm_i->nat_tree_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -646,6 +649,7 @@ release_out:
|
||||
if (err == -ENOENT) {
|
||||
dn->cur_level = i;
|
||||
dn->max_level = level;
|
||||
dn->ofs_in_node = offset[level];
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -670,8 +674,7 @@ static void truncate_node(struct dnode_of_data *dn)
|
||||
if (dn->nid == dn->inode->i_ino) {
|
||||
remove_orphan_inode(sbi, dn->nid);
|
||||
dec_valid_inode_count(sbi);
|
||||
} else {
|
||||
sync_inode_page(dn);
|
||||
f2fs_inode_synced(dn->inode);
|
||||
}
|
||||
invalidate:
|
||||
clear_node_page_dirty(dn->node_page);
|
||||
@@ -953,7 +956,7 @@ int truncate_xattr_node(struct inode *inode, struct page *page)
|
||||
if (IS_ERR(npage))
|
||||
return PTR_ERR(npage);
|
||||
|
||||
F2FS_I(inode)->i_xattr_nid = 0;
|
||||
f2fs_i_xnid_write(inode, 0);
|
||||
|
||||
/* need to do checkpoint during fsync */
|
||||
F2FS_I(inode)->xattr_ver = cur_cp_version(F2FS_CKPT(sbi));
|
||||
@@ -1019,7 +1022,7 @@ struct page *new_node_page(struct dnode_of_data *dn,
|
||||
struct page *page;
|
||||
int err;
|
||||
|
||||
if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)))
|
||||
if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
page = f2fs_grab_cache_page(NODE_MAPPING(sbi), dn->nid, false);
|
||||
@@ -1042,21 +1045,16 @@ struct page *new_node_page(struct dnode_of_data *dn,
|
||||
f2fs_wait_on_page_writeback(page, NODE, true);
|
||||
fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
|
||||
set_cold_node(dn->inode, page);
|
||||
SetPageUptodate(page);
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
if (set_page_dirty(page))
|
||||
dn->node_changed = true;
|
||||
|
||||
if (f2fs_has_xattr_block(ofs))
|
||||
F2FS_I(dn->inode)->i_xattr_nid = dn->nid;
|
||||
f2fs_i_xnid_write(dn->inode, dn->nid);
|
||||
|
||||
dn->node_page = page;
|
||||
if (ipage)
|
||||
update_inode(dn->inode, ipage);
|
||||
else
|
||||
sync_inode_page(dn);
|
||||
if (ofs == 0)
|
||||
inc_valid_inode_count(sbi);
|
||||
|
||||
return page;
|
||||
|
||||
fail:
|
||||
@@ -1083,6 +1081,9 @@ static int read_node_page(struct page *page, int op_flags)
|
||||
.encrypted_page = NULL,
|
||||
};
|
||||
|
||||
if (PageUptodate(page))
|
||||
return LOCKED_PAGE;
|
||||
|
||||
get_node_info(sbi, page->index, &ni);
|
||||
|
||||
if (unlikely(ni.blk_addr == NULL_ADDR)) {
|
||||
@@ -1090,9 +1091,6 @@ static int read_node_page(struct page *page, int op_flags)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (PageUptodate(page))
|
||||
return LOCKED_PAGE;
|
||||
|
||||
fio.new_blkaddr = fio.old_blkaddr = ni.blk_addr;
|
||||
return f2fs_submit_page_bio(&fio);
|
||||
}
|
||||
@@ -1150,16 +1148,21 @@ repeat:
|
||||
|
||||
lock_page(page);
|
||||
|
||||
if (unlikely(!PageUptodate(page))) {
|
||||
f2fs_put_page(page, 1);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
|
||||
f2fs_put_page(page, 1);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
if (unlikely(!PageUptodate(page)))
|
||||
goto out_err;
|
||||
page_hit:
|
||||
f2fs_bug_on(sbi, nid != nid_of_node(page));
|
||||
if(unlikely(nid != nid_of_node(page))) {
|
||||
f2fs_bug_on(sbi, 1);
|
||||
ClearPageUptodate(page);
|
||||
out_err:
|
||||
f2fs_put_page(page, 1);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -1176,24 +1179,6 @@ struct page *get_node_page_ra(struct page *parent, int start)
|
||||
return __get_node_page(sbi, nid, parent, start);
|
||||
}
|
||||
|
||||
void sync_inode_page(struct dnode_of_data *dn)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IS_INODE(dn->node_page) || dn->inode_page == dn->node_page) {
|
||||
ret = update_inode(dn->inode, dn->node_page);
|
||||
} else if (dn->inode_page) {
|
||||
if (!dn->inode_page_locked)
|
||||
lock_page(dn->inode_page);
|
||||
ret = update_inode(dn->inode, dn->inode_page);
|
||||
if (!dn->inode_page_locked)
|
||||
unlock_page(dn->inode_page);
|
||||
} else {
|
||||
ret = update_inode_page(dn->inode);
|
||||
}
|
||||
dn->node_changed = ret ? true: false;
|
||||
}
|
||||
|
||||
static void flush_inline_data(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
struct inode *inode;
|
||||
@@ -1319,7 +1304,7 @@ continue_unlock:
|
||||
return last_page;
|
||||
}
|
||||
|
||||
int fsync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
struct writeback_control *wbc, bool atomic)
|
||||
{
|
||||
pgoff_t index, end;
|
||||
@@ -1327,6 +1312,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
int ret = 0;
|
||||
struct page *last_page = NULL;
|
||||
bool marked = false;
|
||||
nid_t ino = inode->i_ino;
|
||||
|
||||
if (atomic) {
|
||||
last_page = last_fsync_dnode(sbi, ino);
|
||||
@@ -1380,9 +1366,13 @@ continue_unlock:
|
||||
|
||||
if (!atomic || page == last_page) {
|
||||
set_fsync_mark(page, 1);
|
||||
if (IS_INODE(page))
|
||||
if (IS_INODE(page)) {
|
||||
if (is_inode_flag_set(inode,
|
||||
FI_DIRTY_INODE))
|
||||
update_inode(inode, page);
|
||||
set_dentry_mark(page,
|
||||
need_dentry_mark(sbi, ino));
|
||||
}
|
||||
/* may be written by other thread */
|
||||
if (!PageDirty(page))
|
||||
set_page_dirty(page);
|
||||
@@ -1630,6 +1620,7 @@ static int f2fs_write_node_pages(struct address_space *mapping,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
|
||||
struct blk_plug plug;
|
||||
long diff;
|
||||
|
||||
/* balancing f2fs's metadata in background */
|
||||
@@ -1643,7 +1634,9 @@ static int f2fs_write_node_pages(struct address_space *mapping,
|
||||
|
||||
diff = nr_pages_to_write(sbi, NODE, wbc);
|
||||
wbc->sync_mode = WB_SYNC_NONE;
|
||||
blk_start_plug(&plug);
|
||||
sync_node_pages(sbi, wbc);
|
||||
blk_finish_plug(&plug);
|
||||
wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
|
||||
return 0;
|
||||
|
||||
@@ -1657,9 +1650,10 @@ static int f2fs_set_node_page_dirty(struct page *page)
|
||||
{
|
||||
trace_f2fs_set_page_dirty(page, NODE);
|
||||
|
||||
SetPageUptodate(page);
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
f2fs_set_page_dirty_nobuffers(page);
|
||||
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES);
|
||||
SetPagePrivate(page);
|
||||
f2fs_trace_pid(page);
|
||||
@@ -1778,7 +1772,7 @@ static void scan_nat_page(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
}
|
||||
|
||||
static void build_free_nids(struct f2fs_sb_info *sbi)
|
||||
void build_free_nids(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
|
||||
@@ -1787,14 +1781,14 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
|
||||
nid_t nid = nm_i->next_scan_nid;
|
||||
|
||||
/* Enough entries */
|
||||
if (nm_i->fcnt > NAT_ENTRY_PER_BLOCK)
|
||||
if (nm_i->fcnt >= NAT_ENTRY_PER_BLOCK)
|
||||
return;
|
||||
|
||||
/* readahead nat pages to be scanned */
|
||||
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
|
||||
META_NAT, true);
|
||||
|
||||
down_read(&nm_i->nat_tree_lock);
|
||||
percpu_down_read(&nm_i->nat_tree_lock);
|
||||
|
||||
while (1) {
|
||||
struct page *page = get_current_nat_page(sbi, nid);
|
||||
@@ -1826,7 +1820,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
|
||||
remove_free_nid(nm_i, nid);
|
||||
}
|
||||
up_read(&curseg->journal_rwsem);
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
percpu_up_read(&nm_i->nat_tree_lock);
|
||||
|
||||
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
|
||||
nm_i->ra_nid_pages, META_NAT, false);
|
||||
@@ -1925,12 +1919,15 @@ int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
struct free_nid *i, *next;
|
||||
int nr = nr_shrink;
|
||||
|
||||
if (nm_i->fcnt <= MAX_FREE_NIDS)
|
||||
return 0;
|
||||
|
||||
if (!mutex_trylock(&nm_i->build_lock))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nm_i->free_nid_list_lock);
|
||||
list_for_each_entry_safe(i, next, &nm_i->free_nid_list, list) {
|
||||
if (nr_shrink <= 0 || nm_i->fcnt <= NAT_ENTRY_PER_BLOCK)
|
||||
if (nr_shrink <= 0 || nm_i->fcnt <= MAX_FREE_NIDS)
|
||||
break;
|
||||
if (i->state == NID_ALLOC)
|
||||
continue;
|
||||
@@ -1957,7 +1954,7 @@ void recover_inline_xattr(struct inode *inode, struct page *page)
|
||||
|
||||
ri = F2FS_INODE(page);
|
||||
if (!(ri->i_inline & F2FS_INLINE_XATTR)) {
|
||||
clear_inode_flag(F2FS_I(inode), FI_INLINE_XATTR);
|
||||
clear_inode_flag(inode, FI_INLINE_XATTR);
|
||||
goto update_inode;
|
||||
}
|
||||
|
||||
@@ -1999,13 +1996,11 @@ recover_xnid:
|
||||
get_node_info(sbi, new_xnid, &ni);
|
||||
ni.ino = inode->i_ino;
|
||||
set_node_addr(sbi, &ni, NEW_ADDR, false);
|
||||
F2FS_I(inode)->i_xattr_nid = new_xnid;
|
||||
f2fs_i_xnid_write(inode, new_xnid);
|
||||
|
||||
/* 3: update xattr blkaddr */
|
||||
refresh_sit_entry(sbi, NEW_ADDR, blkaddr);
|
||||
set_node_addr(sbi, &ni, blkaddr, false);
|
||||
|
||||
update_inode_page(inode);
|
||||
}
|
||||
|
||||
int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
|
||||
@@ -2027,7 +2022,8 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
|
||||
/* Should not use this inode from free nid list */
|
||||
remove_free_nid(NM_I(sbi), ino);
|
||||
|
||||
SetPageUptodate(ipage);
|
||||
if (!PageUptodate(ipage))
|
||||
SetPageUptodate(ipage);
|
||||
fill_node_footer(ipage, ino, ino, 0, true);
|
||||
|
||||
src = F2FS_INODE(page);
|
||||
@@ -2213,7 +2209,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
|
||||
if (!nm_i->dirty_nat_cnt)
|
||||
return;
|
||||
|
||||
down_write(&nm_i->nat_tree_lock);
|
||||
percpu_down_write(&nm_i->nat_tree_lock);
|
||||
|
||||
/*
|
||||
* if there are no enough space in journal to store dirty nat
|
||||
@@ -2236,7 +2232,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
|
||||
list_for_each_entry_safe(set, tmp, &sets, set_list)
|
||||
__flush_nat_entry_set(sbi, set);
|
||||
|
||||
up_write(&nm_i->nat_tree_lock);
|
||||
percpu_up_write(&nm_i->nat_tree_lock);
|
||||
|
||||
f2fs_bug_on(sbi, nm_i->dirty_nat_cnt);
|
||||
}
|
||||
@@ -2272,7 +2268,8 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
|
||||
|
||||
mutex_init(&nm_i->build_lock);
|
||||
spin_lock_init(&nm_i->free_nid_list_lock);
|
||||
init_rwsem(&nm_i->nat_tree_lock);
|
||||
if (percpu_init_rwsem(&nm_i->nat_tree_lock))
|
||||
return -ENOMEM;
|
||||
|
||||
nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
|
||||
nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP);
|
||||
@@ -2329,7 +2326,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
spin_unlock(&nm_i->free_nid_list_lock);
|
||||
|
||||
/* destroy nat cache */
|
||||
down_write(&nm_i->nat_tree_lock);
|
||||
percpu_down_write(&nm_i->nat_tree_lock);
|
||||
while ((found = __gang_lookup_nat_cache(nm_i,
|
||||
nid, NATVEC_SIZE, natvec))) {
|
||||
unsigned idx;
|
||||
@@ -2354,8 +2351,9 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
kmem_cache_free(nat_entry_set_slab, setvec[idx]);
|
||||
}
|
||||
}
|
||||
up_write(&nm_i->nat_tree_lock);
|
||||
percpu_up_write(&nm_i->nat_tree_lock);
|
||||
|
||||
percpu_free_rwsem(&nm_i->nat_tree_lock);
|
||||
kfree(nm_i->nat_bitmap);
|
||||
sbi->nm_info = NULL;
|
||||
kfree(nm_i);
|
||||
|
||||
@@ -15,18 +15,21 @@
|
||||
#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK)
|
||||
|
||||
/* # of pages to perform synchronous readahead before building free nids */
|
||||
#define FREE_NID_PAGES 4
|
||||
#define FREE_NID_PAGES 8
|
||||
#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES)
|
||||
|
||||
#define DEF_RA_NID_PAGES 4 /* # of nid pages to be readaheaded */
|
||||
#define DEF_RA_NID_PAGES 0 /* # of nid pages to be readaheaded */
|
||||
|
||||
/* maximum readahead size for node during getting data blocks */
|
||||
#define MAX_RA_NODE 128
|
||||
|
||||
/* control the memory footprint threshold (10MB per 1GB ram) */
|
||||
#define DEF_RAM_THRESHOLD 10
|
||||
#define DEF_RAM_THRESHOLD 1
|
||||
|
||||
/* control dirty nats ratio threshold (default: 10% over max nid count) */
|
||||
#define DEF_DIRTY_NAT_RATIO_THRESHOLD 10
|
||||
/* control total # of nats */
|
||||
#define DEF_NAT_CACHE_THRESHOLD 100000
|
||||
|
||||
/* vector size for gang look-up from nat cache that consists of radix tree */
|
||||
#define NATVEC_SIZE 64
|
||||
@@ -126,6 +129,11 @@ static inline bool excess_dirty_nats(struct f2fs_sb_info *sbi)
|
||||
NM_I(sbi)->dirty_nats_ratio / 100;
|
||||
}
|
||||
|
||||
static inline bool excess_cached_nats(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
return NM_I(sbi)->nat_cnt >= DEF_NAT_CACHE_THRESHOLD;
|
||||
}
|
||||
|
||||
enum mem_type {
|
||||
FREE_NIDS, /* indicates the free nid list */
|
||||
NAT_ENTRIES, /* indicates the cached nat entry */
|
||||
|
||||
@@ -153,9 +153,12 @@ retry:
|
||||
f2fs_delete_entry(de, page, dir, einode);
|
||||
iput(einode);
|
||||
goto retry;
|
||||
} else if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
} else {
|
||||
err = __f2fs_add_link(dir, &name, inode,
|
||||
inode->i_ino, inode->i_mode);
|
||||
}
|
||||
err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode);
|
||||
|
||||
goto out;
|
||||
|
||||
out_unmap_put:
|
||||
@@ -175,7 +178,7 @@ static void recover_inode(struct inode *inode, struct page *page)
|
||||
char *name;
|
||||
|
||||
inode->i_mode = le16_to_cpu(raw->i_mode);
|
||||
i_size_write(inode, le64_to_cpu(raw->i_size));
|
||||
f2fs_i_size_write(inode, le64_to_cpu(raw->i_size));
|
||||
inode->i_atime.tv_sec = le64_to_cpu(raw->i_mtime);
|
||||
inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime);
|
||||
inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime);
|
||||
@@ -455,6 +458,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((start + 1) << PAGE_SHIFT > i_size_read(inode))
|
||||
f2fs_i_size_write(inode, (start + 1) << PAGE_SHIFT);
|
||||
|
||||
/*
|
||||
* dest is reserved block, invalidate src block
|
||||
* and then reserve one new block in dnode page.
|
||||
@@ -476,6 +482,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
#endif
|
||||
/* We should not get -ENOSPC */
|
||||
f2fs_bug_on(sbi, err);
|
||||
if (err)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Check the previous node page having this index */
|
||||
@@ -490,9 +498,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_INODE(dn.node_page))
|
||||
sync_inode_page(&dn);
|
||||
|
||||
copy_node_footer(dn.node_page, page);
|
||||
fill_node_footer(dn.node_page, dn.nid, ni.ino,
|
||||
ofs_of_node(page), false);
|
||||
@@ -624,8 +629,12 @@ out:
|
||||
if (err) {
|
||||
bool invalidate = false;
|
||||
|
||||
if (discard_next_dnode(sbi, blkaddr))
|
||||
if (test_opt(sbi, LFS)) {
|
||||
update_meta_page(sbi, NULL, blkaddr);
|
||||
invalidate = true;
|
||||
} else if (discard_next_dnode(sbi, blkaddr)) {
|
||||
invalidate = true;
|
||||
}
|
||||
|
||||
/* Flush all the NAT/SIT pages */
|
||||
while (get_pages(sbi, F2FS_DIRTY_META))
|
||||
|
||||
@@ -241,7 +241,7 @@ void drop_inmem_pages(struct inode *inode)
|
||||
{
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
|
||||
clear_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
|
||||
mutex_lock(&fi->inmem_lock);
|
||||
__revoke_inmem_pages(inode, &fi->inmem_pages, true, false);
|
||||
@@ -346,6 +346,11 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
|
||||
{
|
||||
if (!need)
|
||||
return;
|
||||
|
||||
/* balance_fs_bg is able to be pending */
|
||||
if (excess_cached_nats(sbi))
|
||||
f2fs_balance_fs_bg(sbi);
|
||||
|
||||
/*
|
||||
* We should do GC or end up with checkpoint, if there are so many dirty
|
||||
* dir/node pages without enough free segments.
|
||||
@@ -367,7 +372,9 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
|
||||
try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK);
|
||||
|
||||
if (!available_free_memory(sbi, FREE_NIDS))
|
||||
try_to_free_nids(sbi, NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES);
|
||||
try_to_free_nids(sbi, MAX_FREE_NIDS);
|
||||
else
|
||||
build_free_nids(sbi);
|
||||
|
||||
/* checkpoint is the only way to shrink partial cached entries */
|
||||
if (!available_free_memory(sbi, NAT_ENTRIES) ||
|
||||
@@ -435,25 +442,29 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi)
|
||||
if (test_opt(sbi, NOBARRIER))
|
||||
return 0;
|
||||
|
||||
if (!test_opt(sbi, FLUSH_MERGE)) {
|
||||
if (!test_opt(sbi, FLUSH_MERGE) || !atomic_read(&fcc->submit_flush)) {
|
||||
struct bio *bio = f2fs_bio_alloc(0);
|
||||
int ret;
|
||||
|
||||
atomic_inc(&fcc->submit_flush);
|
||||
bio->bi_bdev = sbi->sb->s_bdev;
|
||||
bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH);
|
||||
ret = submit_bio_wait(bio);
|
||||
atomic_dec(&fcc->submit_flush);
|
||||
bio_put(bio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
init_completion(&cmd.wait);
|
||||
|
||||
atomic_inc(&fcc->submit_flush);
|
||||
llist_add(&cmd.llnode, &fcc->issue_list);
|
||||
|
||||
if (!fcc->dispatch_list)
|
||||
wake_up(&fcc->flush_wait_queue);
|
||||
|
||||
wait_for_completion(&cmd.wait);
|
||||
atomic_dec(&fcc->submit_flush);
|
||||
|
||||
return cmd.ret;
|
||||
}
|
||||
@@ -467,6 +478,7 @@ int create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
||||
fcc = kzalloc(sizeof(struct flush_cmd_control), GFP_KERNEL);
|
||||
if (!fcc)
|
||||
return -ENOMEM;
|
||||
atomic_set(&fcc->submit_flush, 0);
|
||||
init_waitqueue_head(&fcc->flush_wait_queue);
|
||||
init_llist_head(&fcc->issue_list);
|
||||
SM_I(sbi)->cmd_control_info = fcc;
|
||||
@@ -668,6 +680,10 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
break;
|
||||
|
||||
end = __find_rev_next_zero_bit(dmap, max_blocks, start + 1);
|
||||
if (force && start && end != max_blocks
|
||||
&& (end - start) < cpc->trim_minlen)
|
||||
continue;
|
||||
|
||||
__add_discard_entry(sbi, cpc, se, start, end);
|
||||
}
|
||||
}
|
||||
@@ -705,6 +721,8 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
|
||||
unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
|
||||
unsigned int start = 0, end = -1;
|
||||
unsigned int secno, start_segno;
|
||||
bool force = (cpc->reason == CP_DISCARD);
|
||||
|
||||
mutex_lock(&dirty_i->seglist_lock);
|
||||
|
||||
@@ -721,17 +739,31 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
dirty_i->nr_dirty[PRE] -= end - start;
|
||||
|
||||
if (!test_opt(sbi, DISCARD))
|
||||
if (force || !test_opt(sbi, DISCARD))
|
||||
continue;
|
||||
|
||||
f2fs_issue_discard(sbi, START_BLOCK(sbi, start),
|
||||
if (!test_opt(sbi, LFS) || sbi->segs_per_sec == 1) {
|
||||
f2fs_issue_discard(sbi, START_BLOCK(sbi, start),
|
||||
(end - start) << sbi->log_blocks_per_seg);
|
||||
continue;
|
||||
}
|
||||
next:
|
||||
secno = GET_SECNO(sbi, start);
|
||||
start_segno = secno * sbi->segs_per_sec;
|
||||
if (!IS_CURSEC(sbi, secno) &&
|
||||
!get_valid_blocks(sbi, start, sbi->segs_per_sec))
|
||||
f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno),
|
||||
sbi->segs_per_sec << sbi->log_blocks_per_seg);
|
||||
|
||||
start = start_segno + sbi->segs_per_sec;
|
||||
if (start < end)
|
||||
goto next;
|
||||
}
|
||||
mutex_unlock(&dirty_i->seglist_lock);
|
||||
|
||||
/* send small discards */
|
||||
list_for_each_entry_safe(entry, this, head, list) {
|
||||
if (cpc->reason == CP_DISCARD && entry->len < cpc->trim_minlen)
|
||||
if (force && entry->len < cpc->trim_minlen)
|
||||
goto skip;
|
||||
f2fs_issue_discard(sbi, entry->blkaddr, entry->len);
|
||||
cpc->trimmed += entry->len;
|
||||
@@ -1219,6 +1251,9 @@ void allocate_new_segments(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (test_opt(sbi, LFS))
|
||||
return;
|
||||
|
||||
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++)
|
||||
__allocate_new_segments(sbi, i);
|
||||
}
|
||||
@@ -1392,11 +1427,17 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
|
||||
{
|
||||
int type = __get_segment_type(fio->page, fio->type);
|
||||
|
||||
if (fio->type == NODE || fio->type == DATA)
|
||||
mutex_lock(&fio->sbi->wio_mutex[fio->type]);
|
||||
|
||||
allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
|
||||
&fio->new_blkaddr, sum, type);
|
||||
|
||||
/* writeout dirty page into bdev */
|
||||
f2fs_submit_page_mbio(fio);
|
||||
|
||||
if (fio->type == NODE || fio->type == DATA)
|
||||
mutex_unlock(&fio->sbi->wio_mutex[fio->type]);
|
||||
}
|
||||
|
||||
void write_meta_page(struct f2fs_sb_info *sbi, struct page *page)
|
||||
@@ -2377,7 +2418,11 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
|
||||
sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
|
||||
sm_info->rec_prefree_segments = sm_info->main_segments *
|
||||
DEF_RECLAIM_PREFREE_SEGMENTS / 100;
|
||||
sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC;
|
||||
if (sm_info->rec_prefree_segments > DEF_MAX_RECLAIM_PREFREE_SEGMENTS)
|
||||
sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS;
|
||||
|
||||
if (!test_opt(sbi, LFS))
|
||||
sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC;
|
||||
sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
|
||||
sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define NULL_SECNO ((unsigned int)(~0))
|
||||
|
||||
#define DEF_RECLAIM_PREFREE_SEGMENTS 5 /* 5% over total segments */
|
||||
#define DEF_MAX_RECLAIM_PREFREE_SEGMENTS 4096 /* 8GB in maximum */
|
||||
|
||||
/* L: Logical segment # in volume, R: Relative segment # in main area */
|
||||
#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno)
|
||||
@@ -470,6 +471,10 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
|
||||
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
|
||||
|
||||
if (test_opt(sbi, LFS))
|
||||
return false;
|
||||
|
||||
return free_sections(sbi) <= (node_secs + 2 * dent_secs +
|
||||
reserved_sections(sbi) + 1);
|
||||
}
|
||||
@@ -479,6 +484,8 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, int freed)
|
||||
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
|
||||
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
|
||||
|
||||
node_secs += get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
|
||||
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
|
||||
return false;
|
||||
|
||||
@@ -531,6 +538,9 @@ static inline bool need_inplace_update(struct inode *inode)
|
||||
if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode))
|
||||
return false;
|
||||
|
||||
if (test_opt(sbi, LFS))
|
||||
return false;
|
||||
|
||||
if (policy & (0x1 << F2FS_IPU_FORCE))
|
||||
return true;
|
||||
if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi))
|
||||
@@ -544,7 +554,7 @@ static inline bool need_inplace_update(struct inode *inode)
|
||||
|
||||
/* this is only set during fdatasync */
|
||||
if (policy & (0x1 << F2FS_IPU_FSYNC) &&
|
||||
is_inode_flag_set(F2FS_I(inode), FI_NEED_IPU))
|
||||
is_inode_flag_set(inode, FI_NEED_IPU))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -706,9 +716,9 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
|
||||
if (type == DATA)
|
||||
return sbi->blocks_per_seg;
|
||||
else if (type == NODE)
|
||||
return 3 * sbi->blocks_per_seg;
|
||||
return 8 * sbi->blocks_per_seg;
|
||||
else if (type == META)
|
||||
return MAX_BIO_BLOCKS(sbi);
|
||||
return 8 * MAX_BIO_BLOCKS(sbi);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -726,10 +736,8 @@ static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type,
|
||||
|
||||
nr_to_write = wbc->nr_to_write;
|
||||
|
||||
if (type == DATA)
|
||||
desired = 4096;
|
||||
else if (type == NODE)
|
||||
desired = 3 * max_hw_blocks(sbi);
|
||||
if (type == NODE)
|
||||
desired = 2 * max_hw_blocks(sbi);
|
||||
else
|
||||
desired = MAX_BIO_BLOCKS(sbi);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/f2fs_fs.h>
|
||||
|
||||
#include "f2fs.h"
|
||||
#include "node.h"
|
||||
|
||||
static LIST_HEAD(f2fs_list);
|
||||
static DEFINE_SPINLOCK(f2fs_list_lock);
|
||||
@@ -25,8 +26,8 @@ static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi)
|
||||
|
||||
static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
if (NM_I(sbi)->fcnt > NAT_ENTRY_PER_BLOCK)
|
||||
return NM_I(sbi)->fcnt - NAT_ENTRY_PER_BLOCK;
|
||||
if (NM_I(sbi)->fcnt > MAX_FREE_NIDS)
|
||||
return NM_I(sbi)->fcnt - MAX_FREE_NIDS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user