Skip to content

Commit

Permalink
Merge tag 'f2fs-for-3.18' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/jaegeuk/f2fs

Pull f2fs updates from Jaegeuk Kim:
 "This patch-set introduces a couple of new features such as large
  sector size, FITRIM, and atomic/volatile writes.

  Several patches enhance power-off recovery and checkpoint routines.

  The fsck.f2fs starts to support fixing corrupted partitions with
  recovery hints provided by this patch-set.

  Summary:
   - retain some recovery information for fsck.f2fs
   - enhance checkpoint speed
   - enhance flush command management
   - bug fix for lseek
   - tune in-place-update policies
   - enhance roll-forward speed
   - revisit all the roll-forward and fsync rules
   - support larget sector size
   - support FITRIM
   - support atomic and volatile writes

  And several clean-ups and bug fixes are included"

* tag 'f2fs-for-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (42 commits)
  f2fs: support volatile operations for transient data
  f2fs: support atomic writes
  f2fs: remove unused return value
  f2fs: clean up f2fs_ioctl functions
  f2fs: potential shift wrapping buf in f2fs_trim_fs()
  f2fs: call f2fs_unlock_op after error was handled
  f2fs: check the use of macros on block counts and addresses
  f2fs: refactor flush_nat_entries to remove costly reorganizing ops
  f2fs: introduce FITRIM in f2fs_ioctl
  f2fs: introduce cp_control structure
  f2fs: use more free segments until SSR is activated
  f2fs: change the ipu_policy option to enable combinations
  f2fs: fix to search whole dirty segmap when get_victim
  f2fs: fix to clean previous mount option when remount_fs
  f2fs: skip punching hole in special condition
  f2fs: support large sector size
  f2fs: fix to truncate blocks past EOF in ->setattr
  f2fs: update i_size when __allocate_data_block
  f2fs: use MAX_BIO_BLOCKS(sbi)
  f2fs: remove redundant operation during roll-forward recovery
  ...
  • Loading branch information
Linus Torvalds committed Oct 8, 2014
2 parents 6dea073 + 02a1335 commit da01e61
Show file tree
Hide file tree
Showing 21 changed files with 1,453 additions and 796 deletions.
7 changes: 7 additions & 0 deletions Documentation/ABI/testing/sysfs-fs-f2fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ Description:
Controls the FS utilization condition for the in-place-update
policies.

What: /sys/fs/f2fs/<disk>/min_fsync_blocks
Date: September 2014
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description:
Controls the dirty page count condition for the in-place-update
policies.

What: /sys/fs/f2fs/<disk>/max_small_discards
Date: November 2013
Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
Expand Down
13 changes: 10 additions & 3 deletions Documentation/filesystems/f2fs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,22 @@ Files in /sys/fs/f2fs/<devname>

ipu_policy This parameter controls the policy of in-place
updates in f2fs. There are five policies:
0: F2FS_IPU_FORCE, 1: F2FS_IPU_SSR,
2: F2FS_IPU_UTIL, 3: F2FS_IPU_SSR_UTIL,
4: F2FS_IPU_DISABLE.
0x01: F2FS_IPU_FORCE, 0x02: F2FS_IPU_SSR,
0x04: F2FS_IPU_UTIL, 0x08: F2FS_IPU_SSR_UTIL,
0x10: F2FS_IPU_FSYNC.

min_ipu_util This parameter controls the threshold to trigger
in-place-updates. The number indicates percentage
of the filesystem utilization, and used by
F2FS_IPU_UTIL and F2FS_IPU_SSR_UTIL policies.

min_fsync_blocks This parameter controls the threshold to trigger
in-place-updates when F2FS_IPU_FSYNC mode is set.
The number indicates the number of dirty pages
when fsync needs to flush on its call path. If
the number is less than this value, it triggers
in-place-updates.

max_victim_search This parameter controls the number of trials to
find a victim segment when conducting SSR and
cleaning operations. The default value is 4096
Expand Down
97 changes: 62 additions & 35 deletions fs/f2fs/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,22 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
return page;
}

static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
struct page *get_meta_page_ra(struct f2fs_sb_info *sbi, pgoff_t index)
{
bool readahead = false;
struct page *page;

page = find_get_page(META_MAPPING(sbi), index);
if (!page || (page && !PageUptodate(page)))
readahead = true;
f2fs_put_page(page, 0);

if (readahead)
ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR);
return get_meta_page(sbi, index);
}

