Commit 09cb6464 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull f2fs updates from Jaegeuk Kim:
 "This patch series contains several performance tuning patches
  regarding to the IO submission flow, in addition to supporting new
  features such as a ZBC-base drive and multiple devices.

  It also includes some major bug fixes such as:
   - checkpoint version control
   - fdatasync-related roll-forward recovery routine
   - memory boundary or null-pointer access in corner cases
   - missing error cases

  It has various minor clean-up patches as well"

* tag 'for-f2fs-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (66 commits)
  f2fs: fix a missing size change in f2fs_setattr
  f2fs: fix to access nullified flush_cmd_control pointer
  f2fs: free meta pages if sanity check for ckpt is failed
  f2fs: detect wrong layout
  f2fs: call sync_fs when f2fs is idle
  Revert "f2fs: use percpu_counter for # of dirty pages in inode"
  f2fs: return AOP_WRITEPAGE_ACTIVATE for writepage
  f2fs: do not activate auto_recovery for fallocated i_size
  f2fs: fix to determine start_cp_addr by sbi->cur_cp_pack
  f2fs: fix 32-bit build
  f2fs: set ->owner for debugfs status file's file_operations
  f2fs: fix incorrect free inode count in ->statfs
  f2fs: drop duplicate header timer.h
  f2fs: fix wrong AUTO_RECOVER condition
  f2fs: do not recover i_size if it's valid
  f2fs: fix fdatasync
  f2fs: fix to account total free nid correctly
  f2fs: fix an infinite loop when flush nodes in cp
  f2fs: don't wait writeback for datas during checkpoint
  f2fs: fix wrong written_valid_blocks counting
  ...
