Skip to content

Commit

Permalink
f2fs: updated to "f2fs: convert inline_data when i_size becomes large"
Browse files Browse the repository at this point in the history
  • Loading branch information
imoseyon committed Nov 14, 2014
1 parent d36918b commit 8ba89a7
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 34 deletions.
27 changes: 15 additions & 12 deletions fs/f2fs/checkpoint.c
Expand Up @@ -319,6 +319,8 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
e->ino = ino;

list_add_tail(&e->list, &sbi->ino_list[type]);
if (type != ORPHAN_INO)
sbi->ino_num[type]++;
}
spin_unlock(&sbi->ino_lock[type]);
}
Expand All @@ -332,8 +334,7 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
if (e) {
list_del(&e->list);
radix_tree_delete(&sbi->ino_root[type], ino);
if (type == ORPHAN_INO)
sbi->n_orphans--;
sbi->ino_num[type]--;
spin_unlock(&sbi->ino_lock[type]);
kmem_cache_free(ino_entry_slab, e);
return;
Expand Down Expand Up @@ -374,6 +375,7 @@ void release_dirty_inode(struct f2fs_sb_info *sbi)
list_del(&e->list);
radix_tree_delete(&sbi->ino_root[i], e->ino);
kmem_cache_free(ino_entry_slab, e);
sbi->ino_num[i]--;
}
spin_unlock(&sbi->ino_lock[i]);
}
Expand All @@ -384,10 +386,10 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
int err = 0;

spin_lock(&sbi->ino_lock[ORPHAN_INO]);
if (unlikely(sbi->n_orphans >= sbi->max_orphans))
if (unlikely(sbi->ino_num[ORPHAN_INO] >= sbi->max_orphans))
err = -ENOSPC;
else
sbi->n_orphans++;
sbi->ino_num[ORPHAN_INO]++;
spin_unlock(&sbi->ino_lock[ORPHAN_INO]);

return err;
Expand All @@ -396,8 +398,8 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
void release_orphan_inode(struct f2fs_sb_info *sbi)
{
spin_lock(&sbi->ino_lock[ORPHAN_INO]);
f2fs_bug_on(sbi, sbi->n_orphans == 0);
sbi->n_orphans--;
f2fs_bug_on(sbi, sbi->ino_num[ORPHAN_INO] == 0);
sbi->ino_num[ORPHAN_INO]--;
spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
}

Expand Down Expand Up @@ -461,11 +463,12 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
struct f2fs_orphan_block *orphan_blk = NULL;
unsigned int nentries = 0;
unsigned short index;
unsigned short orphan_blocks =
(unsigned short)GET_ORPHAN_BLOCKS(sbi->n_orphans);
unsigned short orphan_blocks;
struct page *page = NULL;
struct ino_entry *orphan = NULL;

orphan_blocks = GET_ORPHAN_BLOCKS(sbi->ino_num[ORPHAN_INO]);

for (index = 0; index < orphan_blocks; index++)
grab_meta_page(sbi, start_blk + index);

Expand Down Expand Up @@ -893,7 +896,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
else
clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);

orphan_blocks = GET_ORPHAN_BLOCKS(sbi->n_orphans);
orphan_blocks = GET_ORPHAN_BLOCKS(sbi->ino_num[ORPHAN_INO]);
ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
orphan_blocks);

Expand All @@ -909,7 +912,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
orphan_blocks);
}

if (sbi->n_orphans)
if (sbi->ino_num[ORPHAN_INO])
set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
else
clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
Expand Down Expand Up @@ -944,7 +947,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
f2fs_put_page(cp_page, 1);
}

if (sbi->n_orphans) {
if (sbi->ino_num[ORPHAN_INO]) {
write_orphan_inodes(sbi, start_blk);
start_blk += orphan_blocks;
}
Expand Down Expand Up @@ -1046,6 +1049,7 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
INIT_RADIX_TREE(&sbi->ino_root[i], GFP_ATOMIC);
spin_lock_init(&sbi->ino_lock[i]);
INIT_LIST_HEAD(&sbi->ino_list[i]);
sbi->ino_num[i] = 0;
}

