Commit f9a03ae1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-f2fs-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs

Pull f2fs updates from Jaegeuk Kim:
 "This series adds two ioctls to control cached data and fragmented
  files.  Most of the rest fixes missing error cases and bugs that we
  have not covered so far.  Summary:

  Enhancements:
   - support an ioctl to execute online file defragmentation
   - support an ioctl to flush cached data
   - speed up shrinking of extent_cache entries
   - handle broken superblock
   - refector dirty inode management infra
   - revisit f2fs_map_blocks to handle more cases
   - reduce global lock coverage
   - add detecting user's idle time

  Major bug fixes:
   - fix data race condition on cached nat entries
   - fix error cases of volatile and atomic writes"

* tag 'for-f2fs-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (87 commits)
  f2fs: should unset atomic flag after successful commit
  f2fs: fix wrong memory condition check
  f2fs: monitor the number of background checkpoint
  f2fs: detect idle time depending on user behavior
  f2fs: introduce time and interval facility
  f2fs: skip releasing nodes in chindless extent tree
  f2fs: use atomic type for node count in extent tree
  f2fs: recognize encrypted data in f2fs_fiemap
  f2fs: clean up f2fs_balance_fs
  f2fs: remove redundant calls
  f2fs: avoid unnecessary f2fs_balance_fs calls
  f2fs: check the page status filled from disk
  f2fs: introduce __get_node_page to reuse common code
  f2fs: check node id earily when readaheading node page
  f2fs: read isize while holding i_mutex in fiemap
  Revert "f2fs: check the node block address of newly allocated nid"
  f2fs: cover more area with nat_tree_lock
  f2fs: introduce max_file_blocks in sbi
  f2fs crypto: check CONFIG_F2FS_FS_XATTR for encrypted symlink
  f2fs: introduce zombie list for fast shrinking extent trees
  ...