parents 19d37ce2 c0ed4405
...@@ -384,7 +384,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage, ...@@ -384,7 +384,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
if (error) if (error)
return error; return error;
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, true);
if (default_acl) { if (default_acl) {
error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl, error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
......
...@@ -228,7 +228,7 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) ...@@ -228,7 +228,7 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
f2fs_put_page(page, 0); f2fs_put_page(page, 0);
if (readahead) if (readahead)
ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR, true); ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true);
} }
static int f2fs_write_meta_page(struct page *page, static int f2fs_write_meta_page(struct page *page,
...@@ -770,7 +770,12 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) ...@@ -770,7 +770,12 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
/* Sanity checking of checkpoint */ /* Sanity checking of checkpoint */
if (sanity_check_ckpt(sbi)) if (sanity_check_ckpt(sbi))
goto fail_no_cp; goto free_fail_no_cp;
if (cur_page == cp1)
sbi->cur_cp_pack = 1;
else
sbi->cur_cp_pack = 2;
if (cp_blks <= 1) if (cp_blks <= 1)
goto done; goto done;
...@@ -793,6 +798,9 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) ...@@ -793,6 +798,9 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
f2fs_put_page(cp2, 1); f2fs_put_page(cp2, 1);
return 0; return 0;
free_fail_no_cp:
f2fs_put_page(cp1, 1);
f2fs_put_page(cp2, 1);
fail_no_cp: fail_no_cp:
kfree(sbi->ckpt); kfree(sbi->ckpt);
return -EINVAL; return -EINVAL;
...@@ -921,7 +929,11 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi) ...@@ -921,7 +929,11 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
inode = igrab(&fi->vfs_inode); inode = igrab(&fi->vfs_inode);
spin_unlock(&sbi->inode_lock[DIRTY_META]); spin_unlock(&sbi->inode_lock[DIRTY_META]);
if (inode) { if (inode) {
update_inode_page(inode); sync_inode_metadata(inode, 0);
/* it's on eviction */
if (is_inode_flag_set(inode, FI_DIRTY_INODE))
update_inode_page(inode);
iput(inode); iput(inode);
} }
}; };
...@@ -987,7 +999,7 @@ static void unblock_operations(struct f2fs_sb_info *sbi) ...@@ -987,7 +999,7 @@ static void unblock_operations(struct f2fs_sb_info *sbi)
{ {
up_write(&sbi->node_write); up_write(&sbi->node_write);
build_free_nids(sbi); build_free_nids(sbi, false);
f2fs_unlock_all(sbi); f2fs_unlock_all(sbi);
} }
...@@ -998,7 +1010,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi) ...@@ -998,7 +1010,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
for (;;) { for (;;) {
prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
if (!atomic_read(&sbi->nr_wb_bios)) if (!get_pages(sbi, F2FS_WB_CP_DATA))
break; break;
io_schedule_timeout(5*HZ); io_schedule_timeout(5*HZ);
...@@ -1123,7 +1135,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1123,7 +1135,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
le32_to_cpu(ckpt->checksum_offset))) le32_to_cpu(ckpt->checksum_offset)))
= cpu_to_le32(crc32); = cpu_to_le32(crc32);
start_blk = __start_cp_addr(sbi); start_blk = __start_cp_next_addr(sbi);
/* need to wait for end_io results */ /* need to wait for end_io results */
wait_on_all_pages_writeback(sbi); wait_on_all_pages_writeback(sbi);
...@@ -1184,9 +1196,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1184,9 +1196,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
clear_prefree_segments(sbi, cpc);
clear_sbi_flag(sbi, SBI_IS_DIRTY); clear_sbi_flag(sbi, SBI_IS_DIRTY);
clear_sbi_flag(sbi, SBI_NEED_CP); clear_sbi_flag(sbi, SBI_NEED_CP);
__set_cp_next_pack(sbi);
/* /*
* redirty superblock if metadata like node page or inode cache is * redirty superblock if metadata like node page or inode cache is
...@@ -1261,8 +1273,12 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1261,8 +1273,12 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* unlock all the fs_lock[] in do_checkpoint() */ /* unlock all the fs_lock[] in do_checkpoint() */
err = do_checkpoint(sbi, cpc); err = do_checkpoint(sbi, cpc);
if (err) {
f2fs_wait_all_discard_bio(sbi); release_discard_addrs(sbi);
} else {
clear_prefree_segments(sbi, cpc);
f2fs_wait_all_discard_bio(sbi);
}
unblock_operations(sbi); unblock_operations(sbi);
stat_inc_cp_count(sbi->stat_info); stat_inc_cp_count(sbi->stat_info);
......
This diff is collapsed.
...@@ -50,7 +50,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -50,7 +50,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->ndirty_files = sbi->ndirty_inode[FILE_INODE]; si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
si->ndirty_all = sbi->ndirty_inode[DIRTY_META]; si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES); si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
si->wb_bios = atomic_read(&sbi->nr_wb_bios); si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA);
si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA);
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
si->rsvd_segs = reserved_segments(sbi); si->rsvd_segs = reserved_segments(sbi);
si->overp_segs = overprovision_segments(sbi); si->overp_segs = overprovision_segments(sbi);
...@@ -74,7 +75,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -74,7 +75,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->dirty_nats = NM_I(sbi)->dirty_nat_cnt; si->dirty_nats = NM_I(sbi)->dirty_nat_cnt;
si->sits = MAIN_SEGS(sbi); si->sits = MAIN_SEGS(sbi);
si->dirty_sits = SIT_I(sbi)->dirty_sentries; si->dirty_sits = SIT_I(sbi)->dirty_sentries;
si->fnids = NM_I(sbi)->fcnt; si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID_LIST];
si->alloc_nids = NM_I(sbi)->nid_cnt[ALLOC_NID_LIST];
si->bg_gc = sbi->bg_gc; si->bg_gc = sbi->bg_gc;
si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg) si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg) * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
...@@ -194,7 +196,9 @@ static void update_mem_info(struct f2fs_sb_info *sbi) ...@@ -194,7 +196,9 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
si->cache_mem += sizeof(struct flush_cmd_control); si->cache_mem += sizeof(struct flush_cmd_control);
/* free nids */ /* free nids */
si->cache_mem += NM_I(sbi)->fcnt * sizeof(struct free_nid); si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] +
NM_I(sbi)->nid_cnt[ALLOC_NID_LIST]) *
sizeof(struct free_nid);
si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry); si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry);
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);
...@@ -310,22 +314,22 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -310,22 +314,22 @@ static int stat_show(struct seq_file *s, void *v)
seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n", seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
si->ext_tree, si->zombie_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: %4lld, wb_bios: %4d\n", seq_printf(s, " - inmem: %4d, wb_cp_data: %4d, wb_data: %4d\n",
si->inmem_pages, si->wb_bios); si->inmem_pages, si->nr_wb_cp_data, si->nr_wb_data);
seq_printf(s, " - nodes: %4lld in %4d\n", seq_printf(s, " - nodes: %4d in %4d\n",
si->ndirty_node, si->node_pages); si->ndirty_node, si->node_pages);
seq_printf(s, " - dents: %4lld in dirs:%4d (%4d)\n", seq_printf(s, " - dents: %4d in dirs:%4d (%4d)\n",
si->ndirty_dent, si->ndirty_dirs, si->ndirty_all); si->ndirty_dent, si->ndirty_dirs, si->ndirty_all);
seq_printf(s, " - datas: %4lld in files:%4d\n", seq_printf(s, " - datas: %4d in files:%4d\n",
si->ndirty_data, si->ndirty_files); si->ndirty_data, si->ndirty_files);
seq_printf(s, " - meta: %4lld 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, " - imeta: %4lld\n", seq_printf(s, " - imeta: %4d\n",
si->ndirty_imeta); si->ndirty_imeta);
seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n",
si->dirty_nats, si->nats, si->dirty_sits, si->sits); si->dirty_nats, si->nats, si->dirty_sits, si->sits);
seq_printf(s, " - free_nids: %9d\n", seq_printf(s, " - free_nids: %9d, alloc_nids: %9d\n",
si->fnids); si->free_nids, si->alloc_nids);
seq_puts(s, "\nDistribution of User Blocks:"); seq_puts(s, "\nDistribution of User Blocks:");
seq_puts(s, " [ valid | invalid | free ]\n"); seq_puts(s, " [ valid | invalid | free ]\n");
seq_puts(s, " ["); seq_puts(s, " [");
...@@ -373,6 +377,7 @@ static int stat_open(struct inode *inode, struct file *file) ...@@ -373,6 +377,7 @@ static int stat_open(struct inode *inode, struct file *file)
} }
static const struct file_operations stat_fops = { static const struct file_operations stat_fops = {
.owner = THIS_MODULE,
.open = stat_open, .open = stat_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
......
...@@ -136,7 +136,7 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname, ...@@ -136,7 +136,7 @@ struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
/* show encrypted name */ /* show encrypted name */
if (fname->hash) { if (fname->hash) {
if (de->hash_code == fname->hash) if (de->hash_code == cpu_to_le32(fname->hash))
goto found; goto found;
} else if (de_name.len == name->len && } else if (de_name.len == name->len &&
de->hash_code == namehash && de->hash_code == namehash &&
...@@ -313,7 +313,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, ...@@ -313,7 +313,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
set_page_dirty(page); set_page_dirty(page);
dir->i_mtime = dir->i_ctime = current_time(dir); dir->i_mtime = dir->i_ctime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir); f2fs_mark_inode_dirty_sync(dir, false);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
} }
...@@ -466,7 +466,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode, ...@@ -466,7 +466,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode,
clear_inode_flag(inode, FI_NEW_INODE); clear_inode_flag(inode, FI_NEW_INODE);
} }
dir->i_mtime = dir->i_ctime = current_time(dir); dir->i_mtime = dir->i_ctime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir); f2fs_mark_inode_dirty_sync(dir, false);
if (F2FS_I(dir)->i_current_depth != current_depth) if (F2FS_I(dir)->i_current_depth != current_depth)
f2fs_i_depth_write(dir, current_depth); f2fs_i_depth_write(dir, current_depth);
...@@ -731,7 +731,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, ...@@ -731,7 +731,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
set_page_dirty(page); set_page_dirty(page);
dir->i_ctime = dir->i_mtime = current_time(dir); dir->i_ctime = dir->i_mtime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir); f2fs_mark_inode_dirty_sync(dir, false);
if (inode) if (inode)
f2fs_drop_nlink(dir, inode); f2fs_drop_nlink(dir, inode);
...@@ -742,6 +742,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, ...@@ -742,6 +742,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
ClearPagePrivate(page); ClearPagePrivate(page);
ClearPageUptodate(page); ClearPageUptodate(page);
inode_dec_dirty_pages(dir); inode_dec_dirty_pages(dir);
remove_dirty_inode(dir);
} }
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
} }
...@@ -784,7 +785,7 @@ bool f2fs_empty_dir(struct inode *dir) ...@@ -784,7 +785,7 @@ bool f2fs_empty_dir(struct inode *dir)
return true; return true;
} }
bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
unsigned int start_pos, struct fscrypt_str *fstr) unsigned int start_pos, struct fscrypt_str *fstr)
{ {
unsigned char d_type = DT_UNKNOWN; unsigned char d_type = DT_UNKNOWN;
...@@ -819,7 +820,7 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, ...@@ -819,7 +820,7 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
(u32)de->hash_code, 0, (u32)de->hash_code, 0,
&de_name, fstr); &de_name, fstr);
if (err) if (err)
return true; return err;
de_name = *fstr; de_name = *fstr;
fstr->len = save_len; fstr->len = save_len;
...@@ -827,12 +828,12 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, ...@@ -827,12 +828,12 @@ bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
if (!dir_emit(ctx, de_name.name, de_name.len, if (!dir_emit(ctx, de_name.name, de_name.len,
le32_to_cpu(de->ino), d_type)) le32_to_cpu(de->ino), d_type))
return true; return 1;
bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
ctx->pos = start_pos + bit_pos; ctx->pos = start_pos + bit_pos;
} }
return false; return 0;
} }
static int f2fs_readdir(struct file *file, struct dir_context *ctx) static int f2fs_readdir(struct file *file, struct dir_context *ctx)
...@@ -871,17 +872,21 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -871,17 +872,21 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
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)) {
err = PTR_ERR(dentry_page); err = PTR_ERR(dentry_page);
if (err == -ENOENT) if (err == -ENOENT) {
err = 0;
continue; continue;
else } else {
goto out; 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)) { err = f2fs_fill_dentries(ctx, &d,
n * NR_DENTRY_IN_BLOCK, &fstr);
if (err) {
kunmap(dentry_page); kunmap(dentry_page);
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
break; break;
...@@ -891,10 +896,9 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -891,10 +896,9 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
kunmap(dentry_page); kunmap(dentry_page);
f2fs_put_page(dentry_page, 1); f2fs_put_page(dentry_page, 1);
} }
err = 0;
out: out:
fscrypt_fname_free_buffer(&fstr); fscrypt_fname_free_buffer(&fstr);
return err; return err < 0 ? err : 0;
} }
static int f2fs_dir_open(struct inode *inode, struct file *filp) static int f2fs_dir_open(struct inode *inode, struct file *filp)
......
...@@ -172,7 +172,7 @@ static void __drop_largest_extent(struct inode *inode, ...@@ -172,7 +172,7 @@ static void __drop_largest_extent(struct inode *inode,
if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) { if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) {
largest->len = 0; largest->len = 0;
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, true);
} }
} }
......
This diff is collapsed.
...@@ -94,8 +94,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, ...@@ -94,8 +94,6 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr); f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr);
/* if gced page is attached, don't write to cold segment */
clear_cold_data(page);
out: out:
sb_end_pagefault(inode->i_sb); sb_end_pagefault(inode->i_sb);
f2fs_update_time(sbi, REQ_TIME); f2fs_update_time(sbi, REQ_TIME);
...@@ -210,7 +208,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, ...@@ -210,7 +208,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
} }
/* if the inode is dirty, let's recover all the time */ /* if the inode is dirty, let's recover all the time */
if (!datasync && !f2fs_skip_inode_update(inode)) { if (!f2fs_skip_inode_update(inode, datasync)) {
f2fs_write_inode(inode, NULL); f2fs_write_inode(inode, NULL);
goto go_write; goto go_write;
} }
...@@ -264,7 +262,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, ...@@ -264,7 +262,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
} }
if (need_inode_block_update(sbi, ino)) { if (need_inode_block_update(sbi, ino)) {
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, true);
f2fs_write_inode(inode, NULL); f2fs_write_inode(inode, NULL);
goto sync_nodes; goto sync_nodes;
} }
...@@ -632,7 +630,7 @@ int f2fs_truncate(struct inode *inode) ...@@ -632,7 +630,7 @@ int f2fs_truncate(struct inode *inode)
return err; return err;
inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_mtime = inode->i_ctime = current_time(inode);
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, false);
return 0; return 0;
} }
...@@ -679,6 +677,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -679,6 +677,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
{ {
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int err; int err;
bool size_changed = false;
err = setattr_prepare(dentry, attr); err = setattr_prepare(dentry, attr);
if (err) if (err)
...@@ -694,7 +693,6 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -694,7 +693,6 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
err = f2fs_truncate(inode); err = f2fs_truncate(inode);
if (err) if (err)
return err; return err;
f2fs_balance_fs(F2FS_I_SB(inode), true);
} else { } else {
/* /*
* do not trim all blocks after i_size if target size is * do not trim all blocks after i_size if target size is
...@@ -710,6 +708,8 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -710,6 +708,8 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
} }
inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_mtime = inode->i_ctime = current_time(inode);
} }
size_changed = true;
} }
__setattr_copy(inode, attr); __setattr_copy(inode, attr);
...@@ -722,7 +722,12 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -722,7 +722,12 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
} }
} }
f2fs_mark_inode_dirty_sync(inode); /* file size may changed here */
f2fs_mark_inode_dirty_sync(inode, size_changed);
/* inode change will produce dirty node pages flushed by checkpoint */
f2fs_balance_fs(F2FS_I_SB(inode), true);
return err; return err;
} }
...@@ -967,7 +972,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode, ...@@ -967,7 +972,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
new_size = (dst + i) << PAGE_SHIFT; new_size = (dst + i) << PAGE_SHIFT;
if (dst_inode->i_size < new_size) if (dst_inode->i_size < new_size)
f2fs_i_size_write(dst_inode, new_size); f2fs_i_size_write(dst_inode, new_size);
} while ((do_replace[i] || blkaddr[i] == NULL_ADDR) && --ilen); } while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR));
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
} else { } else {
...@@ -1218,6 +1223,9 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, ...@@ -1218,6 +1223,9 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
ret = f2fs_do_zero_range(&dn, index, end); ret = f2fs_do_zero_range(&dn, index, end);
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
f2fs_balance_fs(sbi, dn.node_changed);
if (ret) if (ret)
goto out; goto out;
...@@ -1313,15 +1321,15 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -1313,15 +1321,15 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
pgoff_t pg_end; pgoff_t pg_end;
loff_t new_size = i_size_read(inode); loff_t new_size = i_size_read(inode);
loff_t off_end; loff_t off_end;
int ret; int err;
ret = inode_newsize_ok(inode, (len + offset)); err = inode_newsize_ok(inode, (len + offset));
if (ret) if (err)
return ret; return err;
ret = f2fs_convert_inline_inode(inode); err = f2fs_convert_inline_inode(inode);
if (ret) if (err)
return ret; return err;
f2fs_balance_fs(sbi, true); f2fs_balance_fs(sbi, true);
...@@ -1333,12 +1341,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -1333,12 +1341,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
if (off_end) if (off_end)
map.m_len++; map.m_len++;
ret = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO); err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
if (ret) { if (err) {
pgoff_t last_off; pgoff_t last_off;
if (!map.m_len) if (!map.m_len)
return ret; return err;
last_off = map.m_lblk + map.m_len - 1; last_off = map.m_lblk + map.m_len - 1;
...@@ -1352,7 +1360,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -1352,7 +1360,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size)
f2fs_i_size_write(inode, new_size); f2fs_i_size_write(inode, new_size);
return ret; return err;
} }
static long f2fs_fallocate(struct file *file, int mode, static long f2fs_fallocate(struct file *file, int mode,
...@@ -1393,7 +1401,9 @@ static long f2fs_fallocate(struct file *file, int mode, ...@@ -1393,7 +1401,9 @@ static long f2fs_fallocate(struct file *file, int mode,
if (!ret) { if (!ret) {
inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_mtime = inode->i_ctime = current_time(inode);
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, false);
if (mode & FALLOC_FL_KEEP_SIZE)
file_set_keep_isize(inode);
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
} }
...@@ -1526,7 +1536,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) ...@@ -1526,7 +1536,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
goto out; goto out;
f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING, f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
"Unexpected flush for atomic writes: ino=%lu, npages=%lld", "Unexpected flush for atomic writes: ino=%lu, npages=%u",
inode->i_ino, get_dirty_pages(inode)); inode->i_ino, get_dirty_pages(inode));
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
if (ret) if (ret)
...@@ -1842,7 +1852,7 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg) ...@@ -1842,7 +1852,7 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
mutex_lock(&sbi->gc_mutex); mutex_lock(&sbi->gc_mutex);
} }
ret = f2fs_gc(sbi, sync); ret = f2fs_gc(sbi, sync, true);
out: out:
mnt_drop_write_file(filp); mnt_drop_write_file(filp);
return ret; return ret;
...@@ -2256,12 +2266,15 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2256,12 +2266,15 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
inode_lock(inode); inode_lock(inode);
ret = generic_write_checks(iocb, from); ret = generic_write_checks(iocb, from);
if (ret > 0) { if (ret > 0) {
ret = f2fs_preallocate_blocks(iocb, from); int err = f2fs_preallocate_blocks(iocb, from);
if (!ret) {
blk_start_plug(&plug); if (err) {
ret = __generic_file_write_iter(iocb, from); inode_unlock(inode);
blk_finish_plug(&plug); return err;
} }
blk_start_plug(&plug);
ret = __generic_file_write_iter(iocb, from);
blk_finish_plug(&plug);
} }
inode_unlock(inode); inode_unlock(inode);
......
...@@ -82,7 +82,7 @@ static int gc_thread_func(void *data) ...@@ -82,7 +82,7 @@ static int gc_thread_func(void *data)
stat_inc_bggc_count(sbi); stat_inc_bggc_count(sbi);
/* if return value is not zero, no victim was selected */ /* if return value is not zero, no victim was selected */
if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC))) if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true))
wait_ms = gc_th->no_gc_sleep_time; wait_ms = gc_th->no_gc_sleep_time;
trace_f2fs_background_gc(sbi->sb, wait_ms, trace_f2fs_background_gc(sbi->sb, wait_ms,
...@@ -544,7 +544,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ...@@ -544,7 +544,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
return true; return true;
} }
static void move_encrypted_block(struct inode *inode, block_t bidx) static void move_encrypted_block(struct inode *inode, block_t bidx,
unsigned int segno, int off)
{ {
struct f2fs_io_info fio = { struct f2fs_io_info fio = {
.sbi = F2FS_I_SB(inode), .sbi = F2FS_I_SB(inode),
...@@ -565,6 +566,9 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) ...@@ -565,6 +566,9 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
if (!page) if (!page)
return; return;
if (!check_valid_map(F2FS_I_SB(inode), segno, off))
goto out;
set_new_dnode(&dn, inode, NULL, NULL, 0); set_new_dnode(&dn, inode, NULL, NULL, 0);
err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE); err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE);
if (err) if (err)
...@@ -645,7 +649,8 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) ...@@ -645,7 +649,8 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
} }
static void move_data_page(struct inode *inode, block_t bidx, int gc_type) static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
unsigned int segno, int off)
{ {
struct page *page; struct page *page;
...@@ -653,6 +658,9 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type) ...@@ -653,6 +658,9 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
if (IS_ERR(page)) if (IS_ERR(page))
return; return;
if (!check_valid_map(F2FS_I_SB(inode), segno, off))
goto out;
if (gc_type == BG_GC) { if (gc_type == BG_GC) {
if (PageWriteback(page)) if (PageWriteback(page))
goto out; goto out;
...@@ -673,8 +681,10 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type) ...@@ -673,8 +681,10 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
retry: retry:
set_page_dirty(page); set_page_dirty(page);
f2fs_wait_on_page_writeback(page, DATA, true); f2fs_wait_on_page_writeback(page, DATA, true);
if (clear_page_dirty_for_io(page)) if (clear_page_dirty_for_io(page)) {
inode_dec_dirty_pages(inode); inode_dec_dirty_pages(inode);
remove_dirty_inode(inode);
}
set_cold_data(page); set_cold_data(page);
...@@ -683,8 +693,6 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type) ...@@ -683,8 +693,6 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type)
congestion_wait(BLK_RW_ASYNC, HZ/50); congestion_wait(BLK_RW_ASYNC, HZ/50);
goto retry; goto retry;
} }
clear_cold_data(page);
} }
out: out:
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
...@@ -794,9 +802,9 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ...@@ -794,9 +802,9 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
start_bidx = start_bidx_of_node(nofs, inode) start_bidx = start_bidx_of_node(nofs, inode)
+ ofs_in_node; + ofs_in_node;
if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
move_encrypted_block(inode, start_bidx); move_encrypted_block(inode, start_bidx, segno, off);
else else
move_data_page(inode, start_bidx, gc_type); move_data_page(inode, start_bidx, gc_type, segno, off);
if (locked) { if (locked) {
up_write(&fi->dio_rwsem[WRITE]); up_write(&fi->dio_rwsem[WRITE]);
...@@ -899,7 +907,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -899,7 +907,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
return sec_freed; return sec_freed;
} }
int f2fs_gc(struct f2fs_sb_info *sbi, bool sync) int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background)
{ {
unsigned int segno; unsigned int segno;
int gc_type = sync ? FG_GC : BG_GC; int gc_type = sync ? FG_GC : BG_GC;
...@@ -940,6 +948,9 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync) ...@@ -940,6 +948,9 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync)
if (ret) if (ret)
goto stop; goto stop;
} }
} else if (gc_type == BG_GC && !background) {
/* f2fs_balance_fs doesn't need to do BG_GC in critical path. */
goto stop;
} }
if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type)) if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type))
......
...@@ -137,8 +137,10 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) ...@@ -137,8 +137,10 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
fio.old_blkaddr = dn->data_blkaddr; fio.old_blkaddr = dn->data_blkaddr;
write_data_page(dn, &fio); write_data_page(dn, &fio);
f2fs_wait_on_page_writeback(page, DATA, true); f2fs_wait_on_page_writeback(page, DATA, true);
if (dirty) if (dirty) {
inode_dec_dirty_pages(dn->inode); inode_dec_dirty_pages(dn->inode);
remove_dirty_inode(dn->inode);
}
/* this converted inline_data should be recovered. */ /* this converted inline_data should be recovered. */
set_inode_flag(dn->inode, FI_APPEND_WRITE); set_inode_flag(dn->inode, FI_APPEND_WRITE);
...@@ -419,7 +421,7 @@ static int f2fs_add_inline_entries(struct inode *dir, ...@@ -419,7 +421,7 @@ static int f2fs_add_inline_entries(struct inode *dir,
} }
new_name.name = d.filename[bit_pos]; new_name.name = d.filename[bit_pos];
new_name.len = de->name_len; new_name.len = le16_to_cpu(de->name_len);
ino = le32_to_cpu(de->ino); ino = le32_to_cpu(de->ino);
fake_mode = get_de_type(de) << S_SHIFT; fake_mode = get_de_type(de) << S_SHIFT;
...@@ -573,7 +575,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page, ...@@ -573,7 +575,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
dir->i_ctime = dir->i_mtime = current_time(dir); dir->i_ctime = dir->i_mtime = current_time(dir);
f2fs_mark_inode_dirty_sync(dir); f2fs_mark_inode_dirty_sync(dir, false);
if (inode) if (inode)
f2fs_drop_nlink(dir, inode); f2fs_drop_nlink(dir, inode);
...@@ -610,6 +612,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx, ...@@ -610,6 +612,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
struct f2fs_inline_dentry *inline_dentry = NULL; struct f2fs_inline_dentry *inline_dentry = NULL;
struct page *ipage = NULL; struct page *ipage = NULL;
struct f2fs_dentry_ptr d; struct f2fs_dentry_ptr d;
int err;
if (ctx->pos == NR_INLINE_DENTRY) if (ctx->pos == NR_INLINE_DENTRY)
return 0; return 0;
...@@ -622,11 +625,12 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx, ...@@ -622,11 +625,12 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
make_dentry_ptr(inode, &d, (void *)inline_dentry, 2); make_dentry_ptr(inode, &d, (void *)inline_dentry, 2);
if (!f2fs_fill_dentries(ctx, &d, 0, fstr)) err = f2fs_fill_dentries(ctx, &d, 0, fstr);
if (!err)
ctx->pos = NR_INLINE_DENTRY; ctx->pos = NR_INLINE_DENTRY;
f2fs_put_page(ipage, 1); f2fs_put_page(ipage, 1);
return 0; return err < 0 ? err : 0;
} }
int f2fs_inline_data_fiemap(struct inode *inode, int f2fs_inline_data_fiemap(struct inode *inode,
......
...@@ -19,10 +19,11 @@ ...@@ -19,10 +19,11 @@
#include <trace/events/f2fs.h> #include <trace/events/f2fs.h>
void f2fs_mark_inode_dirty_sync(struct inode *inode) void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync)
{ {
if (f2fs_inode_dirtied(inode)) if (f2fs_inode_dirtied(inode, sync))
return; return;
mark_inode_dirty_sync(inode); mark_inode_dirty_sync(inode);
} }
...@@ -43,7 +44,7 @@ void f2fs_set_inode_flags(struct inode *inode) ...@@ -43,7 +44,7 @@ void f2fs_set_inode_flags(struct inode *inode)
new_fl |= S_DIRSYNC; new_fl |= S_DIRSYNC;
inode_set_flags(inode, new_fl, inode_set_flags(inode, new_fl,
S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, false);
} }
static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
...@@ -252,6 +253,7 @@ struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino) ...@@ -252,6 +253,7 @@ struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino)
int 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;
struct extent_tree *et = F2FS_I(inode)->extent_tree;
f2fs_inode_synced(inode); f2fs_inode_synced(inode);
...@@ -267,11 +269,13 @@ int update_inode(struct inode *inode, struct page *node_page) ...@@ -267,11 +269,13 @@ int update_inode(struct inode *inode, struct page *node_page)
ri->i_size = cpu_to_le64(i_size_read(inode)); ri->i_size = cpu_to_le64(i_size_read(inode));
ri->i_blocks = cpu_to_le64(inode->i_blocks); ri->i_blocks = cpu_to_le64(inode->i_blocks);
if (F2FS_I(inode)->extent_tree) if (et) {
set_raw_extent(&F2FS_I(inode)->extent_tree->largest, read_lock(&et->lock);
&ri->i_ext); set_raw_extent(&et->largest, &ri->i_ext);
else read_unlock(&et->lock);
} else {
memset(&ri->i_ext, 0, sizeof(ri->i_ext)); memset(&ri->i_ext, 0, sizeof(ri->i_ext));
}
set_raw_inline(inode, ri); set_raw_inline(inode, ri);
ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec); ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
...@@ -335,7 +339,7 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -335,7 +339,7 @@ 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.
*/ */
if (update_inode_page(inode)) if (update_inode_page(inode) && wbc && wbc->nr_to_write)
f2fs_balance_fs(sbi, true); f2fs_balance_fs(sbi, true);
return 0; return 0;
} }
...@@ -373,6 +377,9 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -373,6 +377,9 @@ void f2fs_evict_inode(struct inode *inode)
goto no_delete; goto no_delete;
#endif #endif
remove_ino_entry(sbi, inode->i_ino, APPEND_INO);
remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
sb_start_intwrite(inode->i_sb); sb_start_intwrite(inode->i_sb);
set_inode_flag(inode, FI_NO_ALLOC); set_inode_flag(inode, FI_NO_ALLOC);
i_size_write(inode, 0); i_size_write(inode, 0);
...@@ -384,6 +391,8 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -384,6 +391,8 @@ void f2fs_evict_inode(struct inode *inode)
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = remove_inode_page(inode); err = remove_inode_page(inode);
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
if (err == -ENOENT)
err = 0;
} }
/* give more chances, if ENOMEM case */ /* give more chances, if ENOMEM case */
...@@ -403,10 +412,12 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -403,10 +412,12 @@ void f2fs_evict_inode(struct inode *inode)
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino); invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
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(inode, FI_APPEND_WRITE)) if (inode->i_nlink) {
add_ino_entry(sbi, inode->i_ino, APPEND_INO); if (is_inode_flag_set(inode, FI_APPEND_WRITE))
if (is_inode_flag_set(inode, FI_UPDATE_WRITE)) add_ino_entry(sbi, inode->i_ino, APPEND_INO);
add_ino_entry(sbi, inode->i_ino, UPDATE_INO); if (is_inode_flag_set(inode, FI_UPDATE_WRITE))
add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
}
if (is_inode_flag_set(inode, FI_FREE_NID)) { if (is_inode_flag_set(inode, FI_FREE_NID)) {
alloc_nid_failed(sbi, inode->i_ino); alloc_nid_failed(sbi, inode->i_ino);
clear_inode_flag(inode, FI_FREE_NID); clear_inode_flag(inode, FI_FREE_NID);
...@@ -424,6 +435,18 @@ void handle_failed_inode(struct inode *inode) ...@@ -424,6 +435,18 @@ void handle_failed_inode(struct inode *inode)
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct node_info ni; struct node_info ni;
/*
* clear nlink of inode in order to release resource of inode
* immediately.
*/
clear_nlink(inode);
/*
* we must call this to avoid inode being remained as dirty, resulting
* in a panic when flushing dirty inodes in gdirty_list.
*/
update_inode_page(inode);
/* don't make bad inode, since it becomes a regular file. */ /* don't make bad inode, since it becomes a regular file. */
unlock_new_inode(inode); unlock_new_inode(inode);
......
...@@ -778,7 +778,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -778,7 +778,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
up_write(&F2FS_I(old_inode)->i_sem); up_write(&F2FS_I(old_inode)->i_sem);
old_inode->i_ctime = current_time(old_inode); old_inode->i_ctime = current_time(old_inode);
f2fs_mark_inode_dirty_sync(old_inode); f2fs_mark_inode_dirty_sync(old_inode, false);
f2fs_delete_entry(old_entry, old_page, old_dir, NULL); f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
...@@ -938,7 +938,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -938,7 +938,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
f2fs_i_links_write(old_dir, old_nlink > 0); f2fs_i_links_write(old_dir, old_nlink > 0);
up_write(&F2FS_I(old_dir)->i_sem); up_write(&F2FS_I(old_dir)->i_sem);
} }
f2fs_mark_inode_dirty_sync(old_dir); f2fs_mark_inode_dirty_sync(old_dir, false);
/* update directory entry info of new dir inode */ /* update directory entry info of new dir inode */
f2fs_set_link(new_dir, new_entry, new_page, old_inode); f2fs_set_link(new_dir, new_entry, new_page, old_inode);
...@@ -953,7 +953,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -953,7 +953,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
f2fs_i_links_write(new_dir, new_nlink > 0); f2fs_i_links_write(new_dir, new_nlink > 0);
up_write(&F2FS_I(new_dir)->i_sem); up_write(&F2FS_I(new_dir)->i_sem);
} }
f2fs_mark_inode_dirty_sync(new_dir); f2fs_mark_inode_dirty_sync(new_dir, false);
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
......
This diff is collapsed.
...@@ -169,14 +169,15 @@ static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid) ...@@ -169,14 +169,15 @@ static inline void next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid)
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
struct free_nid *fnid; struct free_nid *fnid;
spin_lock(&nm_i->free_nid_list_lock); spin_lock(&nm_i->nid_list_lock);
if (nm_i->fcnt <= 0) { if (nm_i->nid_cnt[FREE_NID_LIST] <= 0) {
spin_unlock(&nm_i->free_nid_list_lock); spin_unlock(&nm_i->nid_list_lock);
return; return;
} }
fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list); fnid = list_entry(nm_i->nid_list[FREE_NID_LIST].next,
struct free_nid, list);
*nid = fnid->nid; *nid = fnid->nid;
spin_unlock(&nm_i->free_nid_list_lock); spin_unlock(&nm_i->nid_list_lock);
} }
/* /*
...@@ -313,7 +314,7 @@ static inline bool is_recoverable_dnode(struct page *page) ...@@ -313,7 +314,7 @@ static inline bool is_recoverable_dnode(struct page *page)
((unsigned char *)ckpt + crc_offset))); ((unsigned char *)ckpt + crc_offset)));
cp_ver |= (crc << 32); cp_ver |= (crc << 32);
} }
return cpu_to_le64(cp_ver) == cpver_of_node(page); return cp_ver == cpver_of_node(page);
} }
/* /*
......
...@@ -180,13 +180,15 @@ static void recover_inode(struct inode *inode, struct page *page) ...@@ -180,13 +180,15 @@ static void recover_inode(struct inode *inode, struct page *page)
inode->i_mode = le16_to_cpu(raw->i_mode); inode->i_mode = le16_to_cpu(raw->i_mode);
f2fs_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_atime.tv_sec = le64_to_cpu(raw->i_atime);
inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime); inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime);
inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime); inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime);
inode->i_atime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); inode->i_atime.tv_nsec = le32_to_cpu(raw->i_atime_nsec);
inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec); inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec);
inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec);
F2FS_I(inode)->i_advise = raw->i_advise;
if (file_enc_name(inode)) if (file_enc_name(inode))
name = "<encrypted>"; name = "<encrypted>";
else else
...@@ -196,32 +198,6 @@ static void recover_inode(struct inode *inode, struct page *page) ...@@ -196,32 +198,6 @@ 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)
{ {
struct curseg_info *curseg; struct curseg_info *curseg;
...@@ -248,10 +224,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -248,10 +224,7 @@ 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)
...@@ -454,7 +427,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -454,7 +427,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
continue; continue;
} }
if ((start + 1) << PAGE_SHIFT > i_size_read(inode)) if (!file_keep_isize(inode) &&
(i_size_read(inode) <= (start << PAGE_SHIFT)))
f2fs_i_size_write(inode, (start + 1) << PAGE_SHIFT); f2fs_i_size_write(inode, (start + 1) << PAGE_SHIFT);
/* /*
...@@ -507,8 +481,10 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -507,8 +481,10 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
f2fs_put_dnode(&dn); f2fs_put_dnode(&dn);
out: out:
f2fs_msg(sbi->sb, KERN_NOTICE, f2fs_msg(sbi->sb, KERN_NOTICE,
"recover_data: ino = %lx, recovered = %d blocks, err = %d", "recover_data: ino = %lx (i_size: %s) recovered = %d, err = %d",
inode->i_ino, recovered, err); inode->i_ino,
file_keep_isize(inode) ? "keep" : "recover",
recovered, err);
return err; return err;
} }
......
This diff is collapsed.
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#define DEF_RECLAIM_PREFREE_SEGMENTS 5 /* 5% over total segments */ #define DEF_RECLAIM_PREFREE_SEGMENTS 5 /* 5% over total segments */
#define DEF_MAX_RECLAIM_PREFREE_SEGMENTS 4096 /* 8GB in maximum */ #define DEF_MAX_RECLAIM_PREFREE_SEGMENTS 4096 /* 8GB in maximum */
#define F2FS_MIN_SEGMENTS 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */
/* L: Logical segment # in volume, R: Relative segment # in main area */ /* L: Logical segment # in volume, R: Relative segment # in main area */
#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno) #define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno)
#define GET_R2L_SEGNO(free_i, segno) (segno + free_i->start_segno) #define GET_R2L_SEGNO(free_i, segno) (segno + free_i->start_segno)
...@@ -102,8 +104,6 @@ ...@@ -102,8 +104,6 @@
(((sector_t)blk_addr) << F2FS_LOG_SECTORS_PER_BLOCK) (((sector_t)blk_addr) << F2FS_LOG_SECTORS_PER_BLOCK)
#define SECTOR_TO_BLOCK(sectors) \ #define SECTOR_TO_BLOCK(sectors) \
(sectors >> F2FS_LOG_SECTORS_PER_BLOCK) (sectors >> F2FS_LOG_SECTORS_PER_BLOCK)
#define MAX_BIO_BLOCKS(sbi) \
((int)min((int)max_hw_blocks(sbi), BIO_MAX_PAGES))
/* /*
* indicate a block allocation direction: RIGHT and LEFT. * indicate a block allocation direction: RIGHT and LEFT.
...@@ -471,11 +471,12 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi) ...@@ -471,11 +471,12 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi)
{ {
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
if (test_opt(sbi, LFS)) if (test_opt(sbi, LFS))
return false; return false;
return free_sections(sbi) <= (node_secs + 2 * dent_secs + return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs +
reserved_sections(sbi) + 1); reserved_sections(sbi) + 1);
} }
...@@ -484,14 +485,14 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, ...@@ -484,14 +485,14 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,
{ {
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
node_secs += get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
return false; return false;
return (free_sections(sbi) + freed) <= return (free_sections(sbi) + freed) <=
(node_secs + 2 * dent_secs + reserved_sections(sbi) + needed); (node_secs + 2 * dent_secs + imeta_secs +
reserved_sections(sbi) + needed);
} }
static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi) static inline bool excess_prefree_segs(struct f2fs_sb_info *sbi)
...@@ -695,13 +696,6 @@ static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno) ...@@ -695,13 +696,6 @@ static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno)
return false; return false;
} }
static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi)
{
struct block_device *bdev = sbi->sb->s_bdev;
struct request_queue *q = bdev_get_queue(bdev);
return SECTOR_TO_BLOCK(queue_max_sectors(q));
}
/* /*
* It is very important to gather dirty pages and write at once, so that we can * It is very important to gather dirty pages and write at once, so that we can
* submit a big bio without interfering other data writes. * submit a big bio without interfering other data writes.
...@@ -719,7 +713,7 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type) ...@@ -719,7 +713,7 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
else if (type == NODE) else if (type == NODE)
return 8 * sbi->blocks_per_seg; return 8 * sbi->blocks_per_seg;
else if (type == META) else if (type == META)
return 8 * MAX_BIO_BLOCKS(sbi); return 8 * BIO_MAX_PAGES;
else else
return 0; return 0;
} }
...@@ -736,11 +730,9 @@ static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type, ...@@ -736,11 +730,9 @@ static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type,
return 0; return 0;
nr_to_write = wbc->nr_to_write; nr_to_write = wbc->nr_to_write;
desired = BIO_MAX_PAGES;
if (type == NODE) if (type == NODE)
desired = 2 * max_hw_blocks(sbi); desired <<= 1;
else
desired = MAX_BIO_BLOCKS(sbi);
wbc->nr_to_write = desired; wbc->nr_to_write = desired;
return desired - nr_to_write; return desired - nr_to_write;
......
...@@ -21,14 +21,16 @@ static unsigned int shrinker_run_no; ...@@ -21,14 +21,16 @@ static unsigned int shrinker_run_no;
static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi) static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi)
{ {
return NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt; long count = NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt;
return count > 0 ? count : 0;
} }
static unsigned long __count_free_nids(struct f2fs_sb_info *sbi) static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
{ {
if (NM_I(sbi)->fcnt > MAX_FREE_NIDS) long count = NM_I(sbi)->nid_cnt[FREE_NID_LIST] - MAX_FREE_NIDS;
return NM_I(sbi)->fcnt - MAX_FREE_NIDS;
return 0; return count > 0 ? count : 0;
} }
static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi) static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi)
......
This diff is collapsed.
...@@ -106,7 +106,7 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler, ...@@ -106,7 +106,7 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
return -EINVAL; return -EINVAL;
F2FS_I(inode)->i_advise |= *(char *)value; F2FS_I(inode)->i_advise |= *(char *)value;
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, true);
return 0; return 0;
} }
...@@ -554,7 +554,7 @@ static int __f2fs_setxattr(struct inode *inode, int index, ...@@ -554,7 +554,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
if (index == F2FS_XATTR_INDEX_ENCRYPTION && if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
!strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT)) !strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT))
f2fs_set_encrypted_inode(inode); f2fs_set_encrypted_inode(inode);
f2fs_mark_inode_dirty_sync(inode); f2fs_mark_inode_dirty_sync(inode, true);
if (!error && S_ISDIR(inode->i_mode)) if (!error && S_ISDIR(inode->i_mode))
set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP); set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_CP);
exit: exit:
......
...@@ -52,10 +52,17 @@ ...@@ -52,10 +52,17 @@
#define VERSION_LEN 256 #define VERSION_LEN 256
#define MAX_VOLUME_NAME 512 #define MAX_VOLUME_NAME 512
#define MAX_PATH_LEN 64
#define MAX_DEVICES 8
/* /*
* For superblock * For superblock
*/ */
struct f2fs_device {
__u8 path[MAX_PATH_LEN];
__le32 total_segments;
} __packed;
struct f2fs_super_block { struct f2fs_super_block {
__le32 magic; /* Magic Number */ __le32 magic; /* Magic Number */
__le16 major_ver; /* Major Version */ __le16 major_ver; /* Major Version */
...@@ -94,7 +101,8 @@ struct f2fs_super_block { ...@@ -94,7 +101,8 @@ struct f2fs_super_block {
__le32 feature; /* defined features */ __le32 feature; /* defined features */
__u8 encryption_level; /* versioning level for encryption */ __u8 encryption_level; /* versioning level for encryption */
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
__u8 reserved[871]; /* valid reserved region */ struct f2fs_device devs[MAX_DEVICES]; /* device list */
__u8 reserved[327]; /* valid reserved region */
} __packed; } __packed;
/* /*
......
...@@ -1111,6 +1111,27 @@ TRACE_EVENT(f2fs_issue_discard, ...@@ -1111,6 +1111,27 @@ TRACE_EVENT(f2fs_issue_discard,
(unsigned long long)__entry->blklen) (unsigned long long)__entry->blklen)
); );
TRACE_EVENT(f2fs_issue_reset_zone,
TP_PROTO(struct super_block *sb, block_t blkstart),
TP_ARGS(sb, blkstart),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(block_t, blkstart)
),
TP_fast_assign(
__entry->dev = sb->s_dev;
__entry->blkstart = blkstart;
),
TP_printk("dev = (%d,%d), reset zone at block = 0x%llx",
show_dev(__entry),
(unsigned long long)__entry->blkstart)
);
TRACE_EVENT(f2fs_issue_flush, TRACE_EVENT(f2fs_issue_flush,
TP_PROTO(struct super_block *sb, unsigned int nobarrier, TP_PROTO(struct super_block *sb, unsigned int nobarrier,
......
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