Commit 70ef8f0d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull f2fs updates from Jaegeuk Kim:
 "In this round, we've focused on enhancing performance with regards to
  block allocation, GC, and discard/in-place-update IO controls. There
  are a bunch of clean-ups as well as minor bug fixes.

  Enhancements:
   - disable heap-based allocation by default
   - issue small-sized discard commands by default
   - change the policy of data hotness for logging
   - distinguish IOs in terms of size and wbc type
   - start SSR earlier to avoid foreground GC
   - enhance data structures managing discard commands
   - enhance in-place update flow
   - add some more fault injection routines
   - secure one more xattr entry

  Bug fixes:
   - calculate victim cost for GC correctly
   - remain correct victim segment number for GC
   - race condition in nid allocator and initializer
   - stale pointer produced by atomic_writes
   - fix missing REQ_SYNC for flush commands
   - handle missing errors in more corner cases"

* tag 'for-f2fs-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (111 commits)
  f2fs: fix a mount fail for wrong next_scan_nid
  f2fs: enhance scalability of trace macro
  f2fs: relocate inode_{,un}lock in F2FS_IOC_SETFLAGS
  f2fs: Make flush bios explicitely sync
  f2fs: show available_nids in f2fs/status
  f2fs: flush dirty nats periodically
  f2fs: introduce CP_TRIMMED_FLAG to avoid unneeded discard
  f2fs: allow cpc->reason to indicate more than one reason
  f2fs: release cp and dnode lock before IPU
  f2fs: shrink size of struct discard_cmd
  f2fs: don't hold cmd_lock during waiting discard command
  f2fs: nullify fio->encrypted_page for each writes
  f2fs: sanity check segment count
  f2fs: introduce valid_ipu_blkaddr to clean up
  f2fs: lookup extent cache first under IPU scenario
  f2fs: reconstruct code to write a data page
  f2fs: introduce __wait_discard_cmd
  f2fs: introduce __issue_discard_cmd
  f2fs: enable small discard by default
  f2fs: delay awaking discard thread
  ...
parents 677375ce e9cdd307
...@@ -275,10 +275,11 @@ static int f2fs_write_meta_pages(struct address_space *mapping, ...@@ -275,10 +275,11 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
goto skip_write; goto skip_write;
trace_f2fs_writepages(mapping->host, wbc, META); /* if locked failed, cp will flush dirty pages instead */
if (!mutex_trylock(&sbi->cp_mutex))
goto skip_write;
/* if mounting is failed, skip writing node pages */ trace_f2fs_writepages(mapping->host, wbc, META);
mutex_lock(&sbi->cp_mutex);
diff = nr_pages_to_write(sbi, META, wbc); diff = nr_pages_to_write(sbi, META, wbc);
written = sync_meta_pages(sbi, META, wbc->nr_to_write); written = sync_meta_pages(sbi, META, wbc->nr_to_write);
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
...@@ -567,7 +568,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) ...@@ -567,7 +568,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
if (ni.blk_addr != NULL_ADDR) { if (ni.blk_addr != NULL_ADDR) {
set_sbi_flag(sbi, SBI_NEED_FSCK); set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_msg(sbi->sb, KERN_WARNING, f2fs_msg(sbi->sb, KERN_WARNING,
"%s: orphan failed (ino=%x), run fsck to fix.", "%s: orphan failed (ino=%x) by kernel, retry mount.",
__func__, ino); __func__, ino);
return -EIO; return -EIO;
} }
...@@ -677,7 +678,7 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr, ...@@ -677,7 +678,7 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
*cp_block = (struct f2fs_checkpoint *)page_address(*cp_page); *cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
crc_offset = le32_to_cpu((*cp_block)->checksum_offset); crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
if (crc_offset >= blk_size) { if (crc_offset > (blk_size - sizeof(__le32))) {
f2fs_msg(sbi->sb, KERN_WARNING, f2fs_msg(sbi->sb, KERN_WARNING,
"invalid crc_offset: %zu", crc_offset); "invalid crc_offset: %zu", crc_offset);
return -EINVAL; return -EINVAL;
...@@ -816,7 +817,9 @@ static void __add_dirty_inode(struct inode *inode, enum inode_type type) ...@@ -816,7 +817,9 @@ static void __add_dirty_inode(struct inode *inode, enum inode_type type)
return; return;
set_inode_flag(inode, flag); set_inode_flag(inode, flag);
list_add_tail(&F2FS_I(inode)->dirty_list, &sbi->inode_list[type]); if (!f2fs_is_volatile_file(inode))
list_add_tail(&F2FS_I(inode)->dirty_list,
&sbi->inode_list[type]);
stat_inc_dirty_inode(sbi, type); stat_inc_dirty_inode(sbi, type);
} }
...@@ -941,6 +944,19 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi) ...@@ -941,6 +944,19 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
return 0; return 0;
} }
static void __prepare_cp_block(struct f2fs_sb_info *sbi)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi);
nid_t last_nid = nm_i->next_scan_nid;
next_free_nid(sbi, &last_nid);
ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi));
ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi));
ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi));
ckpt->next_free_nid = cpu_to_le32(last_nid);
}
/* /*
* Freeze all the FS-operations for checkpoint. * Freeze all the FS-operations for checkpoint.
*/ */
...@@ -964,21 +980,26 @@ static int block_operations(struct f2fs_sb_info *sbi) ...@@ -964,21 +980,26 @@ static int block_operations(struct f2fs_sb_info *sbi)
err = sync_dirty_inodes(sbi, DIR_INODE); err = sync_dirty_inodes(sbi, DIR_INODE);
if (err) if (err)
goto out; goto out;
cond_resched();
goto retry_flush_dents; goto retry_flush_dents;
} }
/*
* POR: we should ensure that there are no dirty node pages
* until finishing nat/sit flush. inode->i_blocks can be updated.
*/
down_write(&sbi->node_change);
if (get_pages(sbi, F2FS_DIRTY_IMETA)) { if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
up_write(&sbi->node_change);
f2fs_unlock_all(sbi); f2fs_unlock_all(sbi);
err = f2fs_sync_inode_meta(sbi); err = f2fs_sync_inode_meta(sbi);
if (err) if (err)
goto out; goto out;
cond_resched();
goto retry_flush_dents; goto retry_flush_dents;
} }
/*
* POR: we should ensure that there are no dirty node pages
* until finishing nat/sit flush.
*/
retry_flush_nodes: retry_flush_nodes:
down_write(&sbi->node_write); down_write(&sbi->node_write);
...@@ -986,11 +1007,20 @@ static int block_operations(struct f2fs_sb_info *sbi) ...@@ -986,11 +1007,20 @@ static int block_operations(struct f2fs_sb_info *sbi)
up_write(&sbi->node_write); up_write(&sbi->node_write);
err = sync_node_pages(sbi, &wbc); err = sync_node_pages(sbi, &wbc);
if (err) { if (err) {
up_write(&sbi->node_change);
f2fs_unlock_all(sbi); f2fs_unlock_all(sbi);
goto out; goto out;
} }
cond_resched();
goto retry_flush_nodes; goto retry_flush_nodes;
} }
/*
* sbi->node_change is used only for AIO write_begin path which produces
* dirty node blocks and some checkpoint values by block allocation.
*/
__prepare_cp_block(sbi);
up_write(&sbi->node_change);
out: out:
blk_finish_plug(&plug); blk_finish_plug(&plug);
return err; return err;
...@@ -1024,16 +1054,20 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1024,16 +1054,20 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
spin_lock(&sbi->cp_lock); spin_lock(&sbi->cp_lock);
if (cpc->reason == CP_UMOUNT && ckpt->cp_pack_total_block_count > if ((cpc->reason & CP_UMOUNT) &&
le32_to_cpu(ckpt->cp_pack_total_block_count) >
sbi->blocks_per_seg - NM_I(sbi)->nat_bits_blocks) sbi->blocks_per_seg - NM_I(sbi)->nat_bits_blocks)
disable_nat_bits(sbi, false); disable_nat_bits(sbi, false);
if (cpc->reason == CP_UMOUNT) if (cpc->reason & CP_TRIMMED)
__set_ckpt_flags(ckpt, CP_TRIMMED_FLAG);
if (cpc->reason & CP_UMOUNT)
__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
else else
__clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); __clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
if (cpc->reason == CP_FASTBOOT) if (cpc->reason & CP_FASTBOOT)
__set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); __set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
else else
__clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); __clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
...@@ -1057,7 +1091,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1057,7 +1091,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num; unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
nid_t last_nid = nm_i->next_scan_nid;
block_t start_blk; block_t start_blk;
unsigned int data_sum_blocks, orphan_blocks; unsigned int data_sum_blocks, orphan_blocks;
__u32 crc32 = 0; __u32 crc32 = 0;
...@@ -1074,14 +1107,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1074,14 +1107,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
return -EIO; return -EIO;
} }
next_free_nid(sbi, &last_nid);
/* /*
* modify checkpoint * modify checkpoint
* version number is already updated * version number is already updated
*/ */
ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi)); ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi));
ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi));
ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); ckpt->free_segment_count = cpu_to_le32(free_segments(sbi));
for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
ckpt->cur_node_segno[i] = ckpt->cur_node_segno[i] =
...@@ -1100,10 +1130,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1100,10 +1130,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
curseg_alloc_type(sbi, i + CURSEG_HOT_DATA); curseg_alloc_type(sbi, i + CURSEG_HOT_DATA);
} }
ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi));
ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi));
ckpt->next_free_nid = cpu_to_le32(last_nid);
/* 2 cp + n data seg summary + orphan inode blocks */ /* 2 cp + n data seg summary + orphan inode blocks */
data_sum_blocks = npages_for_summary_flush(sbi, false); data_sum_blocks = npages_for_summary_flush(sbi, false);
spin_lock(&sbi->cp_lock); spin_lock(&sbi->cp_lock);
...@@ -1143,7 +1169,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1143,7 +1169,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* write nat bits */ /* write nat bits */
if (enabled_nat_bits(sbi, cpc)) { if (enabled_nat_bits(sbi, cpc)) {
__u64 cp_ver = cur_cp_version(ckpt); __u64 cp_ver = cur_cp_version(ckpt);
unsigned int i;
block_t blk; block_t blk;
cp_ver |= ((__u64)crc32 << 32); cp_ver |= ((__u64)crc32 << 32);
...@@ -1250,8 +1275,8 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1250,8 +1275,8 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
mutex_lock(&sbi->cp_mutex); mutex_lock(&sbi->cp_mutex);
if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) &&
(cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC || ((cpc->reason & CP_FASTBOOT) || (cpc->reason & CP_SYNC) ||
(cpc->reason == CP_DISCARD && !sbi->discard_blks))) ((cpc->reason & CP_DISCARD) && !sbi->discard_blks)))
goto out; goto out;
if (unlikely(f2fs_cp_error(sbi))) { if (unlikely(f2fs_cp_error(sbi))) {
err = -EIO; err = -EIO;
...@@ -1273,7 +1298,7 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1273,7 +1298,7 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
f2fs_flush_merged_bios(sbi); f2fs_flush_merged_bios(sbi);
/* this is the case of multiple fstrims without any changes */ /* this is the case of multiple fstrims without any changes */
if (cpc->reason == CP_DISCARD) { if (cpc->reason & CP_DISCARD) {
if (!exist_trim_candidates(sbi, cpc)) { if (!exist_trim_candidates(sbi, cpc)) {
unblock_operations(sbi); unblock_operations(sbi);
goto out; goto out;
...@@ -1311,7 +1336,7 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1311,7 +1336,7 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
unblock_operations(sbi); unblock_operations(sbi);
stat_inc_cp_count(sbi->stat_info); stat_inc_cp_count(sbi->stat_info);
if (cpc->reason == CP_RECOVERY) if (cpc->reason & CP_RECOVERY)
f2fs_msg(sbi->sb, KERN_NOTICE, f2fs_msg(sbi->sb, KERN_NOTICE,
"checkpoint: version = %llx", ckpt_ver); "checkpoint: version = %llx", ckpt_ver);
......
This diff is collapsed.
...@@ -51,15 +51,26 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -51,15 +51,26 @@ static void update_general_status(struct f2fs_sb_info *sbi)
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->aw_cnt = atomic_read(&sbi->aw_cnt); si->aw_cnt = atomic_read(&sbi->aw_cnt);
si->vw_cnt = atomic_read(&sbi->vw_cnt);
si->max_aw_cnt = atomic_read(&sbi->max_aw_cnt); si->max_aw_cnt = atomic_read(&sbi->max_aw_cnt);
si->max_vw_cnt = atomic_read(&sbi->max_vw_cnt);
si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA); si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA);
si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA); si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA);
if (SM_I(sbi) && SM_I(sbi)->fcc_info) if (SM_I(sbi) && SM_I(sbi)->fcc_info) {
si->nr_flush = si->nr_flushed =
atomic_read(&SM_I(sbi)->fcc_info->submit_flush); atomic_read(&SM_I(sbi)->fcc_info->issued_flush);
if (SM_I(sbi) && SM_I(sbi)->dcc_info) si->nr_flushing =
si->nr_discard = atomic_read(&SM_I(sbi)->fcc_info->issing_flush);
atomic_read(&SM_I(sbi)->dcc_info->submit_discard); }
if (SM_I(sbi) && SM_I(sbi)->dcc_info) {
si->nr_discarded =
atomic_read(&SM_I(sbi)->dcc_info->issued_discard);
si->nr_discarding =
atomic_read(&SM_I(sbi)->dcc_info->issing_discard);
si->nr_discard_cmd =
atomic_read(&SM_I(sbi)->dcc_info->discard_cmd_cnt);
si->undiscard_blks = SM_I(sbi)->dcc_info->undiscard_blks;
}
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);
...@@ -86,6 +97,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -86,6 +97,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
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->free_nids = NM_I(sbi)->nid_cnt[FREE_NID_LIST]; si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID_LIST];
si->avail_nids = NM_I(sbi)->available_nids;
si->alloc_nids = NM_I(sbi)->nid_cnt[ALLOC_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)
...@@ -99,8 +111,8 @@ static void update_general_status(struct f2fs_sb_info *sbi) ...@@ -99,8 +111,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) { for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) {
struct curseg_info *curseg = CURSEG_I(sbi, i); struct curseg_info *curseg = CURSEG_I(sbi, i);
si->curseg[i] = curseg->segno; si->curseg[i] = curseg->segno;
si->cursec[i] = curseg->segno / sbi->segs_per_sec; si->cursec[i] = GET_SEC_FROM_SEG(sbi, curseg->segno);
si->curzone[i] = si->cursec[i] / sbi->secs_per_zone; si->curzone[i] = GET_ZONE_FROM_SEC(sbi, si->cursec[i]);
} }
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
...@@ -124,10 +136,10 @@ static void update_sit_info(struct f2fs_sb_info *sbi) ...@@ -124,10 +136,10 @@ 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 * sbi->blocks_per_seg; blks_per_sec = BLKS_PER_SEC(sbi);
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, true);
dist = abs(vblocks - hblks_per_sec); dist = abs(vblocks - hblks_per_sec);
bimodal += dist * dist; bimodal += dist * dist;
...@@ -156,7 +168,11 @@ static void update_mem_info(struct f2fs_sb_info *sbi) ...@@ -156,7 +168,11 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
if (si->base_mem) if (si->base_mem)
goto get_cache; goto get_cache;
si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize; /* build stat */
si->base_mem = sizeof(struct f2fs_stat_info);
/* build superblock */
si->base_mem += sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
si->base_mem += 2 * sizeof(struct f2fs_inode_info); si->base_mem += 2 * sizeof(struct f2fs_inode_info);
si->base_mem += sizeof(*sbi->ckpt); si->base_mem += sizeof(*sbi->ckpt);
si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE; si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE;
...@@ -208,8 +224,11 @@ static void update_mem_info(struct f2fs_sb_info *sbi) ...@@ -208,8 +224,11 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
/* build merge flush thread */ /* build merge flush thread */
if (SM_I(sbi)->fcc_info) if (SM_I(sbi)->fcc_info)
si->cache_mem += sizeof(struct flush_cmd_control); si->cache_mem += sizeof(struct flush_cmd_control);
if (SM_I(sbi)->dcc_info) if (SM_I(sbi)->dcc_info) {
si->cache_mem += sizeof(struct discard_cmd_control); si->cache_mem += sizeof(struct discard_cmd_control);
si->cache_mem += sizeof(struct discard_cmd) *
atomic_read(&SM_I(sbi)->dcc_info->discard_cmd_cnt);
}
/* free nids */ /* free nids */
si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] + si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] +
...@@ -330,11 +349,16 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -330,11 +349,16 @@ 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, " - IO (CP: %4d, Data: %4d, Flush: %4d, Discard: %4d)\n", seq_printf(s, " - IO (CP: %4d, Data: %4d, Flush: (%4d %4d), "
"Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n",
si->nr_wb_cp_data, si->nr_wb_data, si->nr_wb_cp_data, si->nr_wb_data,
si->nr_flush, si->nr_discard); si->nr_flushing, si->nr_flushed,
seq_printf(s, " - inmem: %4d, atomic IO: %4d (Max. %4d)\n", si->nr_discarding, si->nr_discarded,
si->inmem_pages, si->aw_cnt, si->max_aw_cnt); si->nr_discard_cmd, si->undiscard_blks);
seq_printf(s, " - inmem: %4d, atomic IO: %4d (Max. %4d), "
"volatile IO: %4d (Max. %4d)\n",
si->inmem_pages, si->aw_cnt, si->max_aw_cnt,
si->vw_cnt, si->max_vw_cnt);
seq_printf(s, " - nodes: %4d 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: %4d in dirs:%4d (%4d)\n", seq_printf(s, " - dents: %4d in dirs:%4d (%4d)\n",
...@@ -347,8 +371,8 @@ static int stat_show(struct seq_file *s, void *v) ...@@ -347,8 +371,8 @@ static int stat_show(struct seq_file *s, void *v)
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, alloc_nids: %9d\n", seq_printf(s, " - free_nids: %9d/%9d\n - alloc_nids: %9d\n",
si->free_nids, si->alloc_nids); si->free_nids, si->avail_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, " [");
...@@ -434,7 +458,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi) ...@@ -434,7 +458,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
atomic_set(&sbi->inplace_count, 0); atomic_set(&sbi->inplace_count, 0);
atomic_set(&sbi->aw_cnt, 0); atomic_set(&sbi->aw_cnt, 0);
atomic_set(&sbi->vw_cnt, 0);
atomic_set(&sbi->max_aw_cnt, 0); atomic_set(&sbi->max_aw_cnt, 0);
atomic_set(&sbi->max_vw_cnt, 0);
mutex_lock(&f2fs_stat_mutex); mutex_lock(&f2fs_stat_mutex);
list_add_tail(&si->stat_list, &f2fs_stat_list); list_add_tail(&si->stat_list, &f2fs_stat_list);
......
...@@ -94,7 +94,7 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, ...@@ -94,7 +94,7 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page); dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); make_dentry_ptr_block(NULL, &d, dentry_blk);
de = find_target_dentry(fname, namehash, max_slots, &d); de = find_target_dentry(fname, namehash, max_slots, &d);
if (de) if (de)
*res_page = dentry_page; *res_page = dentry_page;
...@@ -192,14 +192,10 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, ...@@ -192,14 +192,10 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
f2fs_put_page(dentry_page, 0); f2fs_put_page(dentry_page, 0);
} }
/* This is to increase the speed of f2fs_create */ if (!de && room && F2FS_I(dir)->chash != namehash) {
if (!de && room) {
F2FS_I(dir)->task = current;
if (F2FS_I(dir)->chash != namehash) {
F2FS_I(dir)->chash = namehash; F2FS_I(dir)->chash = namehash;
F2FS_I(dir)->clevel = level; F2FS_I(dir)->clevel = level;
} }
}
return de; return de;
} }
...@@ -239,6 +235,9 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir, ...@@ -239,6 +235,9 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
break; break;
} }
out: out:
/* This is to increase the speed of f2fs_create */
if (!de)
F2FS_I(dir)->task = current;
return de; return de;
} }
...@@ -322,24 +321,6 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage) ...@@ -322,24 +321,6 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
set_page_dirty(ipage); set_page_dirty(ipage);
} }
int update_dent_inode(struct inode *inode, struct inode *to,
const struct qstr *name)
{
struct page *page;
if (file_enc_name(to))
return 0;
page = get_node_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(page))
return PTR_ERR(page);
init_dent_inode(name, page);
f2fs_put_page(page, 1);
return 0;
}
void do_make_empty_dir(struct inode *inode, struct inode *parent, void do_make_empty_dir(struct inode *inode, struct inode *parent,
struct f2fs_dentry_ptr *d) struct f2fs_dentry_ptr *d)
{ {
...@@ -369,7 +350,7 @@ static int make_empty_dir(struct inode *inode, ...@@ -369,7 +350,7 @@ static int make_empty_dir(struct inode *inode,
dentry_blk = kmap_atomic(dentry_page); dentry_blk = kmap_atomic(dentry_page);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); make_dentry_ptr_block(NULL, &d, dentry_blk);
do_make_empty_dir(inode, parent, &d); do_make_empty_dir(inode, parent, &d);
kunmap_atomic(dentry_blk); kunmap_atomic(dentry_blk);
...@@ -423,8 +404,11 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, ...@@ -423,8 +404,11 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
set_cold_node(inode, page); set_cold_node(inode, page);
} }
if (new_name) if (new_name) {
init_dent_inode(new_name, page); init_dent_inode(new_name, page);
if (f2fs_encrypted_inode(dir))
file_set_enc_name(inode);
}
/* /*
* This file should be checkpointed during fsync. * This file should be checkpointed during fsync.
...@@ -584,11 +568,9 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, ...@@ -584,11 +568,9 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
err = PTR_ERR(page); err = PTR_ERR(page);
goto fail; goto fail;
} }
if (f2fs_encrypted_inode(dir))
file_set_enc_name(inode);
} }
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1); make_dentry_ptr_block(NULL, &d, dentry_blk);
f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos); f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos);
set_page_dirty(dentry_page); set_page_dirty(dentry_page);
...@@ -896,7 +878,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) ...@@ -896,7 +878,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
dentry_blk = kmap(dentry_page); dentry_blk = kmap(dentry_page);
make_dentry_ptr(inode, &d, (void *)dentry_blk, 1); make_dentry_ptr_block(inode, &d, dentry_blk);
err = f2fs_fill_dentries(ctx, &d, err = f2fs_fill_dentries(ctx, &d,
n * NR_DENTRY_IN_BLOCK, &fstr); n * NR_DENTRY_IN_BLOCK, &fstr);
......
...@@ -18,6 +18,179 @@ ...@@ -18,6 +18,179 @@
#include "node.h" #include "node.h"
#include <trace/events/f2fs.h> #include <trace/events/f2fs.h>
static struct rb_entry *__lookup_rb_tree_fast(struct rb_entry *cached_re,
unsigned int ofs)
{
if (cached_re) {
if (cached_re->ofs <= ofs &&
cached_re->ofs + cached_re->len > ofs) {
return cached_re;
}
}
return NULL;
}
static struct rb_entry *__lookup_rb_tree_slow(struct rb_root *root,
unsigned int ofs)
{
struct rb_node *node = root->rb_node;
struct rb_entry *re;
while (node) {
re = rb_entry(node, struct rb_entry, rb_node);
if (ofs < re->ofs)
node = node->rb_left;
else if (ofs >= re->ofs + re->len)
node = node->rb_right;
else
return re;
}
return NULL;
}
struct rb_entry *__lookup_rb_tree(struct rb_root *root,
struct rb_entry *cached_re, unsigned int ofs)
{
struct rb_entry *re;
re = __lookup_rb_tree_fast(cached_re, ofs);
if (!re)
return __lookup_rb_tree_slow(root, ofs);
return re;
}
struct rb_node **__lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
struct rb_root *root, struct rb_node **parent,
unsigned int ofs)
{
struct rb_node **p = &root->rb_node;
struct rb_entry *re;
while (*p) {
*parent = *p;
re = rb_entry(*parent, struct rb_entry, rb_node);
if (ofs < re->ofs)
p = &(*p)->rb_left;
else if (ofs >= re->ofs + re->len)
p = &(*p)->rb_right;
else
f2fs_bug_on(sbi, 1);
}
return p;
}
/*
* lookup rb entry in position of @ofs in rb-tree,
* if hit, return the entry, otherwise, return NULL
* @prev_ex: extent before ofs
* @next_ex: extent after ofs
* @insert_p: insert point for new extent at ofs
* in order to simpfy the insertion after.
* tree must stay unchanged between lookup and insertion.
*/
struct rb_entry *__lookup_rb_tree_ret(struct rb_root *root,
struct rb_entry *cached_re,
unsigned int ofs,
struct rb_entry **prev_entry,
struct rb_entry **next_entry,
struct rb_node ***insert_p,
struct rb_node **insert_parent,
bool force)
{
struct rb_node **pnode = &root->rb_node;
struct rb_node *parent = NULL, *tmp_node;
struct rb_entry *re = cached_re;
*insert_p = NULL;
*insert_parent = NULL;
*prev_entry = NULL;
*next_entry = NULL;
if (RB_EMPTY_ROOT(root))
return NULL;
if (re) {
if (re->ofs <= ofs && re->ofs + re->len > ofs)
goto lookup_neighbors;
}
while (*pnode) {
parent = *pnode;
re = rb_entry(*pnode, struct rb_entry, rb_node);
if (ofs < re->ofs)
pnode = &(*pnode)->rb_left;
else if (ofs >= re->ofs + re->len)
pnode = &(*pnode)->rb_right;
else
goto lookup_neighbors;
}
*insert_p = pnode;
*insert_parent = parent;
re = rb_entry(parent, struct rb_entry, rb_node);
tmp_node = parent;
if (parent && ofs > re->ofs)
tmp_node = rb_next(parent);
*next_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
tmp_node = parent;
if (parent && ofs < re->ofs)
tmp_node = rb_prev(parent);
*prev_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
return NULL;
lookup_neighbors:
if (ofs == re->ofs || force) {
/* lookup prev node for merging backward later */
tmp_node = rb_prev(&re->rb_node);
*prev_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
}
if (ofs == re->ofs + re->len - 1 || force) {
/* lookup next node for merging frontward later */
tmp_node = rb_next(&re->rb_node);
*next_entry = rb_entry_safe(tmp_node, struct rb_entry, rb_node);
}
return re;
}
bool __check_rb_tree_consistence(struct f2fs_sb_info *sbi,
struct rb_root *root)
{
#ifdef CONFIG_F2FS_CHECK_FS
struct rb_node *cur = rb_first(root), *next;
struct rb_entry *cur_re, *next_re;
if (!cur)
return true;
while (cur) {
next = rb_next(cur);
if (!next)
return true;
cur_re = rb_entry(cur, struct rb_entry, rb_node);
next_re = rb_entry(next, struct rb_entry, rb_node);
if (cur_re->ofs + cur_re->len > next_re->ofs) {
f2fs_msg(sbi->sb, KERN_INFO, "inconsistent rbtree, "
"cur(%u, %u) next(%u, %u)",
cur_re->ofs, cur_re->len,
next_re->ofs, next_re->len);
return false;
}
cur = next;
}
#endif
return true;
}
static struct kmem_cache *extent_tree_slab; static struct kmem_cache *extent_tree_slab;
static struct kmem_cache *extent_node_slab; static struct kmem_cache *extent_node_slab;
...@@ -102,36 +275,6 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode) ...@@ -102,36 +275,6 @@ static struct extent_tree *__grab_extent_tree(struct inode *inode)
return et; return et;
} }
static struct extent_node *__lookup_extent_tree(struct f2fs_sb_info *sbi,
struct extent_tree *et, unsigned int fofs)
{
struct rb_node *node = et->root.rb_node;
struct extent_node *en = et->cached_en;
if (en) {
struct extent_info *cei = &en->ei;
if (cei->fofs <= fofs && cei->fofs + cei->len > fofs) {
stat_inc_cached_node_hit(sbi);
return en;
}
}
while (node) {
en = rb_entry(node, struct extent_node, rb_node);
if (fofs < en->ei.fofs) {
node = node->rb_left;
} else if (fofs >= en->ei.fofs + en->ei.len) {
node = node->rb_right;
} else {
stat_inc_rbtree_node_hit(sbi);
return en;
}
}
return NULL;
}
static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi, static struct extent_node *__init_extent_tree(struct f2fs_sb_info *sbi,
struct extent_tree *et, struct extent_info *ei) struct extent_tree *et, struct extent_info *ei)
{ {
...@@ -237,8 +380,16 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, ...@@ -237,8 +380,16 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
goto out; goto out;
} }
en = __lookup_extent_tree(sbi, et, pgofs); en = (struct extent_node *)__lookup_rb_tree(&et->root,
if (en) { (struct rb_entry *)et->cached_en, pgofs);
if (!en)
goto out;
if (en == et->cached_en)
stat_inc_cached_node_hit(sbi);
else
stat_inc_rbtree_node_hit(sbi);
*ei = en->ei; *ei = en->ei;
spin_lock(&sbi->extent_lock); spin_lock(&sbi->extent_lock);
if (!list_empty(&en->list)) { if (!list_empty(&en->list)) {
...@@ -247,7 +398,6 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, ...@@ -247,7 +398,6 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
} }
spin_unlock(&sbi->extent_lock); spin_unlock(&sbi->extent_lock);
ret = true; ret = true;
}
out: out:
stat_inc_total_hit(sbi); stat_inc_total_hit(sbi);
read_unlock(&et->lock); read_unlock(&et->lock);
...@@ -256,83 +406,6 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, ...@@ -256,83 +406,6 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
return ret; return ret;
} }
/*
* lookup extent at @fofs, if hit, return the extent
* if not, return NULL and
* @prev_ex: extent before fofs
* @next_ex: extent after fofs
* @insert_p: insert point for new extent at fofs
* in order to simpfy the insertion after.
* tree must stay unchanged between lookup and insertion.
*/
static struct extent_node *__lookup_extent_tree_ret(struct extent_tree *et,
unsigned int fofs,
struct extent_node **prev_ex,
struct extent_node **next_ex,
struct rb_node ***insert_p,
struct rb_node **insert_parent)
{
struct rb_node **pnode = &et->root.rb_node;
struct rb_node *parent = NULL, *tmp_node;
struct extent_node *en = et->cached_en;
*insert_p = NULL;
*insert_parent = NULL;
*prev_ex = NULL;
*next_ex = NULL;
if (RB_EMPTY_ROOT(&et->root))
return NULL;
if (en) {
struct extent_info *cei = &en->ei;
if (cei->fofs <= fofs && cei->fofs + cei->len > fofs)
goto lookup_neighbors;
}
while (*pnode) {
parent = *pnode;
en = rb_entry(*pnode, struct extent_node, rb_node);
if (fofs < en->ei.fofs)
pnode = &(*pnode)->rb_left;
else if (fofs >= en->ei.fofs + en->ei.len)
pnode = &(*pnode)->rb_right;
else
goto lookup_neighbors;
}
*insert_p = pnode;
*insert_parent = parent;
en = rb_entry(parent, struct extent_node, rb_node);
tmp_node = parent;
if (parent && fofs > en->ei.fofs)
tmp_node = rb_next(parent);
*next_ex = rb_entry_safe(tmp_node, struct extent_node, rb_node);
tmp_node = parent;
if (parent && fofs < en->ei.fofs)
tmp_node = rb_prev(parent);
*prev_ex = rb_entry_safe(tmp_node, struct extent_node, rb_node);
return NULL;
lookup_neighbors:
if (fofs == en->ei.fofs) {
/* lookup prev node for merging backward later */
tmp_node = rb_prev(&en->rb_node);
*prev_ex = rb_entry_safe(tmp_node, struct extent_node, rb_node);
}
if (fofs == en->ei.fofs + en->ei.len - 1) {
/* lookup next node for merging frontward later */
tmp_node = rb_next(&en->rb_node);
*next_ex = rb_entry_safe(tmp_node, struct extent_node, rb_node);
}
return en;
}
static struct extent_node *__try_merge_extent_node(struct inode *inode, static struct extent_node *__try_merge_extent_node(struct inode *inode,
struct extent_tree *et, struct extent_info *ei, struct extent_tree *et, struct extent_info *ei,
struct extent_node *prev_ex, struct extent_node *prev_ex,
...@@ -387,17 +460,7 @@ static struct extent_node *__insert_extent_tree(struct inode *inode, ...@@ -387,17 +460,7 @@ static struct extent_node *__insert_extent_tree(struct inode *inode,
goto do_insert; goto do_insert;
} }
while (*p) { p = __lookup_rb_tree_for_insert(sbi, &et->root, &parent, ei->fofs);
parent = *p;
en = rb_entry(parent, struct extent_node, rb_node);
if (ei->fofs < en->ei.fofs)
p = &(*p)->rb_left;
else if (ei->fofs >= en->ei.fofs + en->ei.len)
p = &(*p)->rb_right;
else
f2fs_bug_on(sbi, 1);
}
do_insert: do_insert:
en = __attach_extent_node(sbi, et, ei, parent, p); en = __attach_extent_node(sbi, et, ei, parent, p);
if (!en) if (!en)
...@@ -447,8 +510,11 @@ static void f2fs_update_extent_tree_range(struct inode *inode, ...@@ -447,8 +510,11 @@ static void f2fs_update_extent_tree_range(struct inode *inode,
__drop_largest_extent(inode, fofs, len); __drop_largest_extent(inode, fofs, len);
/* 1. lookup first extent node in range [fofs, fofs + len - 1] */ /* 1. lookup first extent node in range [fofs, fofs + len - 1] */
en = __lookup_extent_tree_ret(et, fofs, &prev_en, &next_en, en = (struct extent_node *)__lookup_rb_tree_ret(&et->root,
&insert_p, &insert_parent); (struct rb_entry *)et->cached_en, fofs,
(struct rb_entry **)&prev_en,
(struct rb_entry **)&next_en,
&insert_p, &insert_parent, false);
if (!en) if (!en)
en = next_en; en = next_en;
......
This diff is collapsed.
This diff is collapsed.
...@@ -84,7 +84,7 @@ static int gc_thread_func(void *data) ...@@ -84,7 +84,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), true)) if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO))
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,
...@@ -172,7 +172,11 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, ...@@ -172,7 +172,11 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
if (gc_type != FG_GC && p->max_search > sbi->max_victim_search) if (gc_type != FG_GC && p->max_search > sbi->max_victim_search)
p->max_search = sbi->max_victim_search; p->max_search = sbi->max_victim_search;
p->offset = sbi->last_victim[p->gc_mode]; /* let's select beginning hot/small space first */
if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
p->offset = 0;
else
p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
} }
static unsigned int get_max_cost(struct f2fs_sb_info *sbi, static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
...@@ -182,7 +186,7 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi, ...@@ -182,7 +186,7 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
if (p->alloc_mode == SSR) if (p->alloc_mode == SSR)
return sbi->blocks_per_seg; return sbi->blocks_per_seg;
if (p->gc_mode == GC_GREEDY) if (p->gc_mode == GC_GREEDY)
return sbi->blocks_per_seg * p->ofs_unit; return 2 * 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 */
...@@ -207,7 +211,7 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi) ...@@ -207,7 +211,7 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
continue; continue;
clear_bit(secno, dirty_i->victim_secmap); clear_bit(secno, dirty_i->victim_secmap);
return secno * sbi->segs_per_sec; return GET_SEG_FROM_SEC(sbi, secno);
} }
return NULL_SEGNO; return NULL_SEGNO;
} }
...@@ -215,8 +219,8 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi) ...@@ -215,8 +219,8 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
{ {
struct sit_info *sit_i = SIT_I(sbi); struct sit_info *sit_i = SIT_I(sbi);
unsigned int secno = GET_SECNO(sbi, segno); unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
unsigned int start = secno * sbi->segs_per_sec; unsigned int start = GET_SEG_FROM_SEC(sbi, secno);
unsigned long long mtime = 0; unsigned long long mtime = 0;
unsigned int vblocks; unsigned int vblocks;
unsigned char age = 0; unsigned char age = 0;
...@@ -225,7 +229,7 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno) ...@@ -225,7 +229,7 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
for (i = 0; i < sbi->segs_per_sec; i++) for (i = 0; i < sbi->segs_per_sec; i++)
mtime += get_seg_entry(sbi, start + i)->mtime; mtime += get_seg_entry(sbi, start + i)->mtime;
vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec); vblocks = get_valid_blocks(sbi, segno, true);
mtime = div_u64(mtime, sbi->segs_per_sec); mtime = div_u64(mtime, sbi->segs_per_sec);
vblocks = div_u64(vblocks, sbi->segs_per_sec); vblocks = div_u64(vblocks, sbi->segs_per_sec);
...@@ -248,7 +252,7 @@ static unsigned int get_greedy_cost(struct f2fs_sb_info *sbi, ...@@ -248,7 +252,7 @@ static unsigned int get_greedy_cost(struct f2fs_sb_info *sbi,
unsigned int segno) unsigned int segno)
{ {
unsigned int valid_blocks = unsigned int valid_blocks =
get_valid_blocks(sbi, segno, sbi->segs_per_sec); get_valid_blocks(sbi, segno, true);
return IS_DATASEG(get_seg_entry(sbi, segno)->type) ? return IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
valid_blocks * 2 : valid_blocks; valid_blocks * 2 : valid_blocks;
...@@ -291,6 +295,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -291,6 +295,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
unsigned int *result, int gc_type, int type, char alloc_mode) unsigned int *result, int gc_type, int type, char alloc_mode)
{ {
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
struct sit_info *sm = SIT_I(sbi);
struct victim_sel_policy p; struct victim_sel_policy p;
unsigned int secno, last_victim; unsigned int secno, last_victim;
unsigned int last_segment = MAIN_SEGS(sbi); unsigned int last_segment = MAIN_SEGS(sbi);
...@@ -304,10 +309,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -304,10 +309,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
p.min_segno = NULL_SEGNO; p.min_segno = NULL_SEGNO;
p.min_cost = get_max_cost(sbi, &p); p.min_cost = get_max_cost(sbi, &p);
if (*result != NULL_SEGNO) {
if (IS_DATASEG(get_seg_entry(sbi, *result)->type) &&
get_valid_blocks(sbi, *result, false) &&
!sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result)))
p.min_segno = *result;
goto out;
}
if (p.max_search == 0) if (p.max_search == 0)
goto out; goto out;
last_victim = sbi->last_victim[p.gc_mode]; last_victim = sm->last_victim[p.gc_mode];
if (p.alloc_mode == LFS && gc_type == FG_GC) { if (p.alloc_mode == LFS && gc_type == FG_GC) {
p.min_segno = check_bg_victims(sbi); p.min_segno = check_bg_victims(sbi);
if (p.min_segno != NULL_SEGNO) if (p.min_segno != NULL_SEGNO)
...@@ -320,9 +333,10 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -320,9 +333,10 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
segno = find_next_bit(p.dirty_segmap, last_segment, p.offset); segno = find_next_bit(p.dirty_segmap, last_segment, p.offset);
if (segno >= last_segment) { if (segno >= last_segment) {
if (sbi->last_victim[p.gc_mode]) { if (sm->last_victim[p.gc_mode]) {
last_segment = sbi->last_victim[p.gc_mode]; last_segment =
sbi->last_victim[p.gc_mode] = 0; sm->last_victim[p.gc_mode];
sm->last_victim[p.gc_mode] = 0;
p.offset = 0; p.offset = 0;
continue; continue;
} }
...@@ -339,7 +353,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -339,7 +353,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
nsearched++; nsearched++;
} }
secno = GET_SECNO(sbi, segno); secno = GET_SEC_FROM_SEG(sbi, segno);
if (sec_usage_check(sbi, secno)) if (sec_usage_check(sbi, secno))
goto next; goto next;
...@@ -357,17 +371,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi, ...@@ -357,17 +371,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
} }
next: next:
if (nsearched >= p.max_search) { if (nsearched >= p.max_search) {
if (!sbi->last_victim[p.gc_mode] && segno <= last_victim) if (!sm->last_victim[p.gc_mode] && segno <= last_victim)
sbi->last_victim[p.gc_mode] = last_victim + 1; sm->last_victim[p.gc_mode] = last_victim + 1;
else else
sbi->last_victim[p.gc_mode] = segno + 1; sm->last_victim[p.gc_mode] = segno + 1;
sm->last_victim[p.gc_mode] %= MAIN_SEGS(sbi);
break; break;
} }
} }
if (p.min_segno != NULL_SEGNO) { if (p.min_segno != NULL_SEGNO) {
got_it: got_it:
if (p.alloc_mode == LFS) { if (p.alloc_mode == LFS) {
secno = GET_SECNO(sbi, p.min_segno); secno = GET_SEC_FROM_SEG(sbi, p.min_segno);
if (gc_type == FG_GC) if (gc_type == FG_GC)
sbi->cur_victim_sec = secno; sbi->cur_victim_sec = secno;
else else
...@@ -550,8 +565,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, ...@@ -550,8 +565,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
get_node_info(sbi, nid, dni); get_node_info(sbi, nid, dni);
if (sum->version != dni->version) { if (sum->version != dni->version) {
f2fs_put_page(node_page, 1); f2fs_msg(sbi->sb, KERN_WARNING,
return false; "%s: valid data with mismatched node version.",
__func__);
set_sbi_flag(sbi, SBI_NEED_FSCK);
} }
*nofs = ofs_of_node(node_page); *nofs = ofs_of_node(node_page);
...@@ -697,8 +714,10 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, ...@@ -697,8 +714,10 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
.type = DATA, .type = DATA,
.op = REQ_OP_WRITE, .op = REQ_OP_WRITE,
.op_flags = REQ_SYNC, .op_flags = REQ_SYNC,
.old_blkaddr = NULL_ADDR,
.page = page, .page = page,
.encrypted_page = NULL, .encrypted_page = NULL,
.need_lock = true,
}; };
bool is_dirty = PageDirty(page); bool is_dirty = PageDirty(page);
int err; int err;
...@@ -890,7 +909,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -890,7 +909,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
GET_SUM_BLOCK(sbi, segno)); GET_SUM_BLOCK(sbi, segno));
f2fs_put_page(sum_page, 0); f2fs_put_page(sum_page, 0);
if (get_valid_blocks(sbi, segno, 1) == 0 || if (get_valid_blocks(sbi, segno, false) == 0 ||
!PageUptodate(sum_page) || !PageUptodate(sum_page) ||
unlikely(f2fs_cp_error(sbi))) unlikely(f2fs_cp_error(sbi)))
goto next; goto next;
...@@ -905,7 +924,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -905,7 +924,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
* - mutex_lock(sentry_lock) - change_curseg() * - mutex_lock(sentry_lock) - change_curseg()
* - lock_page(sum_page) * - lock_page(sum_page)
*/ */
if (type == SUM_TYPE_NODE) if (type == SUM_TYPE_NODE)
gc_node_segment(sbi, sum->entries, segno, gc_type); gc_node_segment(sbi, sum->entries, segno, gc_type);
else else
...@@ -924,7 +942,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -924,7 +942,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
blk_finish_plug(&plug); blk_finish_plug(&plug);
if (gc_type == FG_GC && if (gc_type == FG_GC &&
get_valid_blocks(sbi, start_segno, sbi->segs_per_sec) == 0) get_valid_blocks(sbi, start_segno, true) == 0)
sec_freed = 1; sec_freed = 1;
stat_inc_call_count(sbi->stat_info); stat_inc_call_count(sbi->stat_info);
...@@ -932,13 +950,14 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -932,13 +950,14 @@ 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, bool background) 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;
int sec_freed = 0; int sec_freed = 0;
int ret = -EINVAL; int ret = -EINVAL;
struct cp_control cpc; struct cp_control cpc;
unsigned int init_segno = segno;
struct gc_inode_list gc_list = { struct gc_inode_list gc_list = {
.ilist = LIST_HEAD_INIT(gc_list.ilist), .ilist = LIST_HEAD_INIT(gc_list.ilist),
.iroot = RADIX_TREE_INIT(GFP_NOFS), .iroot = RADIX_TREE_INIT(GFP_NOFS),
...@@ -959,9 +978,11 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background) ...@@ -959,9 +978,11 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background)
* threshold, we can make them free by checkpoint. Then, we * threshold, we can make them free by checkpoint. Then, we
* secure free segments which doesn't need fggc any more. * secure free segments which doesn't need fggc any more.
*/ */
if (prefree_segments(sbi)) {
ret = write_checkpoint(sbi, &cpc); ret = write_checkpoint(sbi, &cpc);
if (ret) if (ret)
goto stop; goto stop;
}
if (has_not_enough_free_secs(sbi, 0, 0)) if (has_not_enough_free_secs(sbi, 0, 0))
gc_type = FG_GC; gc_type = FG_GC;
} }
...@@ -981,13 +1002,17 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background) ...@@ -981,13 +1002,17 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background)
sbi->cur_victim_sec = NULL_SEGNO; sbi->cur_victim_sec = NULL_SEGNO;
if (!sync) { if (!sync) {
if (has_not_enough_free_secs(sbi, sec_freed, 0)) if (has_not_enough_free_secs(sbi, sec_freed, 0)) {
segno = NULL_SEGNO;
goto gc_more; goto gc_more;
}
if (gc_type == FG_GC) if (gc_type == FG_GC)
ret = write_checkpoint(sbi, &cpc); ret = write_checkpoint(sbi, &cpc);
} }
stop: stop:
SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0;
SIT_I(sbi)->last_victim[FLUSH_DEVICE] = init_segno;
mutex_unlock(&sbi->gc_mutex); mutex_unlock(&sbi->gc_mutex);
put_gc_inode(&gc_list); put_gc_inode(&gc_list);
...@@ -999,7 +1024,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background) ...@@ -999,7 +1024,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background)
void build_gc_manager(struct f2fs_sb_info *sbi) void build_gc_manager(struct f2fs_sb_info *sbi)
{ {
u64 main_count, resv_count, ovp_count, blocks_per_sec; u64 main_count, resv_count, ovp_count;
DIRTY_I(sbi)->v_ops = &default_v_ops; DIRTY_I(sbi)->v_ops = &default_v_ops;
...@@ -1007,8 +1032,12 @@ void build_gc_manager(struct f2fs_sb_info *sbi) ...@@ -1007,8 +1032,12 @@ void build_gc_manager(struct f2fs_sb_info *sbi)
main_count = SM_I(sbi)->main_segments << sbi->log_blocks_per_seg; main_count = SM_I(sbi)->main_segments << sbi->log_blocks_per_seg;
resv_count = SM_I(sbi)->reserved_segments << sbi->log_blocks_per_seg; resv_count = SM_I(sbi)->reserved_segments << sbi->log_blocks_per_seg;
ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg; ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
blocks_per_sec = sbi->blocks_per_seg * sbi->segs_per_sec;
sbi->fggc_threshold = div64_u64((main_count - ovp_count) * blocks_per_sec, sbi->fggc_threshold = div64_u64((main_count - ovp_count) *
(main_count - resv_count)); BLKS_PER_SEC(sbi), (main_count - resv_count));
/* give warm/cold data area from slower device */
if (sbi->s_ndevs && sbi->segs_per_sec == 1)
SIT_I(sbi)->last_victim[ALLOC_NEXT] =
GET_SEGNO(sbi, FDEV(0).end_blk) + 1;
} }
...@@ -63,19 +63,21 @@ void read_inline_data(struct page *page, struct page *ipage) ...@@ -63,19 +63,21 @@ void read_inline_data(struct page *page, struct page *ipage)
SetPageUptodate(page); SetPageUptodate(page);
} }
bool truncate_inline_inode(struct page *ipage, u64 from) void truncate_inline_inode(struct inode *inode, struct page *ipage, u64 from)
{ {
void *addr; void *addr;
if (from >= MAX_INLINE_DATA) if (from >= MAX_INLINE_DATA)
return false; return;
addr = inline_data_addr(ipage); addr = inline_data_addr(ipage);
f2fs_wait_on_page_writeback(ipage, NODE, true); f2fs_wait_on_page_writeback(ipage, NODE, true);
memset(addr + from, 0, MAX_INLINE_DATA - from); memset(addr + from, 0, MAX_INLINE_DATA - from);
set_page_dirty(ipage); set_page_dirty(ipage);
return true;
if (from == 0)
clear_inode_flag(inode, FI_DATA_EXIST);
} }
int f2fs_read_inline_data(struct inode *inode, struct page *page) int f2fs_read_inline_data(struct inode *inode, struct page *page)
...@@ -135,6 +137,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) ...@@ -135,6 +137,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
/* write data page to try to make data consistent */ /* write data page to try to make data consistent */
set_page_writeback(page); set_page_writeback(page);
fio.old_blkaddr = dn->data_blkaddr; fio.old_blkaddr = dn->data_blkaddr;
set_inode_flag(dn->inode, FI_HOT_DATA);
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) {
...@@ -146,11 +149,11 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) ...@@ -146,11 +149,11 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
set_inode_flag(dn->inode, FI_APPEND_WRITE); set_inode_flag(dn->inode, FI_APPEND_WRITE);
/* clear inline data and flag after data writeback */ /* clear inline data and flag after data writeback */
truncate_inline_inode(dn->inode_page, 0); truncate_inline_inode(dn->inode, dn->inode_page, 0);
clear_inline_node(dn->inode_page); clear_inline_node(dn->inode_page);
clear_out: clear_out:
stat_dec_inline_inode(dn->inode); stat_dec_inline_inode(dn->inode);
f2fs_clear_inline_inode(dn->inode); clear_inode_flag(dn->inode, FI_INLINE_DATA);
f2fs_put_dnode(dn); f2fs_put_dnode(dn);
return 0; return 0;
} }
...@@ -267,9 +270,8 @@ bool recover_inline_data(struct inode *inode, struct page *npage) ...@@ -267,9 +270,8 @@ bool recover_inline_data(struct inode *inode, struct page *npage)
if (f2fs_has_inline_data(inode)) { if (f2fs_has_inline_data(inode)) {
ipage = get_node_page(sbi, inode->i_ino); ipage = get_node_page(sbi, inode->i_ino);
f2fs_bug_on(sbi, IS_ERR(ipage)); f2fs_bug_on(sbi, IS_ERR(ipage));
if (!truncate_inline_inode(ipage, 0)) truncate_inline_inode(inode, ipage, 0);
return false; clear_inode_flag(inode, FI_INLINE_DATA);
f2fs_clear_inline_inode(inode);
f2fs_put_page(ipage, 1); f2fs_put_page(ipage, 1);
} else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) { } else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) {
if (truncate_blocks(inode, 0, false)) if (truncate_blocks(inode, 0, false))
...@@ -300,7 +302,7 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir, ...@@ -300,7 +302,7 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
inline_dentry = inline_data_addr(ipage); inline_dentry = inline_data_addr(ipage);
make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2); make_dentry_ptr_inline(NULL, &d, inline_dentry);
de = find_target_dentry(fname, namehash, NULL, &d); de = find_target_dentry(fname, namehash, NULL, &d);
unlock_page(ipage); unlock_page(ipage);
if (de) if (de)
...@@ -319,7 +321,7 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent, ...@@ -319,7 +321,7 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent,
dentry_blk = inline_data_addr(ipage); dentry_blk = inline_data_addr(ipage);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2); make_dentry_ptr_inline(NULL, &d, dentry_blk);
do_make_empty_dir(inode, parent, &d); do_make_empty_dir(inode, parent, &d);
set_page_dirty(ipage); set_page_dirty(ipage);
...@@ -380,7 +382,7 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage, ...@@ -380,7 +382,7 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
set_page_dirty(page); set_page_dirty(page);
/* clear inline dir and flag after data writeback */ /* clear inline dir and flag after data writeback */
truncate_inline_inode(ipage, 0); truncate_inline_inode(dir, ipage, 0);
stat_dec_inline_dir(dir); stat_dec_inline_dir(dir);
clear_inode_flag(dir, FI_INLINE_DENTRY); clear_inode_flag(dir, FI_INLINE_DENTRY);
...@@ -400,7 +402,7 @@ static int f2fs_add_inline_entries(struct inode *dir, ...@@ -400,7 +402,7 @@ static int f2fs_add_inline_entries(struct inode *dir,
unsigned long bit_pos = 0; unsigned long bit_pos = 0;
int err = 0; int err = 0;
make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2); make_dentry_ptr_inline(NULL, &d, inline_dentry);
while (bit_pos < d.max) { while (bit_pos < d.max) {
struct f2fs_dir_entry *de; struct f2fs_dir_entry *de;
...@@ -455,7 +457,7 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage, ...@@ -455,7 +457,7 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
} }
memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA); memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA);
truncate_inline_inode(ipage, 0); truncate_inline_inode(dir, ipage, 0);
unlock_page(ipage); unlock_page(ipage);
...@@ -527,14 +529,12 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name, ...@@ -527,14 +529,12 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
err = PTR_ERR(page); err = PTR_ERR(page);
goto fail; goto fail;
} }
if (f2fs_encrypted_inode(dir))
file_set_enc_name(inode);
} }
f2fs_wait_on_page_writeback(ipage, NODE, true); f2fs_wait_on_page_writeback(ipage, NODE, true);
name_hash = f2fs_dentry_hash(new_name, NULL); name_hash = f2fs_dentry_hash(new_name, NULL);
make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2); make_dentry_ptr_inline(NULL, &d, dentry_blk);
f2fs_update_dentry(ino, mode, &d, new_name, name_hash, bit_pos); f2fs_update_dentry(ino, mode, &d, new_name, name_hash, bit_pos);
set_page_dirty(ipage); set_page_dirty(ipage);
...@@ -623,7 +623,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx, ...@@ -623,7 +623,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
inline_dentry = inline_data_addr(ipage); inline_dentry = inline_data_addr(ipage);
make_dentry_ptr(inode, &d, (void *)inline_dentry, 2); make_dentry_ptr_inline(inode, &d, inline_dentry);
err = f2fs_fill_dentries(ctx, &d, 0, fstr); err = f2fs_fill_dentries(ctx, &d, 0, fstr);
if (!err) if (!err)
......
...@@ -316,7 +316,6 @@ int update_inode_page(struct inode *inode) ...@@ -316,7 +316,6 @@ int update_inode_page(struct inode *inode)
} else if (err != -ENOENT) { } else if (err != -ENOENT) {
f2fs_stop_checkpoint(sbi, false); f2fs_stop_checkpoint(sbi, false);
} }
f2fs_inode_synced(inode);
return 0; return 0;
} }
ret = update_inode(inode, node_page); ret = update_inode(inode, node_page);
...@@ -339,7 +338,8 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -339,7 +338,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.
*/ */
if (update_inode_page(inode) && wbc && wbc->nr_to_write) update_inode_page(inode);
if (wbc && wbc->nr_to_write)
f2fs_balance_fs(sbi, true); f2fs_balance_fs(sbi, true);
return 0; return 0;
} }
...@@ -372,13 +372,6 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -372,13 +372,6 @@ void f2fs_evict_inode(struct inode *inode)
if (inode->i_nlink || is_bad_inode(inode)) if (inode->i_nlink || is_bad_inode(inode))
goto no_delete; goto no_delete;
#ifdef CONFIG_F2FS_FAULT_INJECTION
if (time_to_inject(sbi, FAULT_EVICT_INODE)) {
f2fs_show_injection_info(FAULT_EVICT_INODE);
goto no_delete;
}
#endif
remove_ino_entry(sbi, inode->i_ino, APPEND_INO); remove_ino_entry(sbi, inode->i_ino, APPEND_INO);
remove_ino_entry(sbi, inode->i_ino, UPDATE_INO); remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
...@@ -389,6 +382,12 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -389,6 +382,12 @@ void f2fs_evict_inode(struct inode *inode)
if (F2FS_HAS_BLOCKS(inode)) if (F2FS_HAS_BLOCKS(inode))
err = f2fs_truncate(inode); err = f2fs_truncate(inode);
#ifdef CONFIG_F2FS_FAULT_INJECTION
if (time_to_inject(sbi, FAULT_EVICT_INODE)) {
f2fs_show_injection_info(FAULT_EVICT_INODE);
err = -EIO;
}
#endif
if (!err) { if (!err) {
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = remove_inode_page(inode); err = remove_inode_page(inode);
...@@ -411,7 +410,10 @@ void f2fs_evict_inode(struct inode *inode) ...@@ -411,7 +410,10 @@ void f2fs_evict_inode(struct inode *inode)
stat_dec_inline_dir(inode); stat_dec_inline_dir(inode);
stat_dec_inline_inode(inode); stat_dec_inline_inode(inode);
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino); /* ino == 0, if f2fs_new_inode() was failed t*/
if (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 (inode->i_nlink) { if (inode->i_nlink) {
...@@ -448,6 +450,7 @@ void handle_failed_inode(struct inode *inode) ...@@ -448,6 +450,7 @@ void handle_failed_inode(struct inode *inode)
* in a panic when flushing dirty inodes in gdirty_list. * in a panic when flushing dirty inodes in gdirty_list.
*/ */
update_inode_page(inode); update_inode_page(inode);
f2fs_inode_synced(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);
......
...@@ -148,8 +148,6 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -148,8 +148,6 @@ 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)
...@@ -163,6 +161,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -163,6 +161,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1); f2fs_sync_fs(sbi->sb, 1);
f2fs_balance_fs(sbi, true);
return 0; return 0;
out: out:
handle_failed_inode(inode); handle_failed_inode(inode);
...@@ -424,8 +424,6 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -424,8 +424,6 @@ 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)
...@@ -488,6 +486,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -488,6 +486,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
} }
kfree(sd); kfree(sd);
f2fs_balance_fs(sbi, true);
return err; return err;
out: out:
handle_failed_inode(inode); handle_failed_inode(inode);
...@@ -509,8 +509,6 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -509,8 +509,6 @@ 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(inode, FI_INC_LINK); set_inode_flag(inode, FI_INC_LINK);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode); err = f2fs_add_link(dentry, inode);
...@@ -525,6 +523,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -525,6 +523,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1); f2fs_sync_fs(sbi->sb, 1);
f2fs_balance_fs(sbi, true);
return 0; return 0;
out_fail: out_fail:
...@@ -555,8 +555,6 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -555,8 +555,6 @@ 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)
...@@ -570,6 +568,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -570,6 +568,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1); f2fs_sync_fs(sbi->sb, 1);
f2fs_balance_fs(sbi, true);
return 0; return 0;
out: out:
handle_failed_inode(inode); handle_failed_inode(inode);
...@@ -596,8 +596,6 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -596,8 +596,6 @@ 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)
...@@ -623,6 +621,8 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -623,6 +621,8 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
/* link_count was changed by d_tmpfile as well. */ /* link_count was changed by d_tmpfile as well. */
f2fs_unlock_op(sbi); f2fs_unlock_op(sbi);
unlock_new_inode(inode); unlock_new_inode(inode);
f2fs_balance_fs(sbi, true);
return 0; return 0;
release_out: release_out:
...@@ -721,13 +721,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -721,13 +721,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (err) if (err)
goto put_out_dir; goto put_out_dir;
err = update_dent_inode(old_inode, new_inode,
&new_dentry->d_name);
if (err) {
release_orphan_inode(sbi);
goto put_out_dir;
}
f2fs_set_link(new_dir, new_entry, new_page, old_inode); f2fs_set_link(new_dir, new_entry, new_page, old_inode);
new_inode->i_ctime = current_time(new_inode); new_inode->i_ctime = current_time(new_inode);
...@@ -780,8 +773,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -780,8 +773,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
down_write(&F2FS_I(old_inode)->i_sem); down_write(&F2FS_I(old_inode)->i_sem);
file_lost_pino(old_inode); file_lost_pino(old_inode);
if (new_inode && file_enc_name(new_inode))
file_set_enc_name(old_inode);
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);
...@@ -909,8 +900,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -909,8 +900,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
old_nlink = old_dir_entry ? -1 : 1; old_nlink = old_dir_entry ? -1 : 1;
new_nlink = -old_nlink; new_nlink = -old_nlink;
err = -EMLINK; err = -EMLINK;
if ((old_nlink > 0 && old_inode->i_nlink >= F2FS_LINK_MAX) || if ((old_nlink > 0 && old_dir->i_nlink >= F2FS_LINK_MAX) ||
(new_nlink > 0 && new_inode->i_nlink >= F2FS_LINK_MAX)) (new_nlink > 0 && new_dir->i_nlink >= F2FS_LINK_MAX))
goto out_new_dir; goto out_new_dir;
} }
...@@ -918,18 +909,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -918,18 +909,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
err = update_dent_inode(old_inode, new_inode, &new_dentry->d_name);
if (err)
goto out_unlock;
if (file_enc_name(new_inode))
file_set_enc_name(old_inode);
err = update_dent_inode(new_inode, old_inode, &old_dentry->d_name);
if (err)
goto out_undo;
if (file_enc_name(old_inode))
file_set_enc_name(new_inode);
/* update ".." directory entry info of old dentry */ /* update ".." directory entry info of old dentry */
if (old_dir_entry) if (old_dir_entry)
f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir);
...@@ -973,14 +952,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -973,14 +952,6 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
f2fs_sync_fs(sbi->sb, 1); f2fs_sync_fs(sbi->sb, 1);
return 0; return 0;
out_undo:
/*
* Still we may fail to recover name info of f2fs_inode here
* Drop it, once its name is set as encrypted
*/
update_dent_inode(old_inode, old_inode, &old_dentry->d_name);
out_unlock:
f2fs_unlock_op(sbi);
out_new_dir: out_new_dir:
if (new_dir_entry) { if (new_dir_entry) {
f2fs_dentry_kunmap(new_inode, new_dir_page); f2fs_dentry_kunmap(new_inode, new_dir_page);
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "trace.h" #include "trace.h"
#include <trace/events/f2fs.h> #include <trace/events/f2fs.h>
#define on_build_free_nids(nmi) mutex_is_locked(&nm_i->build_lock) #define on_build_free_nids(nmi) mutex_is_locked(&(nm_i)->build_lock)
static struct kmem_cache *nat_entry_slab; static struct kmem_cache *nat_entry_slab;
static struct kmem_cache *free_nid_slab; static struct kmem_cache *free_nid_slab;
...@@ -63,8 +63,9 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type) ...@@ -63,8 +63,9 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
int i; int i;
for (i = 0; i <= UPDATE_INO; i++) for (i = 0; i <= UPDATE_INO; i++)
mem_size += (sbi->im[i].ino_num * mem_size += sbi->im[i].ino_num *
sizeof(struct ino_entry)) >> PAGE_SHIFT; sizeof(struct ino_entry);
mem_size >>= PAGE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1); res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
} else if (type == EXTENT_CACHE) { } else if (type == EXTENT_CACHE) {
mem_size = (atomic_read(&sbi->total_ext_tree) * mem_size = (atomic_read(&sbi->total_ext_tree) *
...@@ -177,18 +178,12 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, ...@@ -177,18 +178,12 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
} }
static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i, static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i,
struct nat_entry *ne) struct nat_entry_set *set, struct nat_entry *ne)
{ {
nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);
struct nat_entry_set *head;
head = radix_tree_lookup(&nm_i->nat_set_root, set);
if (head) {
list_move_tail(&ne->list, &nm_i->nat_entries); list_move_tail(&ne->list, &nm_i->nat_entries);
set_nat_flag(ne, IS_DIRTY, false); set_nat_flag(ne, IS_DIRTY, false);
head->entry_cnt--; set->entry_cnt--;
nm_i->dirty_nat_cnt--; nm_i->dirty_nat_cnt--;
}
} }
static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i, static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i,
...@@ -381,6 +376,7 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) ...@@ -381,6 +376,7 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
struct page *page = NULL; struct page *page = NULL;
struct f2fs_nat_entry ne; struct f2fs_nat_entry ne;
struct nat_entry *e; struct nat_entry *e;
pgoff_t index;
int i; int i;
ni->nid = nid; ni->nid = nid;
...@@ -406,17 +402,21 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) ...@@ -406,17 +402,21 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
node_info_from_raw_nat(ni, &ne); node_info_from_raw_nat(ni, &ne);
} }
up_read(&curseg->journal_rwsem); up_read(&curseg->journal_rwsem);
if (i >= 0) if (i >= 0) {
up_read(&nm_i->nat_tree_lock);
goto cache; goto cache;
}
/* Fill node_info from nat page */ /* Fill node_info from nat page */
page = get_current_nat_page(sbi, start_nid); index = current_nat_addr(sbi, nid);
up_read(&nm_i->nat_tree_lock);
page = get_meta_page(sbi, index);
nat_blk = (struct f2fs_nat_block *)page_address(page); nat_blk = (struct f2fs_nat_block *)page_address(page);
ne = nat_blk->entries[nid - start_nid]; ne = nat_blk->entries[nid - start_nid];
node_info_from_raw_nat(ni, &ne); node_info_from_raw_nat(ni, &ne);
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
cache: cache:
up_read(&nm_i->nat_tree_lock);
/* cache nat entry */ /* cache nat entry */
down_write(&nm_i->nat_tree_lock); down_write(&nm_i->nat_tree_lock);
cache_nat_entry(sbi, nid, &ne); cache_nat_entry(sbi, nid, &ne);
...@@ -1463,6 +1463,9 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -1463,6 +1463,9 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
f2fs_wait_on_page_writeback(page, NODE, true); f2fs_wait_on_page_writeback(page, NODE, true);
BUG_ON(PageWriteback(page)); BUG_ON(PageWriteback(page));
set_fsync_mark(page, 0);
set_dentry_mark(page, 0);
if (!atomic || page == last_page) { if (!atomic || page == last_page) {
set_fsync_mark(page, 1); set_fsync_mark(page, 1);
if (IS_INODE(page)) { if (IS_INODE(page)) {
...@@ -1766,40 +1769,67 @@ static void __remove_nid_from_list(struct f2fs_sb_info *sbi, ...@@ -1766,40 +1769,67 @@ static void __remove_nid_from_list(struct f2fs_sb_info *sbi,
static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
{ {
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
struct free_nid *i; struct free_nid *i, *e;
struct nat_entry *ne; struct nat_entry *ne;
int err; int err = -EINVAL;
bool ret = false;
/* 0 nid should not be used */ /* 0 nid should not be used */
if (unlikely(nid == 0)) if (unlikely(nid == 0))
return false; return false;
if (build) {
/* do not add allocated nids */
ne = __lookup_nat_cache(nm_i, nid);
if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
nat_get_blkaddr(ne) != NULL_ADDR))
return false;
}
i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS); i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
i->nid = nid; i->nid = nid;
i->state = NID_NEW; i->state = NID_NEW;
if (radix_tree_preload(GFP_NOFS)) { if (radix_tree_preload(GFP_NOFS))
kmem_cache_free(free_nid_slab, i); goto err;
return true;
}
spin_lock(&nm_i->nid_list_lock); spin_lock(&nm_i->nid_list_lock);
if (build) {
/*
* Thread A Thread B
* - f2fs_create
* - f2fs_new_inode
* - alloc_nid
* - __insert_nid_to_list(ALLOC_NID_LIST)
* - f2fs_balance_fs_bg
* - build_free_nids
* - __build_free_nids
* - scan_nat_page
* - add_free_nid
* - __lookup_nat_cache
* - f2fs_add_link
* - init_inode_metadata
* - new_inode_page
* - new_node_page
* - set_node_addr
* - alloc_nid_done
* - __remove_nid_from_list(ALLOC_NID_LIST)
* - __insert_nid_to_list(FREE_NID_LIST)
*/
ne = __lookup_nat_cache(nm_i, nid);
if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
nat_get_blkaddr(ne) != NULL_ADDR))
goto err_out;
e = __lookup_free_nid_list(nm_i, nid);
if (e) {
if (e->state == NID_NEW)
ret = true;
goto err_out;
}
}
ret = true;
err = __insert_nid_to_list(sbi, i, FREE_NID_LIST, true); err = __insert_nid_to_list(sbi, i, FREE_NID_LIST, true);
err_out:
spin_unlock(&nm_i->nid_list_lock); spin_unlock(&nm_i->nid_list_lock);
radix_tree_preload_end(); radix_tree_preload_end();
if (err) { err:
if (err)
kmem_cache_free(free_nid_slab, i); kmem_cache_free(free_nid_slab, i);
return true; return ret;
}
return true;
} }
static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid) static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid)
...@@ -1821,7 +1851,7 @@ static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -1821,7 +1851,7 @@ static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid)
} }
static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid,
bool set, bool build, bool locked) bool set, bool build)
{ {
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid); unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid);
...@@ -1835,14 +1865,10 @@ static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, ...@@ -1835,14 +1865,10 @@ static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid,
else else
__clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]); __clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
if (!locked)
spin_lock(&nm_i->free_nid_lock);
if (set) if (set)
nm_i->free_nid_count[nat_ofs]++; nm_i->free_nid_count[nat_ofs]++;
else if (!build) else if (!build)
nm_i->free_nid_count[nat_ofs]--; nm_i->free_nid_count[nat_ofs]--;
if (!locked)
spin_unlock(&nm_i->free_nid_lock);
} }
static void scan_nat_page(struct f2fs_sb_info *sbi, static void scan_nat_page(struct f2fs_sb_info *sbi,
...@@ -1871,7 +1897,9 @@ static void scan_nat_page(struct f2fs_sb_info *sbi, ...@@ -1871,7 +1897,9 @@ static void scan_nat_page(struct f2fs_sb_info *sbi,
f2fs_bug_on(sbi, blk_addr == NEW_ADDR); f2fs_bug_on(sbi, blk_addr == NEW_ADDR);
if (blk_addr == NULL_ADDR) if (blk_addr == NULL_ADDR)
freed = add_free_nid(sbi, start_nid, true); freed = add_free_nid(sbi, start_nid, true);
update_free_nid_bitmap(sbi, start_nid, freed, true, false); spin_lock(&NM_I(sbi)->nid_list_lock);
update_free_nid_bitmap(sbi, start_nid, freed, true);
spin_unlock(&NM_I(sbi)->nid_list_lock);
} }
} }
...@@ -1927,6 +1955,9 @@ static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount) ...@@ -1927,6 +1955,9 @@ static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
int i = 0; int i = 0;
nid_t nid = nm_i->next_scan_nid; nid_t nid = nm_i->next_scan_nid;
if (unlikely(nid >= nm_i->max_nid))
nid = 0;
/* Enough entries */ /* Enough entries */
if (nm_i->nid_cnt[FREE_NID_LIST] >= NAT_ENTRY_PER_BLOCK) if (nm_i->nid_cnt[FREE_NID_LIST] >= NAT_ENTRY_PER_BLOCK)
return; return;
...@@ -2026,7 +2057,7 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) ...@@ -2026,7 +2057,7 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
__insert_nid_to_list(sbi, i, ALLOC_NID_LIST, false); __insert_nid_to_list(sbi, i, ALLOC_NID_LIST, false);
nm_i->available_nids--; nm_i->available_nids--;
update_free_nid_bitmap(sbi, *nid, false, false, false); update_free_nid_bitmap(sbi, *nid, false, false);
spin_unlock(&nm_i->nid_list_lock); spin_unlock(&nm_i->nid_list_lock);
return true; return true;
...@@ -2082,7 +2113,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -2082,7 +2113,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
nm_i->available_nids++; nm_i->available_nids++;
update_free_nid_bitmap(sbi, nid, true, false, false); update_free_nid_bitmap(sbi, nid, true, false);
spin_unlock(&nm_i->nid_list_lock); spin_unlock(&nm_i->nid_list_lock);
...@@ -2407,16 +2438,16 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, ...@@ -2407,16 +2438,16 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
} }
raw_nat_from_node_info(raw_ne, &ne->ni); raw_nat_from_node_info(raw_ne, &ne->ni);
nat_reset_flag(ne); nat_reset_flag(ne);
__clear_nat_cache_dirty(NM_I(sbi), ne); __clear_nat_cache_dirty(NM_I(sbi), set, ne);
if (nat_get_blkaddr(ne) == NULL_ADDR) { if (nat_get_blkaddr(ne) == NULL_ADDR) {
add_free_nid(sbi, nid, false); add_free_nid(sbi, nid, false);
spin_lock(&NM_I(sbi)->nid_list_lock); spin_lock(&NM_I(sbi)->nid_list_lock);
NM_I(sbi)->available_nids++; NM_I(sbi)->available_nids++;
update_free_nid_bitmap(sbi, nid, true, false, false); update_free_nid_bitmap(sbi, nid, true, false);
spin_unlock(&NM_I(sbi)->nid_list_lock); spin_unlock(&NM_I(sbi)->nid_list_lock);
} else { } else {
spin_lock(&NM_I(sbi)->nid_list_lock); spin_lock(&NM_I(sbi)->nid_list_lock);
update_free_nid_bitmap(sbi, nid, false, false, false); update_free_nid_bitmap(sbi, nid, false, false);
spin_unlock(&NM_I(sbi)->nid_list_lock); spin_unlock(&NM_I(sbi)->nid_list_lock);
} }
} }
...@@ -2428,10 +2459,11 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, ...@@ -2428,10 +2459,11 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
} }
f2fs_bug_on(sbi, set->entry_cnt); /* Allow dirty nats by node block allocation in write_begin */
if (!set->entry_cnt) {
radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set); radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
kmem_cache_free(nat_entry_set_slab, set); kmem_cache_free(nat_entry_set_slab, set);
}
} }
/* /*
...@@ -2476,8 +2508,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -2476,8 +2508,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
__flush_nat_entry_set(sbi, set, cpc); __flush_nat_entry_set(sbi, set, cpc);
up_write(&nm_i->nat_tree_lock); up_write(&nm_i->nat_tree_lock);
/* Allow dirty nats by node block allocation in write_begin */
f2fs_bug_on(sbi, nm_i->dirty_nat_cnt);
} }
static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
...@@ -2541,10 +2572,10 @@ inline void load_free_nid_bitmap(struct f2fs_sb_info *sbi) ...@@ -2541,10 +2572,10 @@ inline void load_free_nid_bitmap(struct f2fs_sb_info *sbi)
nid = i * NAT_ENTRY_PER_BLOCK; nid = i * NAT_ENTRY_PER_BLOCK;
last_nid = (i + 1) * NAT_ENTRY_PER_BLOCK; last_nid = (i + 1) * NAT_ENTRY_PER_BLOCK;
spin_lock(&nm_i->free_nid_lock); spin_lock(&NM_I(sbi)->nid_list_lock);
for (; nid < last_nid; nid++) for (; nid < last_nid; nid++)
update_free_nid_bitmap(sbi, nid, true, true, true); update_free_nid_bitmap(sbi, nid, true, true);
spin_unlock(&nm_i->free_nid_lock); spin_unlock(&NM_I(sbi)->nid_list_lock);
} }
for (i = 0; i < nm_i->nat_blocks; i++) { for (i = 0; i < nm_i->nat_blocks; i++) {
...@@ -2635,9 +2666,6 @@ static int init_free_nid_cache(struct f2fs_sb_info *sbi) ...@@ -2635,9 +2666,6 @@ static int init_free_nid_cache(struct f2fs_sb_info *sbi)
sizeof(unsigned short), GFP_KERNEL); sizeof(unsigned short), GFP_KERNEL);
if (!nm_i->free_nid_count) if (!nm_i->free_nid_count)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&nm_i->free_nid_lock);
return 0; return 0;
} }
......
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
/* start node id of a node block dedicated to the given node id */ /* start node id of a node block dedicated to the given node id */
#define START_NID(nid) ((nid / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK) #define START_NID(nid) (((nid) / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK)
/* node block offset on the NAT area dedicated to the given start node id */ /* node block offset on the NAT area dedicated to the given start node id */
#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) #define NAT_BLOCK_OFFSET(start_nid) ((start_nid) / NAT_ENTRY_PER_BLOCK)
/* # of pages to perform synchronous readahead before building free nids */ /* # of pages to perform synchronous readahead before building free nids */
#define FREE_NID_PAGES 8 #define FREE_NID_PAGES 8
...@@ -62,16 +62,16 @@ struct nat_entry { ...@@ -62,16 +62,16 @@ struct nat_entry {
struct node_info ni; /* in-memory node information */ struct node_info ni; /* in-memory node information */
}; };
#define nat_get_nid(nat) (nat->ni.nid) #define nat_get_nid(nat) ((nat)->ni.nid)
#define nat_set_nid(nat, n) (nat->ni.nid = n) #define nat_set_nid(nat, n) ((nat)->ni.nid = (n))
#define nat_get_blkaddr(nat) (nat->ni.blk_addr) #define nat_get_blkaddr(nat) ((nat)->ni.blk_addr)
#define nat_set_blkaddr(nat, b) (nat->ni.blk_addr = b) #define nat_set_blkaddr(nat, b) ((nat)->ni.blk_addr = (b))
#define nat_get_ino(nat) (nat->ni.ino) #define nat_get_ino(nat) ((nat)->ni.ino)
#define nat_set_ino(nat, i) (nat->ni.ino = i) #define nat_set_ino(nat, i) ((nat)->ni.ino = (i))
#define nat_get_version(nat) (nat->ni.version) #define nat_get_version(nat) ((nat)->ni.version)
#define nat_set_version(nat, v) (nat->ni.version = v) #define nat_set_version(nat, v) ((nat)->ni.version = (v))
#define inc_node_version(version) (++version) #define inc_node_version(version) (++(version))
static inline void copy_node_info(struct node_info *dst, static inline void copy_node_info(struct node_info *dst,
struct node_info *src) struct node_info *src)
...@@ -200,13 +200,16 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start) ...@@ -200,13 +200,16 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start)
struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi);
pgoff_t block_off; pgoff_t block_off;
pgoff_t block_addr; pgoff_t block_addr;
int seg_off;
/*
* block_off = segment_off * 512 + off_in_segment
* OLD = (segment_off * 512) * 2 + off_in_segment
* NEW = 2 * (segment_off * 512 + off_in_segment) - off_in_segment
*/
block_off = NAT_BLOCK_OFFSET(start); block_off = NAT_BLOCK_OFFSET(start);
seg_off = block_off >> sbi->log_blocks_per_seg;
block_addr = (pgoff_t)(nm_i->nat_blkaddr + block_addr = (pgoff_t)(nm_i->nat_blkaddr +
(seg_off << sbi->log_blocks_per_seg << 1) + (block_off << 1) -
(block_off & (sbi->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))
......
...@@ -198,7 +198,8 @@ static void recover_inode(struct inode *inode, struct page *page) ...@@ -198,7 +198,8 @@ static void recover_inode(struct inode *inode, struct page *page)
ino_of_node(page), name); ino_of_node(page), name);
} }
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,
bool check_only)
{ {
struct curseg_info *curseg; struct curseg_info *curseg;
struct page *page = NULL; struct page *page = NULL;
...@@ -225,7 +226,8 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) ...@@ -225,7 +226,8 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
entry = get_fsync_inode(head, ino_of_node(page)); entry = get_fsync_inode(head, ino_of_node(page));
if (!entry) { if (!entry) {
if (IS_INODE(page) && is_dent_dnode(page)) { if (!check_only &&
IS_INODE(page) && is_dent_dnode(page)) {
err = recover_inode_page(sbi, page); err = recover_inode_page(sbi, page);
if (err) if (err)
break; break;
...@@ -569,7 +571,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only) ...@@ -569,7 +571,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
mutex_lock(&sbi->cp_mutex); mutex_lock(&sbi->cp_mutex);
/* step #1: find fsynced inode numbers */ /* step #1: find fsynced inode numbers */
err = find_fsync_dnodes(sbi, &inode_list); err = find_fsync_dnodes(sbi, &inode_list, check_only);
if (err || list_empty(&inode_list)) if (err || list_empty(&inode_list))
goto out; goto out;
......
This diff is collapsed.
This diff is collapsed.
...@@ -49,6 +49,7 @@ char *fault_name[FAULT_MAX] = { ...@@ -49,6 +49,7 @@ char *fault_name[FAULT_MAX] = {
[FAULT_BLOCK] = "no more block", [FAULT_BLOCK] = "no more block",
[FAULT_DIR_DEPTH] = "too big dir depth", [FAULT_DIR_DEPTH] = "too big dir depth",
[FAULT_EVICT_INODE] = "evict_inode fail", [FAULT_EVICT_INODE] = "evict_inode fail",
[FAULT_TRUNCATE] = "truncate fail",
[FAULT_IO] = "IO error", [FAULT_IO] = "IO error",
[FAULT_CHECKPOINT] = "checkpoint error", [FAULT_CHECKPOINT] = "checkpoint error",
}; };
...@@ -82,6 +83,7 @@ enum { ...@@ -82,6 +83,7 @@ enum {
Opt_discard, Opt_discard,
Opt_nodiscard, Opt_nodiscard,
Opt_noheap, Opt_noheap,
Opt_heap,
Opt_user_xattr, Opt_user_xattr,
Opt_nouser_xattr, Opt_nouser_xattr,
Opt_acl, Opt_acl,
...@@ -116,6 +118,7 @@ static match_table_t f2fs_tokens = { ...@@ -116,6 +118,7 @@ static match_table_t f2fs_tokens = {
{Opt_discard, "discard"}, {Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"}, {Opt_nodiscard, "nodiscard"},
{Opt_noheap, "no_heap"}, {Opt_noheap, "no_heap"},
{Opt_heap, "heap"},
{Opt_user_xattr, "user_xattr"}, {Opt_user_xattr, "user_xattr"},
{Opt_nouser_xattr, "nouser_xattr"}, {Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"}, {Opt_acl, "acl"},
...@@ -293,6 +296,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); ...@@ -293,6 +296,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_hot_blocks, min_hot_blocks);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio); F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
...@@ -318,6 +322,7 @@ static struct attribute *f2fs_attrs[] = { ...@@ -318,6 +322,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(ipu_policy), ATTR_LIST(ipu_policy),
ATTR_LIST(min_ipu_util), ATTR_LIST(min_ipu_util),
ATTR_LIST(min_fsync_blocks), ATTR_LIST(min_fsync_blocks),
ATTR_LIST(min_hot_blocks),
ATTR_LIST(max_victim_search), ATTR_LIST(max_victim_search),
ATTR_LIST(dir_level), ATTR_LIST(dir_level),
ATTR_LIST(ram_thresh), ATTR_LIST(ram_thresh),
...@@ -436,6 +441,9 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -436,6 +441,9 @@ static int parse_options(struct super_block *sb, char *options)
case Opt_noheap: case Opt_noheap:
set_opt(sbi, NOHEAP); set_opt(sbi, NOHEAP);
break; break;
case Opt_heap:
clear_opt(sbi, NOHEAP);
break;
#ifdef CONFIG_F2FS_FS_XATTR #ifdef CONFIG_F2FS_FS_XATTR
case Opt_user_xattr: case Opt_user_xattr:
set_opt(sbi, XATTR_USER); set_opt(sbi, XATTR_USER);
...@@ -787,7 +795,14 @@ static void f2fs_put_super(struct super_block *sb) ...@@ -787,7 +795,14 @@ static void f2fs_put_super(struct super_block *sb)
} }
/* be sure to wait for any on-going discard commands */ /* be sure to wait for any on-going discard commands */
f2fs_wait_discard_bio(sbi, NULL_ADDR); f2fs_wait_discard_bios(sbi);
if (!sbi->discard_blks) {
struct cp_control cpc = {
.reason = CP_UMOUNT | CP_TRIMMED,
};
write_checkpoint(sbi, &cpc);
}
/* write_checkpoint can update stat informaion */ /* write_checkpoint can update stat informaion */
f2fs_destroy_stats(sbi); f2fs_destroy_stats(sbi);
...@@ -913,7 +928,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -913,7 +928,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
if (test_opt(sbi, DISCARD)) if (test_opt(sbi, DISCARD))
seq_puts(seq, ",discard"); seq_puts(seq, ",discard");
if (test_opt(sbi, NOHEAP)) if (test_opt(sbi, NOHEAP))
seq_puts(seq, ",no_heap_alloc"); seq_puts(seq, ",no_heap");
else
seq_puts(seq, ",heap");
#ifdef CONFIG_F2FS_FS_XATTR #ifdef CONFIG_F2FS_FS_XATTR
if (test_opt(sbi, XATTR_USER)) if (test_opt(sbi, XATTR_USER))
seq_puts(seq, ",user_xattr"); seq_puts(seq, ",user_xattr");
...@@ -986,7 +1003,7 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset) ...@@ -986,7 +1003,7 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset)
if ((i % 10) == 0) if ((i % 10) == 0)
seq_printf(seq, "%-10d", i); seq_printf(seq, "%-10d", i);
seq_printf(seq, "%d|%-3u", se->type, seq_printf(seq, "%d|%-3u", se->type,
get_valid_blocks(sbi, i, 1)); get_valid_blocks(sbi, i, false));
if ((i % 10) == 9 || i == (total_segs - 1)) if ((i % 10) == 9 || i == (total_segs - 1))
seq_putc(seq, '\n'); seq_putc(seq, '\n');
else else
...@@ -1012,7 +1029,7 @@ static int segment_bits_seq_show(struct seq_file *seq, void *offset) ...@@ -1012,7 +1029,7 @@ static int segment_bits_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "%-10d", i); seq_printf(seq, "%-10d", i);
seq_printf(seq, "%d|%-3u|", se->type, seq_printf(seq, "%d|%-3u|", se->type,
get_valid_blocks(sbi, i, 1)); get_valid_blocks(sbi, i, false));
for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++)
seq_printf(seq, " %.2x", se->cur_valid_map[j]); seq_printf(seq, " %.2x", se->cur_valid_map[j]);
seq_putc(seq, '\n'); seq_putc(seq, '\n');
...@@ -1046,6 +1063,7 @@ static void default_options(struct f2fs_sb_info *sbi) ...@@ -1046,6 +1063,7 @@ static void default_options(struct f2fs_sb_info *sbi)
set_opt(sbi, INLINE_DATA); set_opt(sbi, INLINE_DATA);
set_opt(sbi, INLINE_DENTRY); set_opt(sbi, INLINE_DENTRY);
set_opt(sbi, EXTENT_CACHE); set_opt(sbi, EXTENT_CACHE);
set_opt(sbi, NOHEAP);
sbi->sb->s_flags |= MS_LAZYTIME; sbi->sb->s_flags |= MS_LAZYTIME;
set_opt(sbi, FLUSH_MERGE); set_opt(sbi, FLUSH_MERGE);
if (f2fs_sb_mounted_blkzoned(sbi->sb)) { if (f2fs_sb_mounted_blkzoned(sbi->sb)) {
...@@ -1307,7 +1325,7 @@ static int __f2fs_commit_super(struct buffer_head *bh, ...@@ -1307,7 +1325,7 @@ static int __f2fs_commit_super(struct buffer_head *bh,
unlock_buffer(bh); unlock_buffer(bh);
/* it's rare case, we can do fua all the time */ /* it's rare case, we can do fua all the time */
return __sync_dirty_buffer(bh, REQ_PREFLUSH | REQ_FUA); return __sync_dirty_buffer(bh, REQ_SYNC | REQ_PREFLUSH | REQ_FUA);
} }
static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi, static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
...@@ -1483,6 +1501,13 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, ...@@ -1483,6 +1501,13 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
return 1; return 1;
} }
if (le32_to_cpu(raw_super->segment_count) > F2FS_MAX_SEGMENT) {
f2fs_msg(sb, KERN_INFO,
"Invalid segment count (%u)",
le32_to_cpu(raw_super->segment_count));
return 1;
}
/* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
if (sanity_check_area_boundary(sbi, bh)) if (sanity_check_area_boundary(sbi, bh))
return 1; return 1;
...@@ -1555,6 +1580,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi) ...@@ -1555,6 +1580,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
for (i = 0; i < NR_COUNT_TYPE; i++) for (i = 0; i < NR_COUNT_TYPE; i++)
atomic_set(&sbi->nr_pages[i], 0); atomic_set(&sbi->nr_pages[i], 0);
atomic_set(&sbi->wb_sync_req, 0);
INIT_LIST_HEAD(&sbi->s_list); INIT_LIST_HEAD(&sbi->s_list);
mutex_init(&sbi->umount_mutex); mutex_init(&sbi->umount_mutex);
mutex_init(&sbi->wio_mutex[NODE]); mutex_init(&sbi->wio_mutex[NODE]);
...@@ -1917,6 +1944,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1917,6 +1944,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
mutex_init(&sbi->gc_mutex); mutex_init(&sbi->gc_mutex);
mutex_init(&sbi->cp_mutex); mutex_init(&sbi->cp_mutex);
init_rwsem(&sbi->node_write); init_rwsem(&sbi->node_write);
init_rwsem(&sbi->node_change);
/* disallow all the data/node/meta page writes */ /* disallow all the data/node/meta page writes */
set_sbi_flag(sbi, SBI_POR_DOING); set_sbi_flag(sbi, SBI_POR_DOING);
...@@ -2022,6 +2050,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2022,6 +2050,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
f2fs_join_shrinker(sbi); f2fs_join_shrinker(sbi);
err = f2fs_build_stats(sbi);
if (err)
goto free_nm;
/* if there are nt orphan nodes free them */ /* if there are nt orphan nodes free them */
err = recover_orphan_inodes(sbi); err = recover_orphan_inodes(sbi);
if (err) if (err)
...@@ -2046,10 +2078,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2046,10 +2078,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
goto free_root_inode; goto free_root_inode;
} }
err = f2fs_build_stats(sbi);
if (err)
goto free_root_inode;
if (f2fs_proc_root) if (f2fs_proc_root)
sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
...@@ -2143,7 +2171,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2143,7 +2171,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
remove_proc_entry("segment_bits", sbi->s_proc); remove_proc_entry("segment_bits", sbi->s_proc);
remove_proc_entry(sb->s_id, f2fs_proc_root); remove_proc_entry(sb->s_id, f2fs_proc_root);
} }
f2fs_destroy_stats(sbi);
free_root_inode: free_root_inode:
dput(sb->s_root); dput(sb->s_root);
sb->s_root = NULL; sb->s_root = NULL;
...@@ -2161,6 +2188,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2161,6 +2188,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
truncate_inode_pages_final(META_MAPPING(sbi)); truncate_inode_pages_final(META_MAPPING(sbi));
iput(sbi->node_inode); iput(sbi->node_inode);
mutex_unlock(&sbi->umount_mutex); mutex_unlock(&sbi->umount_mutex);
f2fs_destroy_stats(sbi);
free_nm: free_nm:
destroy_node_manager(sbi); destroy_node_manager(sbi);
free_sm: free_sm:
......
...@@ -59,7 +59,7 @@ void f2fs_trace_pid(struct page *page) ...@@ -59,7 +59,7 @@ void f2fs_trace_pid(struct page *page)
pid_t pid = task_pid_nr(current); pid_t pid = task_pid_nr(current);
void *p; void *p;
page->private = pid; set_page_private(page, (unsigned long)pid);
if (radix_tree_preload(GFP_NOFS)) if (radix_tree_preload(GFP_NOFS))
return; return;
...@@ -138,7 +138,7 @@ static unsigned int gang_lookup_pids(pid_t *results, unsigned long first_index, ...@@ -138,7 +138,7 @@ static unsigned int gang_lookup_pids(pid_t *results, unsigned long first_index,
radix_tree_for_each_slot(slot, &pids, &iter, first_index) { radix_tree_for_each_slot(slot, &pids, &iter, first_index) {
results[ret] = iter.index; results[ret] = iter.index;
if (++ret == PIDVEC_SIZE) if (++ret == max_items)
break; break;
} }
return ret; return ret;
......
...@@ -250,15 +250,13 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage, ...@@ -250,15 +250,13 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
void *cur_addr, *txattr_addr, *last_addr = NULL; void *cur_addr, *txattr_addr, *last_addr = NULL;
nid_t xnid = F2FS_I(inode)->i_xattr_nid; nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0; unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
unsigned int inline_size = 0; unsigned int inline_size = inline_xattr_size(inode);
int err = 0; int err = 0;
inline_size = inline_xattr_size(inode);
if (!size && !inline_size) if (!size && !inline_size)
return -ENODATA; return -ENODATA;
txattr_addr = kzalloc(inline_size + size + sizeof(__u32), txattr_addr = kzalloc(inline_size + size + XATTR_PADDING_SIZE,
GFP_F2FS_ZERO); GFP_F2FS_ZERO);
if (!txattr_addr) if (!txattr_addr)
return -ENOMEM; return -ENOMEM;
...@@ -328,13 +326,14 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage, ...@@ -328,13 +326,14 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage,
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_xattr_header *header; struct f2fs_xattr_header *header;
size_t size = PAGE_SIZE, inline_size = 0; nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = VALID_XATTR_BLOCK_SIZE;
unsigned int inline_size = inline_xattr_size(inode);
void *txattr_addr; void *txattr_addr;
int err; int err;
inline_size = inline_xattr_size(inode); txattr_addr = kzalloc(inline_size + size + XATTR_PADDING_SIZE,
GFP_F2FS_ZERO);
txattr_addr = kzalloc(inline_size + size, GFP_F2FS_ZERO);
if (!txattr_addr) if (!txattr_addr)
return -ENOMEM; return -ENOMEM;
...@@ -358,19 +357,19 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage, ...@@ -358,19 +357,19 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage,
} }
/* read from xattr node block */ /* read from xattr node block */
if (F2FS_I(inode)->i_xattr_nid) { if (xnid) {
struct page *xpage; struct page *xpage;
void *xattr_addr; void *xattr_addr;
/* The inode already has an extended attribute block. */ /* The inode already has an extended attribute block. */
xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid); xpage = get_node_page(sbi, xnid);
if (IS_ERR(xpage)) { if (IS_ERR(xpage)) {
err = PTR_ERR(xpage); err = PTR_ERR(xpage);
goto fail; goto fail;
} }
xattr_addr = page_address(xpage); xattr_addr = page_address(xpage);
memcpy(txattr_addr + inline_size, xattr_addr, PAGE_SIZE); memcpy(txattr_addr + inline_size, xattr_addr, size);
f2fs_put_page(xpage, 1); f2fs_put_page(xpage, 1);
} }
...@@ -392,14 +391,12 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -392,14 +391,12 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
void *txattr_addr, struct page *ipage) void *txattr_addr, struct page *ipage)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
size_t inline_size = 0; size_t inline_size = inline_xattr_size(inode);
void *xattr_addr; void *xattr_addr;
struct page *xpage; struct page *xpage;
nid_t new_nid = 0; nid_t new_nid = 0;
int err; int err;
inline_size = inline_xattr_size(inode);
if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid) if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid)
if (!alloc_nid(sbi, &new_nid)) if (!alloc_nid(sbi, &new_nid))
return -ENOSPC; return -ENOSPC;
...@@ -454,7 +451,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize, ...@@ -454,7 +451,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
} }
xattr_addr = page_address(xpage); xattr_addr = page_address(xpage);
memcpy(xattr_addr, txattr_addr + inline_size, MAX_XATTR_BLOCK_SIZE); memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
set_page_dirty(xpage); set_page_dirty(xpage);
f2fs_put_page(xpage, 1); f2fs_put_page(xpage, 1);
...@@ -546,7 +543,9 @@ static bool f2fs_xattr_value_same(struct f2fs_xattr_entry *entry, ...@@ -546,7 +543,9 @@ static bool f2fs_xattr_value_same(struct f2fs_xattr_entry *entry,
const void *value, size_t size) const void *value, size_t size)
{ {
void *pval = entry->e_name + entry->e_name_len; void *pval = entry->e_name + entry->e_name_len;
return (entry->e_value_size == size) && !memcmp(pval, value, size);
return (le16_to_cpu(entry->e_value_size) == size) &&
!memcmp(pval, value, size);
} }
static int __f2fs_setxattr(struct inode *inode, int index, static int __f2fs_setxattr(struct inode *inode, int index,
......
...@@ -58,10 +58,10 @@ struct f2fs_xattr_entry { ...@@ -58,10 +58,10 @@ struct f2fs_xattr_entry {
#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr) + 1)) #define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr) + 1))
#define XATTR_ROUND (3) #define XATTR_ROUND (3)
#define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND) #define XATTR_ALIGN(size) (((size) + XATTR_ROUND) & ~XATTR_ROUND)
#define ENTRY_SIZE(entry) (XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + \ #define ENTRY_SIZE(entry) (XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + \
entry->e_name_len + le16_to_cpu(entry->e_value_size))) (entry)->e_name_len + le16_to_cpu((entry)->e_value_size)))
#define XATTR_NEXT_ENTRY(entry) ((struct f2fs_xattr_entry *)((char *)(entry) +\ #define XATTR_NEXT_ENTRY(entry) ((struct f2fs_xattr_entry *)((char *)(entry) +\
ENTRY_SIZE(entry))) ENTRY_SIZE(entry)))
...@@ -72,8 +72,8 @@ struct f2fs_xattr_entry { ...@@ -72,8 +72,8 @@ struct f2fs_xattr_entry {
for (entry = XATTR_FIRST_ENTRY(addr);\ for (entry = XATTR_FIRST_ENTRY(addr);\
!IS_XATTR_LAST_ENTRY(entry);\ !IS_XATTR_LAST_ENTRY(entry);\
entry = XATTR_NEXT_ENTRY(entry)) entry = XATTR_NEXT_ENTRY(entry))
#define MAX_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer)) #define VALID_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer))
#define VALID_XATTR_BLOCK_SIZE (MAX_XATTR_BLOCK_SIZE - sizeof(__u32)) #define XATTR_PADDING_SIZE (sizeof(__u32))
#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + \ #define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + \
VALID_XATTR_BLOCK_SIZE) VALID_XATTR_BLOCK_SIZE)
......
...@@ -32,9 +32,9 @@ ...@@ -32,9 +32,9 @@
/* 0, 1(node nid), 2(meta nid) are reserved node id */ /* 0, 1(node nid), 2(meta nid) are reserved node id */
#define F2FS_RESERVED_NODE_NUM 3 #define F2FS_RESERVED_NODE_NUM 3
#define F2FS_ROOT_INO(sbi) (sbi->root_ino_num) #define F2FS_ROOT_INO(sbi) ((sbi)->root_ino_num)
#define F2FS_NODE_INO(sbi) (sbi->node_ino_num) #define F2FS_NODE_INO(sbi) ((sbi)->node_ino_num)
#define F2FS_META_INO(sbi) (sbi->meta_ino_num) #define F2FS_META_INO(sbi) ((sbi)->meta_ino_num)
#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */ #define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */
#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */ #define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */
...@@ -114,6 +114,7 @@ struct f2fs_super_block { ...@@ -114,6 +114,7 @@ struct f2fs_super_block {
/* /*
* For checkpoint * For checkpoint
*/ */
#define CP_TRIMMED_FLAG 0x00000100
#define CP_NAT_BITS_FLAG 0x00000080 #define CP_NAT_BITS_FLAG 0x00000080
#define CP_CRC_RECOVERY_FLAG 0x00000040 #define CP_CRC_RECOVERY_FLAG 0x00000040
#define CP_FASTBOOT_FLAG 0x00000020 #define CP_FASTBOOT_FLAG 0x00000020
...@@ -161,7 +162,7 @@ struct f2fs_checkpoint { ...@@ -161,7 +162,7 @@ struct f2fs_checkpoint {
*/ */
#define F2FS_ORPHANS_PER_BLOCK 1020 #define F2FS_ORPHANS_PER_BLOCK 1020
#define GET_ORPHAN_BLOCKS(n) ((n + F2FS_ORPHANS_PER_BLOCK - 1) / \ #define GET_ORPHAN_BLOCKS(n) (((n) + F2FS_ORPHANS_PER_BLOCK - 1) / \
F2FS_ORPHANS_PER_BLOCK) F2FS_ORPHANS_PER_BLOCK)
struct f2fs_orphan_block { struct f2fs_orphan_block {
...@@ -301,6 +302,12 @@ struct f2fs_nat_block { ...@@ -301,6 +302,12 @@ struct f2fs_nat_block {
#define SIT_VBLOCK_MAP_SIZE 64 #define SIT_VBLOCK_MAP_SIZE 64
#define SIT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_sit_entry)) #define SIT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_sit_entry))
/*
* F2FS uses 4 bytes to represent block address. As a result, supported size of
* disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments.
*/
#define F2FS_MAX_SEGMENT ((16 * 1024 * 1024) / 2)
/* /*
* Note that f2fs_sit_entry->vblocks has the following bit-field information. * Note that f2fs_sit_entry->vblocks has the following bit-field information.
* [15:10] : allocation type such as CURSEG_XXXX_TYPE * [15:10] : allocation type such as CURSEG_XXXX_TYPE
...@@ -449,7 +456,7 @@ typedef __le32 f2fs_hash_t; ...@@ -449,7 +456,7 @@ typedef __le32 f2fs_hash_t;
#define F2FS_SLOT_LEN 8 #define F2FS_SLOT_LEN 8
#define F2FS_SLOT_LEN_BITS 3 #define F2FS_SLOT_LEN_BITS 3
#define GET_DENTRY_SLOTS(x) ((x + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS) #define GET_DENTRY_SLOTS(x) (((x) + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS)
/* MAX level for dir lookup */ /* MAX level for dir lookup */
#define MAX_DIR_HASH_DEPTH 63 #define MAX_DIR_HASH_DEPTH 63
......
...@@ -15,6 +15,8 @@ TRACE_DEFINE_ENUM(META); ...@@ -15,6 +15,8 @@ TRACE_DEFINE_ENUM(META);
TRACE_DEFINE_ENUM(META_FLUSH); TRACE_DEFINE_ENUM(META_FLUSH);
TRACE_DEFINE_ENUM(INMEM); TRACE_DEFINE_ENUM(INMEM);
TRACE_DEFINE_ENUM(INMEM_DROP); TRACE_DEFINE_ENUM(INMEM_DROP);
TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
TRACE_DEFINE_ENUM(INMEM_REVOKE);
TRACE_DEFINE_ENUM(IPU); TRACE_DEFINE_ENUM(IPU);
TRACE_DEFINE_ENUM(OPU); TRACE_DEFINE_ENUM(OPU);
TRACE_DEFINE_ENUM(CURSEG_HOT_DATA); TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
...@@ -42,6 +44,7 @@ TRACE_DEFINE_ENUM(CP_FASTBOOT); ...@@ -42,6 +44,7 @@ TRACE_DEFINE_ENUM(CP_FASTBOOT);
TRACE_DEFINE_ENUM(CP_SYNC); TRACE_DEFINE_ENUM(CP_SYNC);
TRACE_DEFINE_ENUM(CP_RECOVERY); TRACE_DEFINE_ENUM(CP_RECOVERY);
TRACE_DEFINE_ENUM(CP_DISCARD); TRACE_DEFINE_ENUM(CP_DISCARD);
TRACE_DEFINE_ENUM(CP_TRIMMED);
#define show_block_type(type) \ #define show_block_type(type) \
__print_symbolic(type, \ __print_symbolic(type, \
...@@ -51,12 +54,13 @@ TRACE_DEFINE_ENUM(CP_DISCARD); ...@@ -51,12 +54,13 @@ TRACE_DEFINE_ENUM(CP_DISCARD);
{ META_FLUSH, "META_FLUSH" }, \ { META_FLUSH, "META_FLUSH" }, \
{ INMEM, "INMEM" }, \ { INMEM, "INMEM" }, \
{ INMEM_DROP, "INMEM_DROP" }, \ { INMEM_DROP, "INMEM_DROP" }, \
{ INMEM_INVALIDATE, "INMEM_INVALIDATE" }, \
{ INMEM_REVOKE, "INMEM_REVOKE" }, \ { INMEM_REVOKE, "INMEM_REVOKE" }, \
{ IPU, "IN-PLACE" }, \ { IPU, "IN-PLACE" }, \
{ OPU, "OUT-OF-PLACE" }) { OPU, "OUT-OF-PLACE" })
#define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_PREFLUSH | REQ_META |\ #define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO | \
REQ_PRIO) REQ_PREFLUSH | REQ_FUA)
#define F2FS_BIO_FLAG_MASK(t) (t & F2FS_OP_FLAGS) #define F2FS_BIO_FLAG_MASK(t) (t & F2FS_OP_FLAGS)
#define show_bio_type(op,op_flags) show_bio_op(op), \ #define show_bio_type(op,op_flags) show_bio_op(op), \
...@@ -75,16 +79,13 @@ TRACE_DEFINE_ENUM(CP_DISCARD); ...@@ -75,16 +79,13 @@ TRACE_DEFINE_ENUM(CP_DISCARD);
{ REQ_OP_WRITE_ZEROES, "WRITE_ZEROES" }) { REQ_OP_WRITE_ZEROES, "WRITE_ZEROES" })
#define show_bio_op_flags(flags) \ #define show_bio_op_flags(flags) \
__print_symbolic(F2FS_BIO_FLAG_MASK(flags), \ __print_flags(F2FS_BIO_FLAG_MASK(flags), "|", \
{ REQ_RAHEAD, "(RA)" }, \ { REQ_RAHEAD, "R" }, \
{ REQ_SYNC, "(S)" }, \ { REQ_SYNC, "S" }, \
{ REQ_SYNC | REQ_PRIO, "(SP)" }, \ { REQ_META, "M" }, \
{ REQ_META, "(M)" }, \ { REQ_PRIO, "P" }, \
{ REQ_META | REQ_PRIO, "(MP)" }, \ { REQ_PREFLUSH, "PF" }, \
{ REQ_SYNC | REQ_PREFLUSH , "(SF)" }, \ { REQ_FUA, "FUA" })
{ REQ_SYNC | REQ_META | REQ_PRIO, "(SMP)" }, \
{ REQ_PREFLUSH | REQ_META | REQ_PRIO, "(FMP)" }, \
{ 0, " \b" })
#define show_data_type(type) \ #define show_data_type(type) \
__print_symbolic(type, \ __print_symbolic(type, \
...@@ -117,12 +118,14 @@ TRACE_DEFINE_ENUM(CP_DISCARD); ...@@ -117,12 +118,14 @@ TRACE_DEFINE_ENUM(CP_DISCARD);
{ GC_CB, "Cost-Benefit" }) { GC_CB, "Cost-Benefit" })
#define show_cpreason(type) \ #define show_cpreason(type) \
__print_symbolic(type, \ __print_flags(type, "|", \
{ CP_UMOUNT, "Umount" }, \ { CP_UMOUNT, "Umount" }, \
{ CP_FASTBOOT, "Fastboot" }, \ { CP_FASTBOOT, "Fastboot" }, \
{ CP_SYNC, "Sync" }, \ { CP_SYNC, "Sync" }, \
{ CP_RECOVERY, "Recovery" }, \ { CP_RECOVERY, "Recovery" }, \
{ CP_DISCARD, "Discard" }) { CP_DISCARD, "Discard" }, \
{ CP_UMOUNT, "Umount" }, \
{ CP_TRIMMED, "Trimmed" })
struct victim_sel_policy; struct victim_sel_policy;
struct f2fs_map_blocks; struct f2fs_map_blocks;
...@@ -769,7 +772,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio, ...@@ -769,7 +772,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
), ),
TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, " TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s%s, type = %s", "oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s",
show_dev_ino(__entry), show_dev_ino(__entry),
(unsigned long)__entry->index, (unsigned long)__entry->index,
(unsigned long long)__entry->old_blkaddr, (unsigned long long)__entry->old_blkaddr,
...@@ -822,7 +825,7 @@ DECLARE_EVENT_CLASS(f2fs__bio, ...@@ -822,7 +825,7 @@ DECLARE_EVENT_CLASS(f2fs__bio,
__entry->size = bio->bi_iter.bi_size; __entry->size = bio->bi_iter.bi_size;
), ),
TP_printk("dev = (%d,%d)/(%d,%d), rw = %s%s, %s, sector = %lld, size = %u", TP_printk("dev = (%d,%d)/(%d,%d), rw = %s(%s), %s, sector = %lld, size = %u",
show_dev(__entry->target), show_dev(__entry->target),
show_dev(__entry->dev), show_dev(__entry->dev),
show_bio_type(__entry->op, __entry->op_flags), show_bio_type(__entry->op, __entry->op_flags),
...@@ -1126,7 +1129,7 @@ TRACE_EVENT(f2fs_write_checkpoint, ...@@ -1126,7 +1129,7 @@ TRACE_EVENT(f2fs_write_checkpoint,
__entry->msg) __entry->msg)
); );
TRACE_EVENT(f2fs_issue_discard, DECLARE_EVENT_CLASS(f2fs_discard,
TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen), TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
...@@ -1150,6 +1153,20 @@ TRACE_EVENT(f2fs_issue_discard, ...@@ -1150,6 +1153,20 @@ TRACE_EVENT(f2fs_issue_discard,
(unsigned long long)__entry->blklen) (unsigned long long)__entry->blklen)
); );
DEFINE_EVENT(f2fs_discard, f2fs_queue_discard,
TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
TP_ARGS(dev, blkstart, blklen)
);
DEFINE_EVENT(f2fs_discard, f2fs_issue_discard,
TP_PROTO(struct block_device *dev, block_t blkstart, block_t blklen),
TP_ARGS(dev, blkstart, blklen)
);
TRACE_EVENT(f2fs_issue_reset_zone, TRACE_EVENT(f2fs_issue_reset_zone,
TP_PROTO(struct block_device *dev, block_t blkstart), TP_PROTO(struct block_device *dev, block_t blkstart),
...@@ -1174,26 +1191,29 @@ TRACE_EVENT(f2fs_issue_reset_zone, ...@@ -1174,26 +1191,29 @@ TRACE_EVENT(f2fs_issue_reset_zone,
TRACE_EVENT(f2fs_issue_flush, TRACE_EVENT(f2fs_issue_flush,
TP_PROTO(struct block_device *dev, unsigned int nobarrier, TP_PROTO(struct block_device *dev, unsigned int nobarrier,
unsigned int flush_merge), unsigned int flush_merge, int ret),
TP_ARGS(dev, nobarrier, flush_merge), TP_ARGS(dev, nobarrier, flush_merge, ret),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(unsigned int, nobarrier) __field(unsigned int, nobarrier)
__field(unsigned int, flush_merge) __field(unsigned int, flush_merge)
__field(int, ret)
), ),
TP_fast_assign( TP_fast_assign(
__entry->dev = dev->bd_dev; __entry->dev = dev->bd_dev;
__entry->nobarrier = nobarrier; __entry->nobarrier = nobarrier;
__entry->flush_merge = flush_merge; __entry->flush_merge = flush_merge;
__entry->ret = ret;
), ),
TP_printk("dev = (%d,%d), %s %s", TP_printk("dev = (%d,%d), %s %s, ret = %d",
show_dev(__entry->dev), show_dev(__entry->dev),
__entry->nobarrier ? "skip (nobarrier)" : "issue", __entry->nobarrier ? "skip (nobarrier)" : "issue",
__entry->flush_merge ? " with flush_merge" : "") __entry->flush_merge ? " with flush_merge" : "",
__entry->ret)
); );
TRACE_EVENT(f2fs_lookup_extent_tree_start, TRACE_EVENT(f2fs_lookup_extent_tree_start,
......
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