Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb97a784 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "This patch-set includes the following major enhancement patches:
   - support inline xattrs
   - add sysfs support to control GCs explicitly
   - add proc entry to show the current segment usage information
   - improve the GC/SSR performance

  The other bug fixes are as follows:
   - avoid the overflow on status calculation
   - fix some error handling routines
   - fix inconsistent xattr states after power-off-recovery
   - fix incorrect xattr node offset definition
   - fix deadlock condition in fsync
   - fix the fdatasync routine for power-off-recovery"

* tag 'for-f2fs-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (40 commits)
  f2fs: optimize gc for better performance
  f2fs: merge more bios of node block writes
  f2fs: avoid an overflow during utilization calculation
  f2fs: trigger GC when there are prefree segments
  f2fs: use strncasecmp() simplify the string comparison
  f2fs: fix omitting to update inode page
  f2fs: support the inline xattrs
  f2fs: add the truncate_xattr_node function
  f2fs: introduce __find_xattr for readability
  f2fs: reserve the xattr space dynamically
  f2fs: add flags for inline xattrs
  f2fs: fix error return code in init_f2fs_fs()
  f2fs: fix wrong BUG_ON condition
  f2fs: fix memory leak when init f2fs filesystem fail
  f2fs: fix a compound statement label error
  f2fs: avoid writing inode redundantly when creating a file
  f2fs: alloc_page() doesn't return an ERR_PTR
  f2fs: should cover i_xattr_nid with its xattr node page lock
  f2fs: check the free space first in new_node_page
  f2fs: clean up the needless end 'return' of void function
  ...
parents 2e032852 a26b7c8a
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
What:		/sys/fs/f2fs/<disk>/gc_max_sleep_time
Date:		July 2013
Contact:	"Namjae Jeon" <namjae.jeon@samsung.com>
Description:
		 Controls the maximun sleep time for gc_thread. Time
		 is in milliseconds.

What:		/sys/fs/f2fs/<disk>/gc_min_sleep_time
Date:		July 2013
Contact:	"Namjae Jeon" <namjae.jeon@samsung.com>
Description:
		 Controls the minimum sleep time for gc_thread. Time
		 is in milliseconds.

What:		/sys/fs/f2fs/<disk>/gc_no_gc_sleep_time
Date:		July 2013
Contact:	"Namjae Jeon" <namjae.jeon@samsung.com>
Description:
		 Controls the default sleep time for gc_thread. Time
		 is in milliseconds.

What:		/sys/fs/f2fs/<disk>/gc_idle
Date:		July 2013
Contact:	"Namjae Jeon" <namjae.jeon@samsung.com>
Description:
		 Controls the victim selection policy for garbage collection.
+71 −4
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ according to its internal geometry or flash memory management scheme, namely FTL
F2FS and its tools support various parameters not only for configuring on-disk
layout, but also for selecting allocation and cleaning algorithms.

The file system formatting tool, "mkfs.f2fs", is available from the following
git tree:
The following git tree provides the file system formatting tool (mkfs.f2fs),
a consistency checking tool (fsck.f2fs), and a debugging tool (dump.f2fs).
>> git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git

For reporting bugs and sending patches, please use the following mailing list:
@@ -132,6 +132,38 @@ f2fs. Each file shows the whole f2fs information.
 - average SIT information about whole segments
 - current memory footprint consumed by f2fs.

================================================================================
SYSFS ENTRIES
================================================================================

Information about mounted f2f2 file systems can be found in
/sys/fs/f2fs.  Each mounted filesystem will have a directory in
/sys/fs/f2fs based on its device name (i.e., /sys/fs/f2fs/sda).
The files in each per-device directory are shown in table below.

Files in /sys/fs/f2fs/<devname>
(see also Documentation/ABI/testing/sysfs-fs-f2fs)
..............................................................................
 File                         Content

 gc_max_sleep_time            This tuning parameter controls the maximum sleep
                              time for the garbage collection thread. Time is
                              in milliseconds.

 gc_min_sleep_time            This tuning parameter controls the minimum sleep
                              time for the garbage collection thread. Time is
                              in milliseconds.

 gc_no_gc_sleep_time          This tuning parameter controls the default sleep
                              time for the garbage collection thread. Time is
                              in milliseconds.

 gc_idle                      This parameter controls the selection of victim
                              policy for garbage collection. Setting gc_idle = 0
                              (default) will disable this option. Setting
                              gc_idle = 1 will select the Cost Benefit approach
                              & setting gc_idle = 2 will select the greedy aproach.

================================================================================
USAGE
================================================================================
@@ -149,8 +181,12 @@ USAGE
 # mkfs.f2fs -l label /dev/block_device
 # mount -t f2fs /dev/block_device /mnt/f2fs

Format options
--------------
mkfs.f2fs
---------
The mkfs.f2fs is for the use of formatting a partition as the f2fs filesystem,
which builds a basic on-disk layout.

The options consist of:
-l [label]   : Give a volume label, up to 512 unicode name.
-a [0 or 1]  : Split start location of each area for heap-based allocation.
               1 is set by default, which performs this.