parents 1289ace5 447135a8
...@@ -87,6 +87,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> ...@@ -87,6 +87,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description: Description:
Controls the checkpoint timing. Controls the checkpoint timing.
What: /sys/fs/f2fs/<disk>/idle_interval
Date: January 2016
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description:
Controls the idle timing.
What: /sys/fs/f2fs/<disk>/ra_nid_pages What: /sys/fs/f2fs/<disk>/ra_nid_pages
Date: October 2015 Date: October 2015
Contact: "Chao Yu" <chao2.yu@samsung.com> Contact: "Chao Yu" <chao2.yu@samsung.com>
......
...@@ -102,7 +102,7 @@ background_gc=%s Turn on/off cleaning operations, namely garbage ...@@ -102,7 +102,7 @@ background_gc=%s Turn on/off cleaning operations, namely garbage
collection, triggered in background when I/O subsystem is collection, triggered in background when I/O subsystem is
idle. If background_gc=on, it will turn on the garbage idle. If background_gc=on, it will turn on the garbage
collection and if background_gc=off, garbage collection collection and if background_gc=off, garbage collection
will be truned off. If background_gc=sync, it will turn will be turned off. If background_gc=sync, it will turn
on synchronous garbage collection running in background. on synchronous garbage collection running in background.
Default value for this option is on. So garbage Default value for this option is on. So garbage
collection is on by default. collection is on by default.
...@@ -145,10 +145,12 @@ extent_cache Enable an extent cache based on rb-tree, it can cache ...@@ -145,10 +145,12 @@ extent_cache Enable an extent cache based on rb-tree, it can cache
as many as extent which map between contiguous logical as many as extent which map between contiguous logical
address and physical address per inode, resulting in address and physical address per inode, resulting in
increasing the cache hit ratio. Set by default. increasing the cache hit ratio. Set by default.
noextent_cache Diable an extent cache based on rb-tree explicitly, see noextent_cache Disable an extent cache based on rb-tree explicitly, see
the above extent_cache mount option. the above extent_cache mount option.
noinline_data Disable the inline data feature, inline data feature is noinline_data Disable the inline data feature, inline data feature is
enabled by default. enabled by default.
data_flush Enable data flushing before checkpoint in order to
persist data of regular and symlink.
================================================================================ ================================================================================
DEBUGFS ENTRIES DEBUGFS ENTRIES
...@@ -192,7 +194,7 @@ Files in /sys/fs/f2fs/<devname> ...@@ -192,7 +194,7 @@ Files in /sys/fs/f2fs/<devname>
policy for garbage collection. Setting gc_idle = 0 policy for garbage collection. Setting gc_idle = 0
(default) will disable this option. Setting (default) will disable this option. Setting
gc_idle = 1 will select the Cost Benefit approach gc_idle = 1 will select the Cost Benefit approach
& setting gc_idle = 2 will select the greedy aproach. & setting gc_idle = 2 will select the greedy approach.
reclaim_segments This parameter controls the number of prefree reclaim_segments This parameter controls the number of prefree
segments to be reclaimed. If the number of prefree segments to be reclaimed. If the number of prefree
...@@ -298,7 +300,7 @@ The dump.f2fs shows the information of specific inode and dumps SSA and SIT to ...@@ -298,7 +300,7 @@ The dump.f2fs shows the information of specific inode and dumps SSA and SIT to
file. Each file is dump_ssa and dump_sit. file. Each file is dump_ssa and dump_sit.
The dump.f2fs is used to debug on-disk data structures of the f2fs filesystem. The dump.f2fs is used to debug on-disk data structures of the f2fs filesystem.
It shows on-disk inode information reconized by a given inode number, and is It shows on-disk inode information recognized by a given inode number, and is
able to dump all the SSA and SIT entries into predefined files, ./dump_ssa and able to dump all the SSA and SIT entries into predefined files, ./dump_ssa and
./dump_sit respectively. ./dump_sit respectively.
......
This diff is collapsed.
This diff is collapsed.
...@@ -38,12 +38,15 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -38,12 +38,15 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree); si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree);
si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree; si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree;
si->total_ext = atomic64_read(&sbi->total_hit_ext); si->total_ext = atomic64_read(&sbi->total_hit_ext);
si->ext_tree = sbi->total_ext_tree; si->ext_tree = atomic_read(&sbi->total_ext_tree);
si->zombie_tree = atomic_read(&sbi->total_zombie_tree);
si->ext_node = atomic_read(&sbi->total_ext_node); si->ext_node = atomic_read(&sbi->total_ext_node);
si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES); si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS); si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
si->ndirty_dirs = sbi->n_dirty_dirs;
si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META); si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
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->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
si->wb_pages = get_pages(sbi, F2FS_WRITEBACK); si->wb_pages = get_pages(sbi, F2FS_WRITEBACK);
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
...@@ -105,7 +108,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi) ...@@ -105,7 +108,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
bimodal = 0; bimodal = 0;
total_vblocks = 0; total_vblocks = 0;
blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg); blks_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg;
hblks_per_sec = blks_per_sec / 2; hblks_per_sec = blks_per_sec / 2;
for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
...@@ -189,10 +192,10 @@ static void update_mem_info(struct f2fs_sb_info *sbi) ...@@ -189,10 +192,10 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
si->cache_mem += NM_I(sbi)->dirty_nat_cnt * si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
sizeof(struct nat_entry_set); sizeof(struct nat_entry_set);
si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages); si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
si->cache_mem += sbi->n_dirty_dirs * sizeof(struct inode_entry);
for (i = 0; i <= UPDATE_INO; i++) for (i = 0; i <= UPDATE_INO; i++)
si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
si->cache_mem += sbi->total_ext_tree * sizeof(struct extent_tree); si->cache_mem += atomic_read(&sbi->total_ext_tree) *
sizeof(struct extent_tree);
si->cache_mem += atomic_read(&sbi->total_ext_node) * si->cache_mem += atomic_read(&sbi->total_ext_node) *
sizeof(struct extent_node); sizeof(struct extent_node);
...@@ -267,7 +270,8 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -267,7 +270,8 @@ static int stat_show(struct seq_file *s, void *v)
si->dirty_count); si->dirty_count);
seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n", seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n",
si->prefree_count, si->free_segs, si->free_secs); si->prefree_count, si->free_segs, si->free_secs);
seq_printf(s, "CP calls: %d\n", si->cp_count); seq_printf(s, "CP calls: %d (BG: %d)\n",
si->cp_count, si->bg_cp_count);
seq_printf(s, "GC calls: %d (BG: %d)\n", seq_printf(s, "GC calls: %d (BG: %d)\n",
si->call_count, si->bg_gc); si->call_count, si->bg_gc);
seq_printf(s, " - data segments : %d (%d)\n", seq_printf(s, " - data segments : %d (%d)\n",
...@@ -288,8 +292,8 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -288,8 +292,8 @@ static int stat_show(struct seq_file *s, void *v)
!si->total_ext ? 0 : !si->total_ext ? 0 :
div64_u64(si->hit_total * 100, si->total_ext), div64_u64(si->hit_total * 100, si->total_ext),
si->hit_total, si->total_ext); si->hit_total, si->total_ext);
seq_printf(s, " - Inner Struct Count: tree: %d, node: %d\n", seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
si->ext_tree, si->ext_node); si->ext_tree, si->zombie_tree, si->ext_node);
seq_puts(s, "\nBalancing F2FS Async:\n"); seq_puts(s, "\nBalancing F2FS Async:\n");
seq_printf(s, " - inmem: %4d, wb: %4d\n", seq_printf(s, " - inmem: %4d, wb: %4d\n",
si->inmem_pages, si->wb_pages); si->inmem_pages, si->wb_pages);
...@@ -297,6 +301,8 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -297,6 +301,8 @@ static int stat_show(struct seq_file *s, void *v)
si->ndirty_node, si->node_pages); si->ndirty_node, si->node_pages);
seq_printf(s, " - dents: %4d in dirs:%4d\n", seq_printf(s, " - dents: %4d in dirs:%4d\n",
si->ndirty_dent, si->ndirty_dirs); si->ndirty_dent, si->ndirty_dirs);
seq_printf(s, " - datas: %4d in files:%4d\n",
si->ndirty_data, si->ndirty_files);
seq_printf(s, " - meta: %4d in %4d\n", seq_printf(s, " - meta: %4d in %4d\n",
si->ndirty_meta, si->meta_pages); si->ndirty_meta, si->meta_pages);
seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n",
...@@ -404,20 +410,23 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi) ...@@ -404,20 +410,23 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
kfree(si); kfree(si);
} }
void __init f2fs_create_root_stats(void) int __init f2fs_create_root_stats(void)
{ {
struct dentry *file; struct dentry *file;
f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL); f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL);
if (!f2fs_debugfs_root) if (!f2fs_debugfs_root)
return; return -ENOMEM;
file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root, file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root,
NULL, &stat_fops); NULL, &stat_fops);
if (!file) { if (!file) {
debugfs_remove(f2fs_debugfs_root); debugfs_remove(f2fs_debugfs_root);
f2fs_debugfs_root = NULL; f2fs_debugfs_root = NULL;
return -ENOMEM;
} }
return 0;
} }
void f2fs_destroy_root_stats(void) void f2fs_destroy_root_stats(void)
......
...@@ -172,8 +172,6 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, ...@@ -172,8 +172,6 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
namehash = f2fs_dentry_hash(&name); namehash = f2fs_dentry_hash(&name);
f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH);
nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);
nblock = bucket_blocks(level); nblock = bucket_blocks(level);
...@@ -238,6 +236,14 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, ...@@ -238,6 +236,14 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
goto out; goto out;
max_depth = F2FS_I(dir)->i_current_depth; max_depth = F2FS_I(dir)->i_current_depth;
if (unlikely(max_depth > MAX_DIR_HASH_DEPTH)) {
f2fs_msg(F2FS_I_SB(dir)->sb, KERN_WARNING,
"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);
}
for (level = 0; level < max_depth; level++) { for (level = 0; level < max_depth; level++) {
de = find_in_level(dir, level, &fname, res_page); de = find_in_level(dir, level, &fname, res_page);
...@@ -444,7 +450,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, ...@@ -444,7 +450,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
/* once the failed inode becomes a bad inode, i_mode is S_IFREG */ /* once the failed inode becomes a bad inode, i_mode is S_IFREG */
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
truncate_blocks(inode, 0, false); truncate_blocks(inode, 0, false);
remove_dirty_dir_inode(inode); remove_dirty_inode(inode);
remove_inode_page(inode); remove_inode_page(inode);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -630,6 +636,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, ...@@ -630,6 +636,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
out: out:
f2fs_fname_free_filename(&fname); f2fs_fname_free_filename(&fname);
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
return err; return err;
} }
...@@ -651,6 +658,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir) ...@@ -651,6 +658,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
fail: fail:
up_write(&F2FS_I(inode)->i_sem); up_write(&F2FS_I(inode)->i_sem);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
return err; return err;
} }
...@@ -695,6 +703,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, ...@@ -695,6 +703,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len)); int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
int i; int i;
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
if (f2fs_has_inline_dentry(dir)) if (f2fs_has_inline_dentry(dir))
return f2fs_delete_inline_entry(dentry, page, dir, inode); return f2fs_delete_inline_entry(dentry, page, dir, inode);
...@@ -855,25 +865,27 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -855,25 +865,27 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
for (; n < npages; n++) { for (; n < npages; n++) {
dentry_page = get_lock_data_page(inode, n, false); dentry_page = get_lock_data_page(inode, n, false);
if (IS_ERR(dentry_page)) if (IS_ERR(dentry_page)) {
continue; err = PTR_ERR(dentry_page);
if (err == -ENOENT)
continue;
else
goto out;
}
dentry_blk = kmap(dentry_page); dentry_blk = kmap(dentry_page);
make_dentry_ptr(inode, &d, (void *)dentry_blk, 1); make_dentry_ptr(inode, &d, (void *)dentry_blk, 1);
if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK, &fstr)) if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK, &fstr)) {
goto stop; kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
break;
}
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK; ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
kunmap(dentry_page); kunmap(dentry_page);
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
dentry_page = NULL;
}
stop:
if (dentry_page && !IS_ERR(dentry_page)) {
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
} }
out: out:
f2fs_fname_crypto_free_buffer(&fstr); f2fs_fname_crypto_free_buffer(&fstr);
......
...@@ -36,7 +36,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi, ...@@ -36,7 +36,7 @@ static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi,
rb_link_node(&en->rb_node, parent, p); rb_link_node(&en->rb_node, parent, p);
rb_insert_color(&en->rb_node, &et->root); rb_insert_color(&en->rb_node, &et->root);
et->count++; atomic_inc(&et->node_cnt);
atomic_inc(&sbi->total_ext_node); atomic_inc(&sbi->total_ext_node);
return en; return en;
} }
...@@ -45,7 +45,7 @@ static void __detach_extent_node(struct f2fs_sb_info *sbi, ...@@ -45,7 +45,7 @@ static void __detach_extent_node(struct f2fs_sb_info *sbi,
struct extent_tree *et, struct extent_node *en) struct extent_tree *et, struct extent_node *en)
{ {
rb_erase(&en->rb_node, &et->root); rb_erase(&en->rb_node, &et->root);
et->count--; atomic_dec(&et->node_cnt);
atomic_dec(&sbi->total_ext_node); atomic_dec(&sbi->total_ext_node);
if (et->cached_en == en) if (et->cached_en == en)
...@@ -68,11 +68,13 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode) ...@@ -68,11 +68,13 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode)
et->root = RB_ROOT; et->root = RB_ROOT;
et->cached_en = NULL; et->cached_en = NULL;
rwlock_init(&et->lock); rwlock_init(&et->lock);
atomic_set(&et->refcount, 0); INIT_LIST_HEAD(&et->list);
et->count = 0; atomic_set(&et->node_cnt, 0);
sbi->total_ext_tree++; atomic_inc(&sbi->total_ext_tree);
} else {
atomic_dec(&sbi->total_zombie_tree);
list_del_init(&et->list);
} }
atomic_inc(&et->refcount);
up_write(&sbi->extent_tree_lock); up_write(&sbi->extent_tree_lock);
/* never died until evict_inode */ /* never died until evict_inode */
...@@ -131,7 +133,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, ...@@ -131,7 +133,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
{ {
struct rb_node *node, *next; struct rb_node *node, *next;
struct extent_node *en; struct extent_node *en;
unsigned int count = et->count; unsigned int count = atomic_read(&et->node_cnt);
node = rb_first(&et->root); node = rb_first(&et->root);
while (node) { while (node) {
...@@ -152,7 +154,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, ...@@ -152,7 +154,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
node = next; node = next;
} }
return count - et->count; return count - atomic_read(&et->node_cnt);
} }
static void __drop_largest_extent(struct inode *inode, static void __drop_largest_extent(struct inode *inode,
...@@ -164,34 +166,33 @@ static void __drop_largest_extent(struct inode *inode, ...@@ -164,34 +166,33 @@ static void __drop_largest_extent(struct inode *inode,
largest->len = 0; largest->len = 0;
} }
void f2fs_drop_largest_extent(struct inode *inode, pgoff_t fofs) /* return true, if inode page is changed */
{ bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
if (!f2fs_may_extent_tree(inode))
return;
__drop_largest_extent(inode, fofs, 1);
}
void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct extent_tree *et; struct extent_tree *et;
struct extent_node *en; struct extent_node *en;
struct extent_info ei; struct extent_info ei;
if (!f2fs_may_extent_tree(inode)) if (!f2fs_may_extent_tree(inode)) {
return; /* drop largest extent */
if (i_ext && i_ext->len) {
i_ext->len = 0;
return true;
}
return false;
}
et = __grab_extent_tree(inode); et = __grab_extent_tree(inode);
if (!i_ext || le32_to_cpu(i_ext->len) < F2FS_MIN_EXTENT_LEN) if (!i_ext || !i_ext->len)
return; return false;
set_extent_info(&ei, le32_to_cpu(i_ext->fofs), set_extent_info(&ei, le32_to_cpu(i_ext->fofs),
le32_to_cpu(i_ext->blk), le32_to_cpu(i_ext->len)); le32_to_cpu(i_ext->blk), le32_to_cpu(i_ext->len));
write_lock(&et->lock); write_lock(&et->lock);
if (et->count) if (atomic_read(&et->node_cnt))
goto out; goto out;
en = __init_extent_tree(sbi, et, &ei); en = __init_extent_tree(sbi, et, &ei);
...@@ -202,6 +203,7 @@ void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) ...@@ -202,6 +203,7 @@ void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext)
} }
out: out:
write_unlock(&et->lock); write_unlock(&et->lock);
return false;
} }
static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
...@@ -549,45 +551,44 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode, ...@@ -549,45 +551,44 @@ static unsigned int f2fs_update_extent_tree_range(struct inode *inode,
unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
{ {
struct extent_tree *treevec[EXT_TREE_VEC_SIZE]; struct extent_tree *treevec[EXT_TREE_VEC_SIZE];
struct extent_tree *et, *next;
struct extent_node *en, *tmp; struct extent_node *en, *tmp;
unsigned long ino = F2FS_ROOT_INO(sbi); unsigned long ino = F2FS_ROOT_INO(sbi);
struct radix_tree_root *root = &sbi->extent_tree_root;
unsigned int found; unsigned int found;
unsigned int node_cnt = 0, tree_cnt = 0; unsigned int node_cnt = 0, tree_cnt = 0;
int remained; int remained;
bool do_free = false;
if (!test_opt(sbi, EXTENT_CACHE)) if (!test_opt(sbi, EXTENT_CACHE))
return 0; return 0;
if (!atomic_read(&sbi->total_zombie_tree))
goto free_node;
if (!down_write_trylock(&sbi->extent_tree_lock)) if (!down_write_trylock(&sbi->extent_tree_lock))
goto out; goto out;
/* 1. remove unreferenced extent tree */ /* 1. remove unreferenced extent tree */
while ((found = radix_tree_gang_lookup(root, list_for_each_entry_safe(et, next, &sbi->zombie_list, list) {
(void **)treevec, ino, EXT_TREE_VEC_SIZE))) { if (atomic_read(&et->node_cnt)) {
unsigned i; write_lock(&et->lock);
node_cnt += __free_extent_tree(sbi, et, true);
ino = treevec[found - 1]->ino + 1; write_unlock(&et->lock);
for (i = 0; i < found; i++) { }
struct extent_tree *et = treevec[i];
if (!atomic_read(&et->refcount)) {
write_lock(&et->lock);
node_cnt += __free_extent_tree(sbi, et, true);
write_unlock(&et->lock);
radix_tree_delete(root, et->ino); list_del_init(&et->list);
kmem_cache_free(extent_tree_slab, et); radix_tree_delete(&sbi->extent_tree_root, et->ino);
sbi->total_ext_tree--; kmem_cache_free(extent_tree_slab, et);
tree_cnt++; atomic_dec(&sbi->total_ext_tree);
atomic_dec(&sbi->total_zombie_tree);
tree_cnt++;
if (node_cnt + tree_cnt >= nr_shrink) if (node_cnt + tree_cnt >= nr_shrink)
goto unlock_out; goto unlock_out;
}
}
} }
up_write(&sbi->extent_tree_lock); up_write(&sbi->extent_tree_lock);
free_node:
/* 2. remove LRU extent entries */ /* 2. remove LRU extent entries */
if (!down_write_trylock(&sbi->extent_tree_lock)) if (!down_write_trylock(&sbi->extent_tree_lock))
goto out; goto out;
...@@ -599,15 +600,19 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) ...@@ -599,15 +600,19 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
if (!remained--) if (!remained--)
break; break;
list_del_init(&en->list); list_del_init(&en->list);
do_free = true;
} }
spin_unlock(&sbi->extent_lock); spin_unlock(&sbi->extent_lock);
if (do_free == false)
goto unlock_out;
/* /*
* reset ino for searching victims from beginning of global extent tree. * reset ino for searching victims from beginning of global extent tree.
*/ */
ino = F2FS_ROOT_INO(sbi); ino = F2FS_ROOT_INO(sbi);
while ((found = radix_tree_gang_lookup(root, while ((found = radix_tree_gang_lookup(&sbi->extent_tree_root,
(void **)treevec, ino, EXT_TREE_VEC_SIZE))) { (void **)treevec, ino, EXT_TREE_VEC_SIZE))) {
unsigned i; unsigned i;
...@@ -615,9 +620,13 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink) ...@@ -615,9 +620,13 @@ unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
for (i = 0; i < found; i++) { for (i = 0; i < found; i++) {
struct extent_tree *et = treevec[i]; struct extent_tree *et = treevec[i];
write_lock(&et->lock); if (!atomic_read(&et->node_cnt))
node_cnt += __free_extent_tree(sbi, et, false); continue;
write_unlock(&et->lock);
if (write_trylock(&et->lock)) {
node_cnt += __free_extent_tree(sbi, et, false);
write_unlock(&et->lock);
}
if (node_cnt + tree_cnt >= nr_shrink) if (node_cnt + tree_cnt >= nr_shrink)
goto unlock_out; goto unlock_out;
...@@ -637,7 +646,7 @@ unsigned int f2fs_destroy_extent_node(struct inode *inode) ...@@ -637,7 +646,7 @@ unsigned int f2fs_destroy_extent_node(struct inode *inode)
struct extent_tree *et = F2FS_I(inode)->extent_tree; struct extent_tree *et = F2FS_I(inode)->extent_tree;
unsigned int node_cnt = 0; unsigned int node_cnt = 0;
if (!et) if (!et || !atomic_read(&et->node_cnt))
return 0; return 0;
write_lock(&et->lock); write_lock(&et->lock);
...@@ -656,8 +665,12 @@ void f2fs_destroy_extent_tree(struct inode *inode) ...@@ -656,8 +665,12 @@ void f2fs_destroy_extent_tree(struct inode *inode)
if (!et) if (!et)
return; return;
if (inode->i_nlink && !is_bad_inode(inode) && et->count) { if (inode->i_nlink && !is_bad_inode(inode) &&
atomic_dec(&et->refcount); atomic_read(&et->node_cnt)) {
down_write(&sbi->extent_tree_lock);
list_add_tail(&et->list, &sbi->zombie_list);
atomic_inc(&sbi->total_zombie_tree);
up_write(&sbi->extent_tree_lock);
return; return;
} }
...@@ -666,11 +679,10 @@ void f2fs_destroy_extent_tree(struct inode *inode) ...@@ -666,11 +679,10 @@ void f2fs_destroy_extent_tree(struct inode *inode)
/* delete extent tree entry in radix tree */ /* delete extent tree entry in radix tree */
down_write(&sbi->extent_tree_lock); down_write(&sbi->extent_tree_lock);
atomic_dec(&et->refcount); f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
f2fs_bug_on(sbi, atomic_read(&et->refcount) || et->count);
radix_tree_delete(&sbi->extent_tree_root, inode->i_ino); radix_tree_delete(&sbi->extent_tree_root, inode->i_ino);
kmem_cache_free(extent_tree_slab, et); kmem_cache_free(extent_tree_slab, et);
sbi->total_ext_tree--; atomic_dec(&sbi->total_ext_tree);
up_write(&sbi->extent_tree_lock); up_write(&sbi->extent_tree_lock);
F2FS_I(inode)->extent_tree = NULL; F2FS_I(inode)->extent_tree = NULL;
...@@ -722,7 +734,9 @@ void init_extent_cache_info(struct f2fs_sb_info *sbi) ...@@ -722,7 +734,9 @@ void init_extent_cache_info(struct f2fs_sb_info *sbi)
init_rwsem(&sbi->extent_tree_lock); init_rwsem(&sbi->extent_tree_lock);
INIT_LIST_HEAD(&sbi->extent_list); INIT_LIST_HEAD(&sbi->extent_list);
spin_lock_init(&sbi->extent_lock); spin_lock_init(&sbi->extent_lock);
sbi->total_ext_tree = 0; atomic_set(&sbi->total_ext_tree, 0);
INIT_LIST_HEAD(&sbi->zombie_list);
atomic_set(&sbi->total_zombie_tree, 0);
atomic_set(&sbi->total_ext_node, 0); atomic_set(&sbi->total_ext_node, 0);
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/blkdev.h>
#include "f2fs.h" #include "f2fs.h"
#include "node.h" #include "node.h"
...@@ -173,9 +172,9 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi, ...@@ -173,9 +172,9 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
{ {
/* SSR allocates in a segment unit */ /* SSR allocates in a segment unit */
if (p->alloc_mode == SSR) if (p->alloc_mode == SSR)
return 1 << sbi->log_blocks_per_seg; return sbi->blocks_per_seg;
if (p->gc_mode == GC_GREEDY) if (p->gc_mode == GC_GREEDY)
return (1 << sbi->log_blocks_per_seg) * p->ofs_unit; return sbi->blocks_per_seg * p->ofs_unit;
else if (p->gc_mode == GC_CB) else if (p->gc_mode == GC_CB)
return UINT_MAX; return UINT_MAX;
else /* No other gc_mode */ else /* No other gc_mode */
...@@ -832,8 +831,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync) ...@@ -832,8 +831,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync)
if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE))) if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
goto stop; goto stop;
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi))) {
ret = -EIO;
goto stop; goto stop;
}
if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed)) { if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed)) {
gc_type = FG_GC; gc_type = FG_GC;
......
...@@ -100,11 +100,3 @@ static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi) ...@@ -100,11 +100,3 @@ static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
return true; return true;
return false; return false;
} }
static inline int is_idle(struct f2fs_sb_info *sbi)
{
struct block_device *bdev = sbi->sb->s_bdev;
struct request_queue *q = bdev_get_queue(bdev);
struct request_list *rl = &q->root_rl;
return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]);
}
...@@ -16,9 +16,6 @@ ...@@ -16,9 +16,6 @@
bool f2fs_may_inline_data(struct inode *inode) bool f2fs_may_inline_data(struct inode *inode)
{ {
if (!test_opt(F2FS_I_SB(inode), INLINE_DATA))
return false;
if (f2fs_is_atomic_file(inode)) if (f2fs_is_atomic_file(inode))
return false; return false;
...@@ -177,6 +174,9 @@ int f2fs_convert_inline_inode(struct inode *inode) ...@@ -177,6 +174,9 @@ int f2fs_convert_inline_inode(struct inode *inode)
struct page *ipage, *page; struct page *ipage, *page;
int err = 0; int err = 0;
if (!f2fs_has_inline_data(inode))
return 0;
page = grab_cache_page(inode->i_mapping, 0); page = grab_cache_page(inode->i_mapping, 0);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
...@@ -199,6 +199,9 @@ int f2fs_convert_inline_inode(struct inode *inode) ...@@ -199,6 +199,9 @@ int f2fs_convert_inline_inode(struct inode *inode)
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
f2fs_balance_fs(sbi, dn.node_changed);
return err; return err;
} }
......
...@@ -138,7 +138,8 @@ static int do_read_inode(struct inode *inode) ...@@ -138,7 +138,8 @@ static int do_read_inode(struct inode *inode)
fi->i_pino = le32_to_cpu(ri->i_pino); fi->i_pino = le32_to_cpu(ri->i_pino);
fi->i_dir_level = ri->i_dir_level; fi->i_dir_level = ri->i_dir_level;
f2fs_init_extent_tree(inode, &ri->i_ext); if (f2fs_init_extent_tree(inode, &ri->i_ext))
set_page_dirty(node_page);
get_inline_info(fi, ri); get_inline_info(fi, ri);
...@@ -222,7 +223,7 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) ...@@ -222,7 +223,7 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
void update_inode(struct inode *inode, struct page *node_page) int update_inode(struct inode *inode, struct page *node_page)
{ {
struct f2fs_inode *ri; struct f2fs_inode *ri;
...@@ -260,15 +261,16 @@ void update_inode(struct inode *inode, struct page *node_page) ...@@ -260,15 +261,16 @@ void update_inode(struct inode *inode, struct page *node_page)
__set_inode_rdev(inode, ri); __set_inode_rdev(inode, ri);
set_cold_node(inode, node_page); set_cold_node(inode, node_page);
set_page_dirty(node_page);
clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
return set_page_dirty(node_page);
} }
void update_inode_page(struct inode *inode) int update_inode_page(struct inode *inode)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct page *node_page; struct page *node_page;
int ret = 0;
retry: retry:
node_page = get_node_page(sbi, inode->i_ino); node_page = get_node_page(sbi, inode->i_ino);
if (IS_ERR(node_page)) { if (IS_ERR(node_page)) {
...@@ -279,10 +281,11 @@ void update_inode_page(struct inode *inode) ...@@ -279,10 +281,11 @@ void update_inode_page(struct inode *inode)
} else if (err != -ENOENT) { } else if (err != -ENOENT) {
f2fs_stop_checkpoint(sbi); f2fs_stop_checkpoint(sbi);
} }
return; return 0;
} }
update_inode(inode, node_page); ret = update_inode(inode, node_page);
f2fs_put_page(node_page, 1); f2fs_put_page(node_page, 1);
return ret;
} }
int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
...@@ -300,9 +303,8 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -300,9 +303,8 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
* We need to balance fs here to prevent from producing dirty node pages * We need to balance fs here to prevent from producing dirty node pages
* during the urgent cleaning time when runing out of free sections. * during the urgent cleaning time when runing out of free sections.
*/ */
update_inode_page(inode); if (update_inode_page(inode))
f2fs_balance_fs(sbi, true);
f2fs_balance_fs(sbi);
return 0; return 0;
} }
...@@ -328,7 +330,7 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -328,7 +330,7 @@ void f2fs_evict_inode(struct inode *inode)
goto out_clear; goto out_clear;
f2fs_bug_on(sbi, get_dirty_pages(inode)); f2fs_bug_on(sbi, get_dirty_pages(inode));
remove_dirty_dir_inode(inode); remove_dirty_inode(inode);
f2fs_destroy_extent_tree(inode); f2fs_destroy_extent_tree(inode);
...@@ -358,9 +360,9 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -358,9 +360,9 @@ void f2fs_evict_inode(struct inode *inode)
if (xnid) if (xnid)
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid); invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
if (is_inode_flag_set(fi, FI_APPEND_WRITE)) if (is_inode_flag_set(fi, FI_APPEND_WRITE))
add_dirty_inode(sbi, inode->i_ino, APPEND_INO); add_ino_entry(sbi, inode->i_ino, APPEND_INO);
if (is_inode_flag_set(fi, FI_UPDATE_WRITE)) if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
add_dirty_inode(sbi, inode->i_ino, UPDATE_INO); add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
if (is_inode_flag_set(fi, FI_FREE_NID)) { if (is_inode_flag_set(fi, FI_FREE_NID)) {
if (err && err != -ENOENT) if (err && err != -ENOENT)
alloc_nid_done(sbi, inode->i_ino); alloc_nid_done(sbi, inode->i_ino);
......
...@@ -60,7 +60,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) ...@@ -60,7 +60,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode))
f2fs_set_encrypted_inode(inode); f2fs_set_encrypted_inode(inode);
if (f2fs_may_inline_data(inode)) if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
set_inode_flag(F2FS_I(inode), FI_INLINE_DATA); set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
if (f2fs_may_inline_dentry(inode)) if (f2fs_may_inline_dentry(inode))
set_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY); set_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
...@@ -128,8 +128,6 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -128,8 +128,6 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
nid_t ino = 0; nid_t ino = 0;
int err; int err;
f2fs_balance_fs(sbi);
inode = f2fs_new_inode(dir, mode); inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -142,6 +140,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -142,6 +140,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
inode->i_mapping->a_ops = &f2fs_dblock_aops; inode->i_mapping->a_ops = &f2fs_dblock_aops;
ino = inode->i_ino; ino = inode->i_ino;
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
if (err) if (err)
...@@ -172,7 +172,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -172,7 +172,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
!f2fs_is_child_context_consistent_with_parent(dir, inode)) !f2fs_is_child_context_consistent_with_parent(dir, inode))
return -EPERM; return -EPERM;
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi, true);
inode->i_ctime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME;
ihold(inode); ihold(inode);
...@@ -214,6 +214,15 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino) ...@@ -214,6 +214,15 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
struct page *page; struct page *page;
int err = 0; int err = 0;
if (f2fs_readonly(sbi->sb)) {
f2fs_msg(sbi->sb, KERN_INFO,
"skip recovering inline_dots inode (ino:%lu, pino:%u) "
"in readonly mountpoint", dir->i_ino, pino);
return 0;
}
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
de = f2fs_find_entry(dir, &dot, &page); de = f2fs_find_entry(dir, &dot, &page);
...@@ -288,12 +297,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -288,12 +297,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
int err = -ENOENT; int err = -ENOENT;
trace_f2fs_unlink_enter(dir, dentry); trace_f2fs_unlink_enter(dir, dentry);
f2fs_balance_fs(sbi);
de = f2fs_find_entry(dir, &dentry->d_name, &page); de = f2fs_find_entry(dir, &dentry->d_name, &page);
if (!de) if (!de)
goto fail; goto fail;
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi); err = acquire_orphan_inode(sbi);
if (err) { if (err) {
...@@ -344,8 +354,6 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -344,8 +354,6 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
if (len > dir->i_sb->s_blocksize) if (len > dir->i_sb->s_blocksize)
return -ENAMETOOLONG; return -ENAMETOOLONG;
f2fs_balance_fs(sbi);
inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO); inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -357,6 +365,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -357,6 +365,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
inode_nohighmem(inode); inode_nohighmem(inode);
inode->i_mapping->a_ops = &f2fs_dblock_aops; inode->i_mapping->a_ops = &f2fs_dblock_aops;
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
if (err) if (err)
...@@ -437,8 +447,6 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -437,8 +447,6 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
struct inode *inode; struct inode *inode;
int err; int err;
f2fs_balance_fs(sbi);
inode = f2fs_new_inode(dir, S_IFDIR | mode); inode = f2fs_new_inode(dir, S_IFDIR | mode);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -448,6 +456,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -448,6 +456,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
inode->i_mapping->a_ops = &f2fs_dblock_aops; inode->i_mapping->a_ops = &f2fs_dblock_aops;
mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO);
f2fs_balance_fs(sbi, true);
set_inode_flag(F2FS_I(inode), FI_INC_LINK); set_inode_flag(F2FS_I(inode), FI_INC_LINK);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
...@@ -485,8 +495,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -485,8 +495,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
struct inode *inode; struct inode *inode;
int err = 0; int err = 0;
f2fs_balance_fs(sbi);
inode = f2fs_new_inode(dir, mode); inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -494,6 +502,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -494,6 +502,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
init_special_inode(inode, inode->i_mode, rdev); init_special_inode(inode, inode->i_mode, rdev);
inode->i_op = &f2fs_special_inode_operations; inode->i_op = &f2fs_special_inode_operations;
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
if (err) if (err)
...@@ -520,9 +530,6 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -520,9 +530,6 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
struct inode *inode; struct inode *inode;
int err; int err;
if (!whiteout)
f2fs_balance_fs(sbi);
inode = f2fs_new_inode(dir, mode); inode = f2fs_new_inode(dir, mode);
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
...@@ -536,6 +543,8 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -536,6 +543,8 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
inode->i_mapping->a_ops = &f2fs_dblock_aops; inode->i_mapping->a_ops = &f2fs_dblock_aops;
} }
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi); err = acquire_orphan_inode(sbi);
if (err) if (err)
...@@ -608,8 +617,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -608,8 +617,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out; goto out;
} }
f2fs_balance_fs(sbi);
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_entry) if (!old_entry)
goto out; goto out;
...@@ -639,6 +646,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -639,6 +646,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!new_entry) if (!new_entry)
goto out_whiteout; goto out_whiteout;
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = acquire_orphan_inode(sbi); err = acquire_orphan_inode(sbi);
...@@ -670,6 +679,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -670,6 +679,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
update_inode_page(old_inode); update_inode_page(old_inode);
update_inode_page(new_inode); update_inode_page(new_inode);
} else { } else {
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(new_dentry, old_inode); err = f2fs_add_link(new_dentry, old_inode);
...@@ -767,8 +778,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -767,8 +778,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
new_inode))) new_inode)))
return -EPERM; return -EPERM;
f2fs_balance_fs(sbi);
old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_entry) if (!old_entry)
goto out; goto out;
...@@ -811,6 +820,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -811,6 +820,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out_new_dir; goto out_new_dir;
} }
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = update_dent_inode(old_inode, new_inode, &new_dentry->d_name); err = update_dent_inode(old_inode, new_inode, &new_dentry->d_name);
...@@ -933,7 +944,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, ...@@ -933,7 +944,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
{ {
struct page *cpage = NULL; struct page *cpage = NULL;
char *caddr, *paddr = NULL; char *caddr, *paddr = NULL;
struct f2fs_str cstr; struct f2fs_str cstr = FSTR_INIT(NULL, 0);
struct f2fs_str pstr = FSTR_INIT(NULL, 0); struct f2fs_str pstr = FSTR_INIT(NULL, 0);
struct f2fs_encrypted_symlink_data *sd; struct f2fs_encrypted_symlink_data *sd;
loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
...@@ -956,6 +967,12 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, ...@@ -956,6 +967,12 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
/* Symlink is encrypted */ /* Symlink is encrypted */
sd = (struct f2fs_encrypted_symlink_data *)caddr; sd = (struct f2fs_encrypted_symlink_data *)caddr;
cstr.len = le16_to_cpu(sd->len); cstr.len = le16_to_cpu(sd->len);
/* this is broken symlink case */
if (unlikely(cstr.len == 0)) {
res = -ENOENT;
goto errout;
}
cstr.name = kmalloc(cstr.len, GFP_NOFS); cstr.name = kmalloc(cstr.len, GFP_NOFS);
if (!cstr.name) { if (!cstr.name) {
res = -ENOMEM; res = -ENOMEM;
...@@ -964,7 +981,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, ...@@ -964,7 +981,7 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry,
memcpy(cstr.name, sd->encrypted_path, cstr.len); memcpy(cstr.name, sd->encrypted_path, cstr.len);
/* this is broken symlink case */ /* this is broken symlink case */
if (cstr.name[0] == 0 && cstr.len == 0) { if (unlikely(cstr.name[0] == 0)) {
res = -ENOENT; res = -ENOENT;
goto errout; goto errout;
} }
...@@ -1005,10 +1022,12 @@ const struct inode_operations f2fs_encrypted_symlink_inode_operations = { ...@@ -1005,10 +1022,12 @@ const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
.get_link = f2fs_encrypted_get_link, .get_link = f2fs_encrypted_get_link,
.getattr = f2fs_getattr, .getattr = f2fs_getattr,
.setattr = f2fs_setattr, .setattr = f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
.setxattr = generic_setxattr, .setxattr = generic_setxattr,
.getxattr = generic_getxattr, .getxattr = generic_getxattr,
.listxattr = f2fs_listxattr, .listxattr = f2fs_listxattr,
.removexattr = generic_removexattr, .removexattr = generic_removexattr,
#endif
}; };
#endif #endif
......
This diff is collapsed.
...@@ -183,7 +183,7 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start) ...@@ -183,7 +183,7 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start)
block_addr = (pgoff_t)(nm_i->nat_blkaddr + block_addr = (pgoff_t)(nm_i->nat_blkaddr +
(seg_off << sbi->log_blocks_per_seg << 1) + (seg_off << sbi->log_blocks_per_seg << 1) +
(block_off & ((1 << sbi->log_blocks_per_seg) - 1))); (block_off & (sbi->blocks_per_seg - 1)));
if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
block_addr += sbi->blocks_per_seg; block_addr += sbi->blocks_per_seg;
...@@ -317,7 +317,7 @@ static inline bool IS_DNODE(struct page *node_page) ...@@ -317,7 +317,7 @@ static inline bool IS_DNODE(struct page *node_page)
return true; return true;
} }
static inline void set_nid(struct page *p, int off, nid_t nid, bool i) static inline int set_nid(struct page *p, int off, nid_t nid, bool i)
{ {
struct f2fs_node *rn = F2FS_NODE(p); struct f2fs_node *rn = F2FS_NODE(p);
...@@ -327,7 +327,7 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i) ...@@ -327,7 +327,7 @@ static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid); rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
else else
rn->in.nid[off] = cpu_to_le32(nid); rn->in.nid[off] = cpu_to_le32(nid);
set_page_dirty(p); return set_page_dirty(p);
} }
static inline nid_t get_nid(struct page *p, int off, bool i) static inline nid_t get_nid(struct page *p, int off, bool i)
......
...@@ -168,6 +168,32 @@ static void recover_inode(struct inode *inode, struct page *page) ...@@ -168,6 +168,32 @@ static void recover_inode(struct inode *inode, struct page *page)
ino_of_node(page), name); ino_of_node(page), name);
} }
static bool is_same_inode(struct inode *inode, struct page *ipage)
{
struct f2fs_inode *ri = F2FS_INODE(ipage);
struct timespec disk;
if (!IS_INODE(ipage))
return true;
disk.tv_sec = le64_to_cpu(ri->i_ctime);
disk.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
if (timespec_compare(&inode->i_ctime, &disk) > 0)
return false;
disk.tv_sec = le64_to_cpu(ri->i_atime);
disk.tv_nsec = le32_to_cpu(ri->i_atime_nsec);
if (timespec_compare(&inode->i_atime, &disk) > 0)
return false;
disk.tv_sec = le64_to_cpu(ri->i_mtime);
disk.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
if (timespec_compare(&inode->i_mtime, &disk) > 0)
return false;
return true;
}
static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
{ {
unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
...@@ -197,7 +223,10 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -197,7 +223,10 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
goto next; goto next;
entry = get_fsync_inode(head, ino_of_node(page)); entry = get_fsync_inode(head, ino_of_node(page));
if (!entry) { if (entry) {
if (!is_same_inode(entry->inode, page))
goto next;
} else {
if (IS_INODE(page) && is_dent_dnode(page)) { if (IS_INODE(page) && is_dent_dnode(page)) {
err = recover_inode_page(sbi, page); err = recover_inode_page(sbi, page);
if (err) if (err)
...@@ -459,8 +488,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -459,8 +488,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
return err; return err;
} }
static int recover_data(struct f2fs_sb_info *sbi, static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
struct list_head *head, int type)
{ {
unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
struct curseg_info *curseg; struct curseg_info *curseg;
...@@ -469,7 +497,7 @@ static int recover_data(struct f2fs_sb_info *sbi, ...@@ -469,7 +497,7 @@ static int recover_data(struct f2fs_sb_info *sbi,
block_t blkaddr; block_t blkaddr;
/* get node pages in the current segment */ /* get node pages in the current segment */
curseg = CURSEG_I(sbi, type); curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
while (1) { while (1) {
...@@ -556,7 +584,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -556,7 +584,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
need_writecp = true; need_writecp = true;
/* step #2: recover data */ /* step #2: recover data */
err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE); err = recover_data(sbi, &inode_list);
if (!err) if (!err)
f2fs_bug_on(sbi, !list_empty(&inode_list)); f2fs_bug_on(sbi, !list_empty(&inode_list));
out: out:
...@@ -595,7 +623,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -595,7 +623,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
.reason = CP_RECOVERY, .reason = CP_RECOVERY,
}; };
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
write_checkpoint(sbi, &cpc); err = write_checkpoint(sbi, &cpc);
} else { } else {
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
} }
......
...@@ -86,6 +86,7 @@ static inline unsigned long __reverse_ffs(unsigned long word) ...@@ -86,6 +86,7 @@ static inline unsigned long __reverse_ffs(unsigned long word)
/* /*
* __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because
* f2fs_set_bit makes MSB and LSB reversed in a byte. * f2fs_set_bit makes MSB and LSB reversed in a byte.
* @size must be integral times of unsigned long.
* Example: * Example:
* MSB <--> LSB * MSB <--> LSB
* f2fs_set_bit(0, bitmap) => 1000 0000 * f2fs_set_bit(0, bitmap) => 1000 0000
...@@ -95,94 +96,73 @@ static unsigned long __find_rev_next_bit(const unsigned long *addr, ...@@ -95,94 +96,73 @@ static unsigned long __find_rev_next_bit(const unsigned long *addr,
unsigned long size, unsigned long offset) unsigned long size, unsigned long offset)
{ {
const unsigned long *p = addr + BIT_WORD(offset); const unsigned long *p = addr + BIT_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG - 1); unsigned long result = size;
unsigned long tmp; unsigned long tmp;
if (offset >= size) if (offset >= size)
return size; return size;
size -= result; size -= (offset & ~(BITS_PER_LONG - 1));
offset %= BITS_PER_LONG; offset %= BITS_PER_LONG;
if (!offset)
goto aligned; while (1) {
if (*p == 0)
tmp = __reverse_ulong((unsigned char *)p); goto pass;
tmp &= ~0UL >> offset;
if (size < BITS_PER_LONG)
goto found_first;
if (tmp)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
p++;
aligned:
while (size & ~(BITS_PER_LONG-1)) {
tmp = __reverse_ulong((unsigned char *)p); tmp = __reverse_ulong((unsigned char *)p);
tmp &= ~0UL >> offset;
if (size < BITS_PER_LONG)
tmp &= (~0UL << (BITS_PER_LONG - size));
if (tmp) if (tmp)
goto found_middle; goto found;
result += BITS_PER_LONG; pass:
if (size <= BITS_PER_LONG)
break;
size -= BITS_PER_LONG; size -= BITS_PER_LONG;
offset = 0;
p++; p++;
} }
if (!size) return result;
return result; found:
return result - size + __reverse_ffs(tmp);
tmp = __reverse_ulong((unsigned char *)p);
found_first:
tmp &= (~0UL << (BITS_PER_LONG - size));
if (!tmp) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __reverse_ffs(tmp);
} }
static unsigned long __find_rev_next_zero_bit(const unsigned long *addr, static unsigned long __find_rev_next_zero_bit(const unsigned long *addr,
unsigned long size, unsigned long offset) unsigned long size, unsigned long offset)
{ {
const unsigned long *p = addr + BIT_WORD(offset); const unsigned long *p = addr + BIT_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG - 1); unsigned long result = size;
unsigned long tmp; unsigned long tmp;
if (offset >= size) if (offset >= size)
return size; return size;
size -= result; size -= (offset & ~(BITS_PER_LONG - 1));
offset %= BITS_PER_LONG; offset %= BITS_PER_LONG;
if (!offset)
goto aligned; while (1) {
if (*p == ~0UL)
tmp = __reverse_ulong((unsigned char *)p); goto pass;
tmp |= ~((~0UL << offset) >> offset);
if (size < BITS_PER_LONG)
goto found_first;
if (tmp != ~0UL)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
p++;
aligned:
while (size & ~(BITS_PER_LONG - 1)) {
tmp = __reverse_ulong((unsigned char *)p); tmp = __reverse_ulong((unsigned char *)p);
if (offset)
tmp |= ~0UL << (BITS_PER_LONG - offset);
if (size < BITS_PER_LONG)
tmp |= ~0UL >> size;
if (tmp != ~0UL) if (tmp != ~0UL)
goto found_middle; goto found;
result += BITS_PER_LONG; pass:
if (size <= BITS_PER_LONG)
break;
size -= BITS_PER_LONG; size -= BITS_PER_LONG;
offset = 0;
p++; p++;
} }
if (!size) return result;
return result; found:
return result - size + __reverse_ffz(tmp);
tmp = __reverse_ulong((unsigned char *)p);
found_first:
tmp |= ~(~0UL << (BITS_PER_LONG - size));
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found_middle:
return result + __reverse_ffz(tmp);
} }
void register_inmem_page(struct inode *inode, struct page *page) void register_inmem_page(struct inode *inode, struct page *page)
...@@ -233,7 +213,7 @@ int commit_inmem_pages(struct inode *inode, bool abort) ...@@ -233,7 +213,7 @@ int commit_inmem_pages(struct inode *inode, bool abort)
* inode becomes free by iget_locked in f2fs_iget. * inode becomes free by iget_locked in f2fs_iget.
*/ */
if (!abort) { if (!abort) {
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
} }
...@@ -257,6 +237,7 @@ int commit_inmem_pages(struct inode *inode, bool abort) ...@@ -257,6 +237,7 @@ int commit_inmem_pages(struct inode *inode, bool abort)
submit_bio = true; submit_bio = true;
} }
} else { } else {
ClearPageUptodate(cur->page);
trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP); trace_f2fs_commit_inmem_page(cur->page, INMEM_DROP);
} }
set_page_private(cur->page, 0); set_page_private(cur->page, 0);
...@@ -281,8 +262,10 @@ int commit_inmem_pages(struct inode *inode, bool abort) ...@@ -281,8 +262,10 @@ int commit_inmem_pages(struct inode *inode, bool abort)
* This function balances dirty node and dentry pages. * This function balances dirty node and dentry pages.
* In addition, it controls garbage collection. * In addition, it controls garbage collection.
*/ */
void f2fs_balance_fs(struct f2fs_sb_info *sbi) void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
{ {
if (!need)
return;
/* /*
* We should do GC or end up with checkpoint, if there are so many dirty * We should do GC or end up with checkpoint, if there are so many dirty
* dir/node pages without enough free segments. * dir/node pages without enough free segments.
...@@ -310,8 +293,12 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) ...@@ -310,8 +293,12 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
if (!available_free_memory(sbi, NAT_ENTRIES) || if (!available_free_memory(sbi, NAT_ENTRIES) ||
excess_prefree_segs(sbi) || excess_prefree_segs(sbi) ||
!available_free_memory(sbi, INO_ENTRIES) || !available_free_memory(sbi, INO_ENTRIES) ||
jiffies > sbi->cp_expires) (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) {
if (test_opt(sbi, DATA_FLUSH))
sync_dirty_inodes(sbi, FILE_INODE);
f2fs_sync_fs(sbi->sb, true); f2fs_sync_fs(sbi->sb, true);
stat_inc_bg_cp_count(sbi->stat_info);
}
} }
static int issue_flush_thread(void *data) static int issue_flush_thread(void *data)
...@@ -1134,6 +1121,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) ...@@ -1134,6 +1121,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
__u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1; __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1;
unsigned int start_segno, end_segno; unsigned int start_segno, end_segno;
struct cp_control cpc; struct cp_control cpc;
int err = 0;
if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
return -EINVAL; return -EINVAL;
...@@ -1164,12 +1152,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) ...@@ -1164,12 +1152,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
sbi->segs_per_sec) - 1, end_segno); sbi->segs_per_sec) - 1, end_segno);
mutex_lock(&sbi->gc_mutex); mutex_lock(&sbi->gc_mutex);
write_checkpoint(sbi, &cpc); err = write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex); mutex_unlock(&sbi->gc_mutex);
} }
out: out:
range->len = F2FS_BLK_TO_BYTES(cpc.trimmed); range->len = F2FS_BLK_TO_BYTES(cpc.trimmed);
return 0; return err;
} }
static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
...@@ -1749,13 +1737,13 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, ...@@ -1749,13 +1737,13 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type,
if (le32_to_cpu(nid_in_journal(sum, i)) == val) if (le32_to_cpu(nid_in_journal(sum, i)) == val)
return i; return i;
} }
if (alloc && nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) if (alloc && __has_cursum_space(sum, 1, NAT_JOURNAL))
return update_nats_in_cursum(sum, 1); return update_nats_in_cursum(sum, 1);
} else if (type == SIT_JOURNAL) { } else if (type == SIT_JOURNAL) {
for (i = 0; i < sits_in_cursum(sum); i++) for (i = 0; i < sits_in_cursum(sum); i++)
if (le32_to_cpu(segno_in_journal(sum, i)) == val) if (le32_to_cpu(segno_in_journal(sum, i)) == val)
return i; return i;
if (alloc && sits_in_cursum(sum) < SIT_JOURNAL_ENTRIES) if (alloc && __has_cursum_space(sum, 1, SIT_JOURNAL))
return update_sits_in_cursum(sum, 1); return update_sits_in_cursum(sum, 1);
} }
return -1; return -1;
......
...@@ -32,7 +32,8 @@ static unsigned long __count_free_nids(struct f2fs_sb_info *sbi) ...@@ -32,7 +32,8 @@ static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi) static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi)
{ {
return sbi->total_ext_tree + atomic_read(&sbi->total_ext_node); return atomic_read(&sbi->total_zombie_tree) +
atomic_read(&sbi->total_ext_node);
} }
unsigned long f2fs_shrink_count(struct shrinker *shrink, unsigned long f2fs_shrink_count(struct shrinker *shrink,
......
This diff is collapsed.
...@@ -571,7 +571,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name, ...@@ -571,7 +571,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
if (ipage) if (ipage)
return __f2fs_setxattr(inode, index, name, value, return __f2fs_setxattr(inode, index, name, value,
size, ipage, flags); size, ipage, flags);
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
/* protect xattr_ver */ /* protect xattr_ver */
...@@ -580,5 +580,6 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name, ...@@ -580,5 +580,6 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
up_write(&F2FS_I(inode)->i_sem); up_write(&F2FS_I(inode)->i_sem);
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
f2fs_update_time(sbi, REQ_TIME);
return err; return err;
} }
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#define MAX_ACTIVE_DATA_LOGS 8 #define MAX_ACTIVE_DATA_LOGS 8
#define VERSION_LEN 256 #define VERSION_LEN 256
#define MAX_VOLUME_NAME 512
/* /*
* For superblock * For superblock
...@@ -84,7 +85,7 @@ struct f2fs_super_block { ...@@ -84,7 +85,7 @@ struct f2fs_super_block {
__le32 node_ino; /* node inode number */ __le32 node_ino; /* node inode number */
__le32 meta_ino; /* meta inode number */ __le32 meta_ino; /* meta inode number */
__u8 uuid[16]; /* 128-bit uuid for volume */ __u8 uuid[16]; /* 128-bit uuid for volume */
__le16 volume_name[512]; /* volume name */ __le16 volume_name[MAX_VOLUME_NAME]; /* volume name */
__le32 extension_count; /* # of extensions below */ __le32 extension_count; /* # of extensions below */
__u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
__le32 cp_payload; __le32 cp_payload;
......
...@@ -1265,6 +1265,44 @@ TRACE_EVENT(f2fs_destroy_extent_tree, ...@@ -1265,6 +1265,44 @@ TRACE_EVENT(f2fs_destroy_extent_tree,
__entry->node_cnt) __entry->node_cnt)
); );
DECLARE_EVENT_CLASS(f2fs_sync_dirty_inodes,
TP_PROTO(struct super_block *sb, int type, int count),
TP_ARGS(sb, type, count),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(int, type)
__field(int, count)
),
TP_fast_assign(
__entry->dev = sb->s_dev;
__entry->type = type;
__entry->count = count;
),
TP_printk("dev = (%d,%d), %s, dirty count = %d",
show_dev(__entry),
show_file_type(__entry->type),
__entry->count)
);
DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_enter,
TP_PROTO(struct super_block *sb, int type, int count),
TP_ARGS(sb, type, count)
);
DEFINE_EVENT(f2fs_sync_dirty_inodes, f2fs_sync_dirty_inodes_exit,
TP_PROTO(struct super_block *sb, int type, int count),
TP_ARGS(sb, type, count)
);
#endif /* _TRACE_F2FS_H */ #endif /* _TRACE_F2FS_H */
/* This part must be outside protection */ /* This part must be outside protection */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment