Commit 086ba2ec authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "In this round, we've added two small interfaces: (a) GC_URGENT_LOW
  mode for performance and (b) F2FS_IOC_SEC_TRIM_FILE ioctl for
  security.

  The new GC mode allows Android to run some lower priority GCs in
  background, while new ioctl discards user information without race
  condition when the account is removed.

  In addition, some patches were merged to address latency-related
  issues. We've fixed some compression-related bug fixes as well as edge
  race conditions.

  Enhancements:
   - add GC_URGENT_LOW mode in gc_urgent
   - introduce F2FS_IOC_SEC_TRIM_FILE ioctl
   - bypass racy readahead to improve read latencies
   - shrink node_write lock coverage to avoid long latency

  Bug fixes:
   - fix missing compression flag control, i_size, and mount option
   - fix deadlock between quota writes and checkpoint
   - remove inode eviction path in synchronous path to avoid deadlock
   - fix to wait GCed compressed page writeback
   - fix a kernel panic in f2fs_is_compressed_page
   - check page dirty status before writeback
   - wait page writeback before update in node page write flow
   - fix a race condition between f2fs_write_end_io and f2fs_del_fsync_node_entry

  We've added some minor sanity checks and refactored trivial code
  blocks for better readability and debugging information"

* tag 'f2fs-for-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (52 commits)
  f2fs: prepare a waiter before entering io_schedule
  f2fs: update_sit_entry: Make the judgment condition of f2fs_bug_on more intuitive
  f2fs: replace test_and_set/clear_bit() with set/clear_bit()
  f2fs: make file immutable even if releasing zero compression block
  f2fs: compress: disable compression mount option if compression is off
  f2fs: compress: add sanity check during compressed cluster read
  f2fs: use macro instead of f2fs verity version
  f2fs: fix deadlock between quota writes and checkpoint
  f2fs: correct comment of f2fs_exist_written_data
  f2fs: compress: delay temp page allocation
  f2fs: compress: fix to update isize when overwriting compressed file
  f2fs: space related cleanup
  f2fs: fix use-after-free issue
  f2fs: Change the type of f2fs_flush_inline_data() to void
  f2fs: add F2FS_IOC_SEC_TRIM_FILE ioctl
  f2fs: should avoid inode eviction in synchronous path
  f2fs: segment.h: delete a duplicated word
  f2fs: compress: fix to avoid memory leak on cc->cpages
  f2fs: use generic names for generic ioctls
  f2fs: don't keep meta inode pages used for compressed block migration
  ...
parents 8c2618a6 828add77
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -229,7 +229,9 @@ Date: August 2017
Contact:	"Jaegeuk Kim" <jaegeuk@kernel.org>
Description:	Do background GC agressively when set. When gc_urgent = 1,
		background thread starts to do GC by given gc_urgent_sleep_time
		interval. It is set to 0 by default.
		interval. When gc_urgent = 2, F2FS will lower the bar of
		checking idle in order to process outstanding discard commands
		and GC a little bit aggressively. It is set to 0 by default.

What:		/sys/fs/f2fs/<disk>/gc_urgent_sleep_time
Date:		August 2017
+4 −2
Original line number Diff line number Diff line
@@ -258,6 +258,8 @@ compress_extension=%s Support adding specified extension, so that f2fs can enab
			 on compression extension list and enable compression on
			 these file by default rather than to enable it via ioctl.
			 For other files, we can still enable compression via ioctl.
			 Note that, there is one reserved special extension '*', it
			 can be set to enable compression for all files.
inlinecrypt		 When possible, encrypt/decrypt the contents of encrypted
			 files using the blk-crypto framework rather than
			 filesystem-layer encryption. This allows the use of
@@ -743,8 +745,8 @@ Compression implementation

- In order to eliminate write amplification during overwrite, F2FS only
  support compression on write-once file, data can be compressed only when
  all logical blocks in file are valid and cluster compress ratio is lower
  than specified threshold.
  all logical blocks in cluster contain valid data and compress ratio of
  cluster data is lower than specified threshold.

- To enable compression on regular inode, there are three ways:

+9 −6
Original line number Diff line number Diff line
@@ -523,7 +523,7 @@ void f2fs_remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
	__remove_ino_entry(sbi, ino, type);
}