@@ -164,6 +200,37 @@ Format options
-t [0 or 1]  : Disable discard command or not.
               1 is set by default, which conducts discard.

fsck.f2fs
---------
The fsck.f2fs is a tool to check the consistency of an f2fs-formatted
partition, which examines whether the filesystem metadata and user-made data
are cross-referenced correctly or not.
Note that, initial version of the tool does not fix any inconsistency.

The options consist of:
  -d debug level [default:0]

dump.f2fs
---------
The dump.f2fs shows the information of specific inode and dumps SSA and SIT to
file. Each file is dump_ssa and dump_sit.

The dump.f2fs is used to debug on-disk data structures of the f2fs filesystem.
It shows on-disk inode information reconized by a given inode number, and is
able to dump all the SSA and SIT entries into predefined files, ./dump_ssa and
./dump_sit respectively.

The options consist of:
  -d debug level [default:0]
  -i inode no (hex)
  -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]
  -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]

Examples:
# dump.f2fs -i [ino] /dev/sdx
# dump.f2fs -s 0~-1 /dev/sdx (SIT dump)
# dump.f2fs -a 0~-1 /dev/sdx (SSA dump)

================================================================================
DESIGN
================================================================================
+15 −9
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ const struct address_space_operations f2fs_meta_aops = {
	.set_page_dirty	= f2fs_set_meta_page_dirty,
};

int check_orphan_space(struct f2fs_sb_info *sbi)
int acquire_orphan_inode(struct f2fs_sb_info *sbi)
{
	unsigned int max_orphans;
	int err = 0;
@@ -197,10 +197,19 @@ int check_orphan_space(struct f2fs_sb_info *sbi)
	mutex_lock(&sbi->orphan_inode_mutex);
	if (sbi->n_orphans >= max_orphans)
		err = -ENOSPC;
	else
		sbi->n_orphans++;
	mutex_unlock(&sbi->orphan_inode_mutex);
	return err;
}

void release_orphan_inode(struct f2fs_sb_info *sbi)
{
	mutex_lock(&sbi->orphan_inode_mutex);
	sbi->n_orphans--;
	mutex_unlock(&sbi->orphan_inode_mutex);
}

void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
{
	struct list_head *head, *this;
@@ -229,21 +238,18 @@ retry:
		list_add(&new->list, this->prev);
	else
		list_add_tail(&new->list, head);

	sbi->n_orphans++;
out:
	mutex_unlock(&sbi->orphan_inode_mutex);
}

void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
{
	struct list_head *this, *next, *head;
	struct list_head *head;
	struct orphan_inode_entry *orphan;

	mutex_lock(&sbi->orphan_inode_mutex);
	head = &sbi->orphan_inode_list;
	list_for_each_safe(this, next, head) {
		orphan = list_entry(this, struct orphan_inode_entry, list);
	list_for_each_entry(orphan, head, list) {
		if (orphan->ino == ino) {
			list_del(&orphan->list);
			kmem_cache_free(orphan_entry_slab, orphan);
@@ -373,7 +379,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
	if (!f2fs_crc_valid(crc, cp_block, crc_offset))
		goto invalid_cp1;

	pre_version = le64_to_cpu(cp_block->checkpoint_ver);
	pre_version = cur_cp_version(cp_block);

	/* Read the 2nd cp block in this CP pack */
	cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
@@ -388,7 +394,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
	if (!f2fs_crc_valid(crc, cp_block, crc_offset))
		goto invalid_cp2;

	cur_version = le64_to_cpu(cp_block->checkpoint_ver);
	cur_version = cur_cp_version(cp_block);

	if (cur_version == pre_version) {
		*version = cur_version;
@@ -793,7 +799,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
	 * Increase the version number so that
	 * SIT entries and seg summaries are written at correct place
	 */
	ckpt_ver = le64_to_cpu(ckpt->checkpoint_ver);
	ckpt_ver = cur_cp_version(ckpt);
	ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);

	/* write cached NAT/SIT entries to NAT/SIT area */
+16 −12
Original line number Diff line number Diff line
@@ -37,9 +37,9 @@ static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr)
	struct page *node_page = dn->node_page;
	unsigned int ofs_in_node = dn->ofs_in_node;

	wait_on_page_writeback(node_page);
	f2fs_wait_on_page_writeback(node_page, NODE, false);

	rn = (struct f2fs_node *)page_address(node_page);
	rn = F2FS_NODE(node_page);

	/* Get physical address of data block */
	addr_array = blkaddr_in_node(rn);
@@ -117,7 +117,8 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
	block_t start_blkaddr, end_blkaddr;

	BUG_ON(blk_addr == NEW_ADDR);
	fofs = start_bidx_of_node(ofs_of_node(dn->node_page)) + dn->ofs_in_node;
	fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) +
							dn->ofs_in_node;

	/* Update the page address in the parent node */
	__set_data_blkaddr(dn, blk_addr);
@@ -176,7 +177,6 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
end_update:
	write_unlock(&fi->ext.ext_lock);
	sync_inode_page(dn);
	return;
}

struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
@@ -260,8 +260,17 @@ repeat:
	if (PageUptodate(page))
		return page;

	BUG_ON(dn.data_blkaddr == NEW_ADDR);
	BUG_ON(dn.data_blkaddr == NULL_ADDR);
	/*
	 * A new dentry page is allocated but not able to be written, since its
	 * new inode page couldn't be allocated due to -ENOSPC.
	 * In such the case, its blkaddr can be remained as NEW_ADDR.
	 * see, f2fs_add_link -> get_new_data_page -> init_inode_metadata.
	 */
	if (dn.data_blkaddr == NEW_ADDR) {
		zero_user_segment(page, 0, PAGE_CACHE_SIZE);
		SetPageUptodate(page);
		return page;
	}

	err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
	if (err)
@@ -365,7 +374,6 @@ static void read_end_io(struct bio *bio, int err)
		}
		unlock_page(page);
	} while (bvec >= bio->bi_io_vec);
	kfree(bio->bi_private);
	bio_put(bio);
}