/*
Expand All @@ -1054,7 +1058,6 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
* orphan entries with the limitation one reserved segment
* for cp pack we can have max 1020*504 orphan entries
*/
sbi->n_orphans = 0;
sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
NR_CURSEG_TYPE) * F2FS_ORPHANS_PER_BLOCK;
}
Expand Down
4 changes: 3 additions & 1 deletion fs/f2fs/debug.c
Expand Up @@ -119,6 +119,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
{
struct f2fs_stat_info *si = F2FS_STAT(sbi);
unsigned npages;
int i;

if (si->base_mem)
goto get_cache;
Expand Down Expand Up @@ -168,8 +169,9 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
si->cache_mem += npages << PAGE_CACHE_SHIFT;
npages = META_MAPPING(sbi)->nrpages;
si->cache_mem += npages << PAGE_CACHE_SHIFT;
si->cache_mem += sbi->n_orphans * sizeof(struct ino_entry);
si->cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry);
for (i = 0; i <= UPDATE_INO; i++)
si->cache_mem += sbi->ino_num[i] * sizeof(struct ino_entry);
}

static int stat_show(struct seq_file *s, void *v)
Expand Down
2 changes: 1 addition & 1 deletion fs/f2fs/f2fs.h
Expand Up @@ -533,9 +533,9 @@ struct f2fs_sb_info {
struct radix_tree_root ino_root[MAX_INO_ENTRY]; /* ino entry array */
spinlock_t ino_lock[MAX_INO_ENTRY]; /* for ino entry lock */
struct list_head ino_list[MAX_INO_ENTRY]; /* inode list head */
unsigned long ino_num[MAX_INO_ENTRY]; /* number of entries */

/* for orphan inode, use 0'th array */
unsigned int n_orphans; /* # of orphan inodes */
unsigned int max_orphans; /* max orphan inodes */

/* for directory inode management */
Expand Down
16 changes: 11 additions & 5 deletions fs/f2fs/file.c
Expand Up @@ -129,6 +129,8 @@ static inline bool need_do_checkpoint(struct inode *inode)
need_cp = true;
else if (test_opt(sbi, FASTBOOT))
need_cp = true;
else if (sbi->active_logs == 2)
need_cp = true;

return need_cp;
}
Expand Down Expand Up @@ -491,8 +493,6 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
}

if (f2fs_has_inline_data(inode)) {
truncate_inline_data(ipage, from);
update_inode(inode, ipage);
f2fs_put_page(ipage, 1);
goto out;
}
Expand All @@ -518,13 +518,13 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
f2fs_put_dnode(&dn);
free_next:
err = truncate_inode_blocks(inode, free_from);
out:
if (lock)
f2fs_unlock_op(sbi);

/* lastly zero out the first data page */
if (!err)
err = truncate_partial_data_page(inode, from);
out:
if (lock)
f2fs_unlock_op(sbi);

trace_f2fs_truncate_blocks_exit(inode, err);
return err;
Expand All @@ -538,6 +538,12 @@ void f2fs_truncate(struct inode *inode)

trace_f2fs_truncate(inode);

/* we should check inline_data size */
if (f2fs_has_inline_data(inode) && !f2fs_may_inline(inode)) {
if (f2fs_convert_inline_inode(inode))
return;
}

if (!truncate_blocks(inode, i_size_read(inode), true)) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
Expand Down
5 changes: 4 additions & 1 deletion fs/f2fs/inline.c
Expand Up @@ -24,6 +24,9 @@ bool f2fs_may_inline(struct inode *inode)
if (!S_ISREG(inode->i_mode))
return false;

if (i_size_read(inode) > MAX_INLINE_DATA)
return false;

return true;
}

Expand Down Expand Up @@ -116,8 +119,8 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
/* clear inline data and flag after data writeback */
truncate_inline_data(dn->inode_page, 0);
clear_out:
f2fs_clear_inline_inode(dn->inode);
stat_dec_inline_inode(dn->inode);
f2fs_clear_inline_inode(dn->inode);
sync_inode_page(dn);
f2fs_put_dnode(dn);
return 0;
Expand Down
21 changes: 21 additions & 0 deletions fs/f2fs/namei.c
Expand Up @@ -138,6 +138,9 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
stat_inc_inline_inode(inode);
d_instantiate(dentry, inode);
unlock_new_inode(inode);

if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
return 0;
out:
handle_failed_inode(inode);
Expand All @@ -164,6 +167,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
f2fs_unlock_op(sbi);

d_instantiate(dentry, inode);

if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
return 0;
out:
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
Expand Down Expand Up @@ -235,6 +241,9 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)

/* In order to evict this inode, we set it dirty */
mark_inode_dirty(inode);

if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
fail:
trace_f2fs_unlink_exit(inode, err);
return err;
Expand Down Expand Up @@ -268,6 +277,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,

d_instantiate(dentry, inode);
unlock_new_inode(inode);

if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
return err;
out:
handle_failed_inode(inode);
Expand Down Expand Up @@ -304,6 +316,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
d_instantiate(dentry, inode);
unlock_new_inode(inode);

if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
return 0;

out_fail:
Expand Down Expand Up @@ -346,8 +360,12 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
f2fs_unlock_op(sbi);

alloc_nid_done(sbi, inode->i_ino);

d_instantiate(dentry, inode);
unlock_new_inode(inode);

if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
return 0;
out:
handle_failed_inode(inode);
Expand Down Expand Up @@ -461,6 +479,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
}

f2fs_unlock_op(sbi);

if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
f2fs_sync_fs(sbi->sb, 1);
return 0;

put_out_dir:
Expand Down
38 changes: 28 additions & 10 deletions fs/f2fs/node.c
Expand Up @@ -31,22 +31,38 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct sysinfo val;
unsigned long avail_ram;
unsigned long mem_size = 0;
bool res = false;

si_meminfo(&val);
/* give 25%, 25%, 50% memory for each components respectively */

/* only uses low memory */
avail_ram = val.totalram - val.totalhigh;

/* give 25%, 25%, 50%, 50% memory for each components respectively */
if (type == FREE_NIDS) {
mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >> 12;
res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >>
PAGE_CACHE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
} else if (type == NAT_ENTRIES) {
mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12;
res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >>
PAGE_CACHE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
} else if (type == DIRTY_DENTS) {
if (sbi->sb->s_bdi->dirty_exceeded)
return false;
mem_size = get_pages(sbi, F2FS_DIRTY_DENTS);
res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1);
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
} else if (type == INO_ENTRIES) {
int i;

if (sbi->sb->s_bdi->dirty_exceeded)
return false;
for (i = 0; i <= UPDATE_INO; i++)
mem_size += (sbi->ino_num[i] * sizeof(struct ino_entry))
>> PAGE_CACHE_SHIFT;
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
}
return res;
}
Expand Down Expand Up @@ -1300,10 +1316,12 @@ static int f2fs_write_node_page(struct page *page,
return 0;
}

if (wbc->for_reclaim)
goto redirty_out;

down_read(&sbi->node_write);
if (wbc->for_reclaim) {
if (!down_read_trylock(&sbi->node_write))
goto redirty_out;
} else {
down_read(&sbi->node_write);
}
set_page_writeback(page);
write_node_page(sbi, page, &fio, nid, ni.blk_addr, &new_addr);
set_node_addr(sbi, &ni, new_addr, is_fsync_dnode(page));
Expand Down
3 changes: 2 additions & 1 deletion fs/f2fs/node.h
Expand Up @@ -106,7 +106,8 @@ static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne,
enum mem_type {
FREE_NIDS, /* indicates the free nid list */
NAT_ENTRIES, /* indicates the cached nat entry */
DIRTY_DENTS /* indicates dirty dentry pages */
DIRTY_DENTS, /* indicates dirty dentry pages */
INO_ENTRIES, /* indicates inode entries */
};

struct nat_entry_set {
Expand Down
7 changes: 4 additions & 3 deletions fs/f2fs/segment.c
Expand Up @@ -335,7 +335,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
{
/* check the # of cached NAT entries and prefree segments */
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) ||
excess_prefree_segs(sbi))
excess_prefree_segs(sbi) ||
available_free_memory(sbi, INO_ENTRIES))
f2fs_sync_fs(sbi->sb, true);
}

Expand Down Expand Up @@ -1176,8 +1177,8 @@ static int __get_segment_type_4(struct page *page, enum page_type p_type)
else
return CURSEG_COLD_DATA;
} else {
if (IS_DNODE(page) && !is_cold_node(page))
return CURSEG_HOT_NODE;
if (IS_DNODE(page) && is_cold_node(page))
return CURSEG_WARM_NODE;
else
return CURSEG_COLD_NODE;
}
Expand Down
3 changes: 3 additions & 0 deletions fs/f2fs/segment.h
Expand Up @@ -711,6 +711,9 @@ static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi)
*/
static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
{
if (sbi->sb->s_bdi->dirty_exceeded)
return 0;

if (type == DATA)
return sbi->blocks_per_seg;
else if (type == NODE)
Expand Down

0 comments on commit 8ba89a7

Please sign in to comment.