/* mode should be APPEND_INO or UPDATE_INO */
/* mode should be APPEND_INO, UPDATE_INO or TRANS_DIR_INO */
bool f2fs_exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
{
	struct inode_management *im = &sbi->im[mode];
@@ -1258,8 +1258,6 @@ void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type)
	DEFINE_WAIT(wait);

	for (;;) {
		prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);

		if (!get_pages(sbi, type))
			break;

@@ -1269,6 +1267,10 @@ void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type)
		if (type == F2FS_DIRTY_META)
			f2fs_sync_meta_pages(sbi, META, LONG_MAX,
							FS_CP_META_IO);
		else if (type == F2FS_WB_CP_DATA)
			f2fs_submit_merged_write(sbi, DATA);

		prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
		io_schedule_timeout(DEFAULT_IO_TIMEOUT);
	}
	finish_wait(&sbi->cp_wait, &wait);
@@ -1515,9 +1517,10 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)

	/*
	 * invalidate intermediate page cache borrowed from meta inode which are
	 * used for migration of encrypted or verity inode's blocks.
	 * used for migration of encrypted, verity or compressed inode's blocks.
	 */
	if (f2fs_sb_has_encrypt(sbi) || f2fs_sb_has_verity(sbi))
	if (f2fs_sb_has_encrypt(sbi) || f2fs_sb_has_verity(sbi) ||
		f2fs_sb_has_compression(sbi))
		invalidate_mapping_pages(META_MAPPING(sbi),
				MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1);

+64 −25
Original line number Diff line number Diff line
@@ -49,6 +49,13 @@ bool f2fs_is_compressed_page(struct page *page)
		return false;
	if (IS_ATOMIC_WRITTEN_PAGE(page) || IS_DUMMY_WRITTEN_PAGE(page))
		return false;
	/*
	 * page->private may be set with pid.
	 * pid_max is enough to check if it is traced.
	 */
	if (IS_IO_TRACED_PAGE(page))
		return false;

	f2fs_bug_on(F2FS_M_SB(page->mapping),
		*((u32 *)page_private(page)) != F2FS_COMPRESSED_PAGE_MAGIC);
	return true;
@@ -506,7 +513,7 @@ bool f2fs_is_compress_backend_ready(struct inode *inode)
	return f2fs_cops[F2FS_I(inode)->i_compress_algorithm];
}

static mempool_t *compress_page_pool = NULL;
static mempool_t *compress_page_pool;
static int num_compress_pages = 512;
module_param(num_compress_pages, uint, 0444);
MODULE_PARM_DESC(num_compress_pages,
@@ -663,6 +670,7 @@ void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity)
	const struct f2fs_compress_ops *cops =
			f2fs_cops[fi->i_compress_algorithm];
	int ret;
	int i;

	dec_page_count(sbi, F2FS_RD_DATA);

@@ -681,6 +689,26 @@ void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity)
		goto out_free_dic;
	}

	dic->tpages = f2fs_kzalloc(sbi, sizeof(struct page *) *
					dic->cluster_size, GFP_NOFS);
	if (!dic->tpages) {
		ret = -ENOMEM;
		goto out_free_dic;
	}

	for (i = 0; i < dic->cluster_size; i++) {
		if (dic->rpages[i]) {
			dic->tpages[i] = dic->rpages[i];
			continue;
		}

		dic->tpages[i] = f2fs_compress_alloc_page();
		if (!dic->tpages[i]) {
			ret = -ENOMEM;
			goto out_free_dic;
		}
	}

	if (cops->init_decompress_ctx) {
		ret = cops->init_decompress_ctx(dic);
		if (ret)
@@ -821,7 +849,7 @@ static int f2fs_compressed_blocks(struct compress_ctx *cc)
}

/* return # of valid blocks in compressed cluster */
static int f2fs_cluster_blocks(struct compress_ctx *cc, bool compr)
static int f2fs_cluster_blocks(struct compress_ctx *cc)
{
	return __f2fs_cluster_blocks(cc, false);
}
@@ -835,7 +863,7 @@ int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index)
		.cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size,
	};

	return f2fs_cluster_blocks(&cc, false);
	return f2fs_cluster_blocks(&cc);
}

static bool cluster_may_compress(struct compress_ctx *cc)
@@ -886,7 +914,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
	bool prealloc;

retry:
	ret = f2fs_cluster_blocks(cc, false);
	ret = f2fs_cluster_blocks(cc);
	if (ret <= 0)
		return ret;

@@ -949,7 +977,7 @@ retry:
	}

	if (prealloc) {
		__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
		f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);

		set_new_dnode(&dn, cc->inode, NULL, NULL, 0);

@@ -964,7 +992,7 @@ retry:
				break;
		}

		__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
		f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
	}

	if (likely(!ret)) {
@@ -1096,8 +1124,16 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
	loff_t psize;
	int i, err;

	if (!IS_NOQUOTA(inode) && !f2fs_trylock_op(sbi))
	if (IS_NOQUOTA(inode)) {
		/*
		 * We need to wait for node_write to avoid block allocation during
		 * checkpoint. This can only happen to quota writes which can cause
		 * the below discard race condition.
		 */
		down_read(&sbi->node_write);
	} else if (!f2fs_trylock_op(sbi)) {
		return -EAGAIN;
	}

	set_new_dnode(&dn, cc->inode, NULL, NULL, 0);

@@ -1137,6 +1173,13 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
		f2fs_set_compressed_page(cc->cpages[i], inode,
					cc->rpages[i + 1]->index, cic);
		fio.compressed_page = cc->cpages[i];

		fio.old_blkaddr = data_blkaddr(dn.inode, dn.node_page,
						dn.ofs_in_node + i + 1);

		/* wait for GCed page writeback via META_MAPPING */
		f2fs_wait_on_block_writeback(inode, fio.old_blkaddr);

		if (fio.encrypted) {
			fio.page = cc->rpages[i + 1];
			err = f2fs_encrypt_one_page(&fio);
@@ -1203,7 +1246,9 @@ unlock_continue:
		set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);

	f2fs_put_dnode(&dn);
	if (!IS_NOQUOTA(inode))
	if (IS_NOQUOTA(inode))
		up_read(&sbi->node_write);
	else
		f2fs_unlock_op(sbi);

	spin_lock(&fi->i_size_lock);
@@ -1230,7 +1275,9 @@ out_put_cic:
out_put_dnode:
	f2fs_put_dnode(&dn);
out_unlock_op:
	if (!IS_NOQUOTA(inode))
	if (IS_NOQUOTA(inode))
		up_read(&sbi->node_write);
	else
		f2fs_unlock_op(sbi);
	return -EAGAIN;
}
@@ -1310,6 +1357,12 @@ retry_write:
				congestion_wait(BLK_RW_ASYNC,
						DEFAULT_IO_TIMEOUT);
				lock_page(cc->rpages[i]);

				if (!PageDirty(cc->rpages[i])) {
					unlock_page(cc->rpages[i]);
					continue;
				}

				clear_page_dirty_for_io(cc->rpages[i]);
				goto retry_write;
			}
@@ -1353,6 +1406,8 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
		err = f2fs_write_compressed_pages(cc, submitted,
							wbc, io_type);
		cops->destroy_compress_ctx(cc);
		kfree(cc->cpages);
		cc->cpages = NULL;
		if (!err)
			return 0;
		f2fs_bug_on(F2FS_I_SB(cc->inode), err != -EAGAIN);
@@ -1415,22 +1470,6 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
		dic->cpages[i] = page;
	}

	dic->tpages = f2fs_kzalloc(sbi, sizeof(struct page *) *
					dic->cluster_size, GFP_NOFS);
	if (!dic->tpages)
		goto out_free;

	for (i = 0; i < dic->cluster_size; i++) {
		if (cc->rpages[i]) {
			dic->tpages[i] = cc->rpages[i];
			continue;
		}

		dic->tpages[i] = f2fs_compress_alloc_page();
		if (!dic->tpages[i])
			goto out_free;
	}

	return dic;

out_free:
+70 −23
Original line number Diff line number Diff line
@@ -1073,12 +1073,13 @@ static void f2fs_release_read_bio(struct bio *bio)