@@ -391,7 +399,6 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
	bio->bi_end_io = read_end_io;

	if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
		kfree(bio->bi_private);
		bio_put(bio);
		up_read(&sbi->bio_sem);
		f2fs_put_page(page, 1);
@@ -442,7 +449,7 @@ static int get_data_block_ro(struct inode *inode, sector_t iblock,
		unsigned int end_offset;

		end_offset = IS_INODE(dn.node_page) ?
				ADDRS_PER_INODE :
				ADDRS_PER_INODE(F2FS_I(inode)) :
				ADDRS_PER_BLOCK;

		clear_buffer_new(bh_result);
@@ -636,9 +643,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	int err = 0;
	int ilock;

	/* for nobh_write_end */
	*fsdata = NULL;

	f2fs_balance_fs(sbi);
repeat:
	page = grab_cache_page_write_begin(mapping, index, flags);
+17 −17
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ static DEFINE_MUTEX(f2fs_stat_mutex);

static void update_general_status(struct f2fs_sb_info *sbi)
{
	struct f2fs_stat_info *si = sbi->stat_info;
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
	int i;

	/* valid check of the segment numbers */
@@ -83,7 +83,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
 */
static void update_sit_info(struct f2fs_sb_info *sbi)
{
	struct f2fs_stat_info *si = sbi->stat_info;
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
	unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist;
	struct sit_info *sit_i = SIT_I(sbi);
	unsigned int segno, vblocks;
@@ -118,7 +118,7 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
 */
static void update_mem_info(struct f2fs_sb_info *sbi)
{
	struct f2fs_stat_info *si = sbi->stat_info;
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
	unsigned npages;

	if (si->base_mem)
@@ -253,21 +253,21 @@ static int stat_show(struct seq_file *s, void *v)
			   si->nats, NM_WOUT_THRESHOLD);
		seq_printf(s, "  - SITs: %5d\n  - free_nids: %5d\n",
			   si->sits, si->fnids);
		seq_printf(s, "\nDistribution of User Blocks:");
		seq_printf(s, " [ valid | invalid | free ]\n");
		seq_printf(s, "  [");
		seq_puts(s, "\nDistribution of User Blocks:");
		seq_puts(s, " [ valid | invalid | free ]\n");
		seq_puts(s, "  [");

		for (j = 0; j < si->util_valid; j++)
			seq_printf(s, "-");
		seq_printf(s, "|");
			seq_putc(s, '-');
		seq_putc(s, '|');

		for (j = 0; j < si->util_invalid; j++)
			seq_printf(s, "-");
		seq_printf(s, "|");
			seq_putc(s, '-');
		seq_putc(s, '|');

		for (j = 0; j < si->util_free; j++)
			seq_printf(s, "-");
		seq_printf(s, "]\n\n");
			seq_putc(s, '-');
		seq_puts(s, "]\n\n");
		seq_printf(s, "SSR: %u blocks in %u segments\n",
			   si->block_count[SSR], si->segment_count[SSR]);
		seq_printf(s, "LFS: %u blocks in %u segments\n",
@@ -305,11 +305,10 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
	struct f2fs_stat_info *si;

	sbi->stat_info = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
	if (!sbi->stat_info)
	si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
	if (!si)
		return -ENOMEM;

	si = sbi->stat_info;
	si->all_area_segs = le32_to_cpu(raw_super->segment_count);
	si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
	si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
@@ -319,6 +318,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
	si->main_area_zones = si->main_area_sections /
				le32_to_cpu(raw_super->secs_per_zone);
	si->sbi = sbi;
	sbi->stat_info = si;

	mutex_lock(&f2fs_stat_mutex);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
@@ -329,13 +329,13 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)

void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
{
	struct f2fs_stat_info *si = sbi->stat_info;
	struct f2fs_stat_info *si = F2FS_STAT(sbi);

	mutex_lock(&f2fs_stat_mutex);
	list_del(&si->stat_list);
	mutex_unlock(&f2fs_stat_mutex);

	kfree(sbi->stat_info);
	kfree(si);
}

void __init f2fs_create_root_stats(void)
Loading