static inline block_t get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
{
switch (type) {
case META_NAT:
Expand All @@ -82,6 +97,8 @@ static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
case META_SSA:
case META_CP:
return 0;
case META_POR:
return MAX_BLKADDR(sbi);
default:
BUG();
}
Expand All @@ -90,12 +107,12 @@ static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
/*
* Readahead CP/NAT/SIT/SSA pages
*/
int ra_meta_pages(struct f2fs_sb_info *sbi, int start, int nrpages, int type)
int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type)
{
block_t prev_blk_addr = 0;
struct page *page;
int blkno = start;
int max_blks = get_max_meta_blks(sbi, type);
block_t blkno = start;
block_t max_blks = get_max_meta_blks(sbi, type);

struct f2fs_io_info fio = {
.type = META,
Expand Down Expand Up @@ -125,7 +142,11 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, int start, int nrpages, int type)
break;
case META_SSA:
case META_CP:
/* get ssa/cp block addr */
case META_POR:
if (unlikely(blkno >= max_blks))
goto out;
if (unlikely(blkno < SEG0_BLKADDR(sbi)))
goto out;
blk_addr = blkno;
break;
default:
Expand All @@ -151,8 +172,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, int start, int nrpages, int type)
static int f2fs_write_meta_page(struct page *page,
struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct f2fs_sb_info *sbi = F2FS_P_SB(page);

trace_f2fs_writepage(page, META);

Expand All @@ -177,7 +197,7 @@ static int f2fs_write_meta_page(struct page *page,
static int f2fs_write_meta_pages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
long diff, written;

trace_f2fs_writepages(mapping->host, wbc, META);
Expand Down Expand Up @@ -259,15 +279,12 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,

static int f2fs_set_meta_page_dirty(struct page *page)
{
struct address_space *mapping = page->mapping;
struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);

trace_f2fs_set_page_dirty(page, META);

SetPageUptodate(page);
if (!PageDirty(page)) {
__set_page_dirty_nobuffers(page);
inc_page_count(sbi, F2FS_DIRTY_META);
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
return 1;
}
return 0;
Expand Down Expand Up @@ -378,7 +395,7 @@ 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->n_orphans == 0);
f2fs_bug_on(sbi, sbi->n_orphans == 0);
sbi->n_orphans--;
spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
}
Expand All @@ -398,7 +415,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
{
struct inode *inode = f2fs_iget(sbi->sb, ino);
f2fs_bug_on(IS_ERR(inode));
f2fs_bug_on(sbi, IS_ERR(inode));
clear_nlink(inode);

/* truncate all the data during iput */
Expand Down Expand Up @@ -459,7 +476,7 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
list_for_each_entry(orphan, head, list) {
if (!page) {
page = find_get_page(META_MAPPING(sbi), start_blk++);
f2fs_bug_on(!page);
f2fs_bug_on(sbi, !page);
orphan_blk =
(struct f2fs_orphan_block *)page_address(page);
memset(orphan_blk, 0, sizeof(*orphan_blk));
Expand Down Expand Up @@ -619,7 +636,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)

static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);

if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
return -EEXIST;
Expand All @@ -631,32 +648,38 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
return 0;
}

void set_dirty_dir_page(struct inode *inode, struct page *page)
void update_dirty_page(struct inode *inode, struct page *page)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct dir_inode_entry *new;
int ret = 0;

if (!S_ISDIR(inode->i_mode))
if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))
return;

if (!S_ISDIR(inode->i_mode)) {
inode_inc_dirty_pages(inode);
goto out;
}

new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
new->inode = inode;
INIT_LIST_HEAD(&new->list);

spin_lock(&sbi->dir_inode_lock);
ret = __add_dirty_inode(inode, new);
inode_inc_dirty_dents(inode);
SetPagePrivate(page);
inode_inc_dirty_pages(inode);
spin_unlock(&sbi->dir_inode_lock);

if (ret)
kmem_cache_free(inode_entry_slab, new);
out:
SetPagePrivate(page);
}

void add_dirty_dir_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct dir_inode_entry *new =
f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
int ret = 0;
Expand All @@ -674,14 +697,14 @@ void add_dirty_dir_inode(struct inode *inode)

void remove_dirty_dir_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct dir_inode_entry *entry;

if (!S_ISDIR(inode->i_mode))
return;

spin_lock(&sbi->dir_inode_lock);
if (get_dirty_dents(inode) ||
if (get_dirty_pages(inode) ||
!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) {
spin_unlock(&sbi->dir_inode_lock);
return;
Expand Down Expand Up @@ -802,11 +825,12 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
finish_wait(&sbi->cp_wait, &wait);
}

static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
nid_t last_nid = 0;
struct f2fs_nm_info *nm_i = NM_I(sbi);
nid_t last_nid = nm_i->next_scan_nid;
block_t start_blk;
struct page *cp_page;
unsigned int data_sum_blocks, orphan_blocks;
Expand Down Expand Up @@ -869,7 +893,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
orphan_blocks);

if (is_umount) {
if (cpc->reason == CP_UMOUNT) {
set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS+
cp_payload_blks + data_sum_blocks +
Expand All @@ -886,6 +910,9 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
else
clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);

if (sbi->need_fsck)
set_ckpt_flags(ckpt, CP_FSCK_FLAG);

/* update SIT/NAT bitmap */
get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP));
Expand Down Expand Up @@ -920,7 +947,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)

write_data_summaries(sbi, start_blk);
start_blk += data_sum_blocks;
if (is_umount) {
if (cpc->reason == CP_UMOUNT) {
write_node_summaries(sbi, start_blk);
start_blk += NR_CURSEG_NODE_TYPE;
}
Expand Down Expand Up @@ -960,23 +987,23 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
/*
* We guarantee that this checkpoint procedure will not fail.
*/
void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
unsigned long long ckpt_ver;

trace_f2fs_write_checkpoint(sbi->sb, is_umount, "start block_ops");
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops");

mutex_lock(&sbi->cp_mutex);

if (!sbi->s_dirty)
if (!sbi->s_dirty && cpc->reason != CP_DISCARD)
goto out;
if (unlikely(f2fs_cp_error(sbi)))
goto out;
if (block_operations(sbi))
goto out;

trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish block_ops");
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops");

f2fs_submit_merged_bio(sbi, DATA, WRITE);
f2fs_submit_merged_bio(sbi, NODE, WRITE);
Expand All @@ -992,16 +1019,16 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)

/* write cached NAT/SIT entries to NAT/SIT area */
flush_nat_entries(sbi);
flush_sit_entries(sbi);
flush_sit_entries(sbi, cpc);

/* unlock all the fs_lock[] in do_checkpoint() */
do_checkpoint(sbi, is_umount);
do_checkpoint(sbi, cpc);

unblock_operations(sbi);
stat_inc_cp_count(sbi->stat_info);
out:
mutex_unlock(&sbi->cp_mutex);
trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish checkpoint");
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
}

void init_ino_entry_info(struct f2fs_sb_info *sbi)
Expand Down
Loading

0 comments on commit da01e61

Please sign in to comment.