/* This can handle encryption stuffs */
static int f2fs_submit_page_read(struct inode *inode, struct page *page,
						block_t blkaddr, bool for_write)
				 block_t blkaddr, int op_flags, bool for_write)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct bio *bio;

	bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0, page->index, for_write);
	bio = f2fs_grab_read_bio(inode, blkaddr, 1, op_flags,
					page->index, for_write);
	if (IS_ERR(bio))
		return PTR_ERR(bio);

@@ -1265,7 +1266,8 @@ got_it:
		return page;
	}

	err = f2fs_submit_page_read(inode, page, dn.data_blkaddr, for_write);
	err = f2fs_submit_page_read(inode, page, dn.data_blkaddr,
						op_flags, for_write);
	if (err)
		goto put_err;
	return page;
@@ -1414,7 +1416,7 @@ alloc:
	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
	old_blkaddr = dn->data_blkaddr;
	f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr,
					&sum, seg_type, NULL, false);
					&sum, seg_type, NULL);
	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
		invalidate_mapping_pages(META_MAPPING(sbi),
					old_blkaddr, old_blkaddr);
@@ -1474,7 +1476,7 @@ map_blocks:
	return err;
}

void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
{
	if (flag == F2FS_GET_BLOCK_PRE_AIO) {
		if (lock)
@@ -1539,7 +1541,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,

next_dnode:
	if (map->m_may_create)
		__do_map_lock(sbi, flag, true);
		f2fs_do_map_lock(sbi, flag, true);

	/* When reading holes, we need its node page */
	set_new_dnode(&dn, inode, NULL, NULL, 0);
@@ -1688,7 +1690,7 @@ skip:
	f2fs_put_dnode(&dn);

	if (map->m_may_create) {
		__do_map_lock(sbi, flag, false);
		f2fs_do_map_lock(sbi, flag, false);
		f2fs_balance_fs(sbi, dn.node_changed);
	}
	goto next_dnode;
@@ -1714,7 +1716,7 @@ sync_out:
	f2fs_put_dnode(&dn);
unlock_out:
	if (map->m_may_create) {
		__do_map_lock(sbi, flag, false);
		f2fs_do_map_lock(sbi, flag, false);
		f2fs_balance_fs(sbi, dn.node_changed);
	}
out:
@@ -1861,6 +1863,7 @@ static int f2fs_xattr_fiemap(struct inode *inode,
			flags |= FIEMAP_EXTENT_LAST;

		err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);
		trace_f2fs_fiemap(inode, 0, phys, len, flags, err);
		if (err || err == 1)
			return err;
	}
@@ -1884,8 +1887,10 @@ static int f2fs_xattr_fiemap(struct inode *inode,
		flags = FIEMAP_EXTENT_LAST;
	}

	if (phys)
	if (phys) {
		err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);
		trace_f2fs_fiemap(inode, 0, phys, len, flags, err);
	}

	return (err < 0 ? err : 0);
}
@@ -1979,6 +1984,7 @@ next:

		ret = fiemap_fill_next_extent(fieinfo, logical,
				phys, size, flags);
		trace_f2fs_fiemap(inode, logical, phys, size, flags, ret);
		if (ret)
			goto out;
		size = 0;
@@ -2213,9 +2219,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
	if (ret)
		goto out;

	/* cluster was overwritten as normal cluster */
	if (dn.data_blkaddr != COMPRESS_ADDR)
		goto out;
	f2fs_bug_on(sbi, dn.data_blkaddr != COMPRESS_ADDR);

	for (i = 1; i < cc->cluster_size; i++) {
		block_t blkaddr;
@@ -2342,6 +2346,7 @@ static int f2fs_mpage_readpages(struct inode *inode,
	unsigned nr_pages = rac ? readahead_count(rac) : 1;
	unsigned max_nr_pages = nr_pages;
	int ret = 0;
	bool drop_ra = false;

	map.m_pblk = 0;
	map.m_lblk = 0;
@@ -2352,10 +2357,26 @@ static int f2fs_mpage_readpages(struct inode *inode,
	map.m_seg_type = NO_CHECK_TYPE;
	map.m_may_create = false;

	/*
	 * Two readahead threads for same address range can cause race condition
	 * which fragments sequential read IOs. So let's avoid each other.
	 */
	if (rac && readahead_count(rac)) {
		if (READ_ONCE(F2FS_I(inode)->ra_offset) == readahead_index(rac))
			drop_ra = true;
		else
			WRITE_ONCE(F2FS_I(inode)->ra_offset,
						readahead_index(rac));
	}

	for (; nr_pages; nr_pages--) {
		if (rac) {
			page = readahead_page(rac);
			prefetchw(&page->flags);
			if (drop_ra) {
				f2fs_put_page(page, 1);
				continue;
			}
		}

#ifdef CONFIG_F2FS_FS_COMPRESSION
@@ -2418,6 +2439,9 @@ next_page:
	}
	if (bio)
		__submit_bio(F2FS_I_SB(inode), bio, DATA);

	if (rac && readahead_count(rac) && !drop_ra)
		WRITE_ONCE(F2FS_I(inode)->ra_offset, -1);
	return ret;
}

@@ -2772,8 +2796,20 @@ write:

	/* Dentry/quota blocks are controlled by checkpoint */
	if (S_ISDIR(inode->i_mode) || IS_NOQUOTA(inode)) {
		/*
		 * We need to wait for node_write to avoid block allocation during
		 * checkpoint. This can only happen to quota writes which can cause
		 * the below discard race condition.
		 */
		if (IS_NOQUOTA(inode))
			down_read(&sbi->node_write);

		fio.need_lock = LOCK_DONE;
		err = f2fs_do_write_data_page(&fio);

		if (IS_NOQUOTA(inode))
			up_read(&sbi->node_write);

		goto done;
	}

@@ -3268,7 +3304,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,

	if (f2fs_has_inline_data(inode) ||
			(pos & PAGE_MASK) >= i_size_read(inode)) {
		__do_map_lock(sbi, flag, true);
		f2fs_do_map_lock(sbi, flag, true);
		locked = true;
	}

@@ -3305,7 +3341,7 @@ restart:
			err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
			if (err || dn.data_blkaddr == NULL_ADDR) {
				f2fs_put_dnode(&dn);
				__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO,
				f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO,
								true);
				WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO);
				locked = true;
@@ -3321,7 +3357,7 @@ out:
	f2fs_put_dnode(&dn);
unlock_out:
	if (locked)
		__do_map_lock(sbi, flag, false);
		f2fs_do_map_lock(sbi, flag, false);
	return err;
}

@@ -3433,7 +3469,7 @@ repeat:
			err = -EFSCORRUPTED;
			goto fail;
		}
		err = f2fs_submit_page_read(inode, page, blkaddr, true);
		err = f2fs_submit_page_read(inode, page, blkaddr, 0, true);
		if (err)
			goto fail;

@@ -3483,6 +3519,10 @@ static int f2fs_write_end(struct file *file,
	if (f2fs_compressed_file(inode) && fsdata) {
		f2fs_compress_write_end(inode, fsdata, page->index, copied);
		f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);

		if (pos + copied > i_size_read(inode) &&
				!f2fs_verity_in_progress(inode))
			f2fs_i_size_write(inode, pos + copied);
		return copied;
	}
#endif
@@ -3742,10 +3782,9 @@ static sector_t f2fs_bmap_compress(struct inode *inode, sector_t block)
	}

	f2fs_put_dnode(&dn);

	return blknr;
#else
	return -EOPNOTSUPP;
	return 0;
#endif
}

@@ -3753,18 +3792,26 @@ static sector_t f2fs_bmap_compress(struct inode *inode, sector_t block)
static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
{
	struct inode *inode = mapping->host;
	struct buffer_head tmp = {
		.b_size = i_blocksize(inode),
	};
	sector_t blknr = 0;

	if (f2fs_has_inline_data(inode))
		return 0;
		goto out;

	/* make sure allocating whole blocks */
	if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
		filemap_write_and_wait(mapping);

	if (f2fs_compressed_file(inode))
		return f2fs_bmap_compress(inode, block);
		blknr = f2fs_bmap_compress(inode, block);

	return generic_block_bmap(mapping, block, get_data_block_bmap);
	if (!get_data_block_bmap(inode, block, &tmp, 0))
		blknr = tmp.b_blocknr;
out:
	trace_f2fs_bmap(inode, block, blknr);
	return blknr;
}

#ifdef CONFIG_MIGRATION
Loading