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

Commit ce767d9a authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: updates on v4.16-rc1



Pull f2fs updates from Jaegeuk Kim:
 "In this round, we've followed up to support some generic features such
  as cgroup, block reservation, linking fscrypt_ops, delivering
  write_hints, and some ioctls. And, we could fix some corner cases in
  terms of power-cut recovery and subtle deadlocks.

  Enhancements:
   - bitmap operations to handle NAT blocks
   - readahead to improve readdir speed
   - switch to use fscrypt_*
   - apply write hints for direct IO
   - add reserve_root=%u,resuid=%u,resgid=%u to reserve blocks for root/uid/gid
   - modify b_avail and b_free to consider root reserved blocks
   - support cgroup writeback
   - support FIEMAP_FLAG_XATTR for fibmap
   - add F2FS_IOC_PRECACHE_EXTENTS to pre-cache extents
   - add F2FS_IOC_{GET/SET}_PIN_FILE to pin LBAs for data blocks
   - support inode creation time

  Bug fixs:
   - sysfile-based quota operations
   - memory footprint accounting
   - allow to write data on partial preallocation case
   - fix deadlock case on fallocate
   - fix to handle fill_super errors
   - fix missing inode updates of fsync'ed file
   - recover renamed file which was fsycn'ed before
   - drop inmemory pages in corner error case
   - keep last_disk_size correctly
   - recover missing i_inline flags during roll-forward

  Various clean-up patches were added as well"

Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y:

00f0eaaa f2fs: support inode creation time
3e7444ad f2fs: rebuild sit page from sit info in mem
76688790 f2fs: stop issuing discard if fs is readonly
ae93dca2 f2fs: clean up duplicated assignment in init_discard_policy
0052bba1 f2fs: use GFP_F2FS_ZERO for cleanup
6271336c f2fs: allow to recover node blocks given updated checkpoint
e003a2d1 f2fs: recover some i_inline flags
3cafae53 f2fs: correct removexattr behavior for null valued extended attribute
78d7fa9a f2fs: drop page cache after fs shutdown
150b61ce f2fs: stop gc/discard thread after fs shutdown
cf27ccc4 f2fs: hanlde error case in f2fs_ioc_shutdown
1526117c f2fs: split need_inplace_update
cd576d7b f2fs: fix to update last_disk_size correctly
7a57bd33 f2fs: kill F2FS_INLINE_XATTR_ADDRS for cleanup
95eb6a6c f2fs: clean up error path of fill_super
63c949c9 f2fs: avoid hungtask when GC encrypted block if io_bits is set
583d13d1 f2fs: allow quota to use reserved blocks
fbe371d3 f2fs: fix to drop all inmem pages correctly
7e08ce43 f2fs: speed up defragment on sparse file
0f914cab f2fs: support F2FS_IOC_PRECACHE_EXTENTS
ed1311e5 f2fs: add an ioctl to disable GC for specific file
b08974ab f2fs: prevent newly created inode from being dirtied incorrectly
e8a8acf6 f2fs: support FIEMAP_FLAG_XATTR
042aeed6 f2fs: fix to cover f2fs_inline_data_fiemap with inode_lock
9cf9c37e f2fs: check node page again in write end io
b9eedb48 f2fs: fix to caclulate required free section correctly
75ae50cf f2fs: handle newly created page when revoking inmem pages
871b9749 f2fs: add resgid and resuid to reserve root blocks
0cf361ac f2fs: implement cgroup writeback support
196d52cf f2fs: remove unused pend_list_tag
6e899a83 f2fs: avoid high cpu usage in discard thread
bb1af976 f2fs: make local functions static
ad658936 f2fs: add reserved blocks for root user
c6e64f1f f2fs: check segment type in __f2fs_replace_block
88cdc60b f2fs: update inode info to inode page for new file
4203e9fb f2fs: show precise # of blocks that user/root can use
47dc1372 f2fs: clean up unneeded declaration
27f9e551 f2fs: continue to do direct IO if we only preallocate partial blocks
f2f13783 f2fs: enable quota at remount from r to w
d507f300 f2fs: skip stop_checkpoint for user data writes
4b242ffc f2fs: fix missing error number for xattr operation
c6c76a0e f2fs: recover directory operations by fsync
5943e399 f2fs: return error during fill_super
93579c97 f2fs: fix an error case of missing update inode page
3d753c15 f2fs: fix potential hangtask in f2fs_trace_pid
625f066c f2fs: no need return value in restore summary process
f76c831a f2fs: use unlikely for release case
0408ad5e f2fs: don't return value in truncate_data_blocks_range
62e507cd f2fs: clean up f2fs_map_blocks
233b1977 f2fs: clean up hash codes
58d550e5 f2fs: fix error handling in fill_super
35d78e6f f2fs: spread f2fs_k{m,z}alloc
fecf31ce f2fs: inject fault to kvmalloc
41af39db f2fs: inject fault to kzalloc
9fecb415 f2fs: remove a redundant conditional expression
8e56c02e f2fs: apply write hints to select the type of segment for direct write
a4015f91 f2fs: switch to fscrypt_prepare_setattr()
56351ec7 f2fs: switch to fscrypt_prepare_lookup()
51f2caab f2fs: switch to fscrypt_prepare_rename()
f9a35b22 f2fs: switch to fscrypt_prepare_link()
787bd263 f2fs: switch to fscrypt_file_open()
eb9d8ee0 posix_acl: convert posix_acl.a_refcount from atomic_t to refcount_t
bd0bb8ab f2fs: remove repeated f2fs_bug_on
d1c0441c f2fs: remove an excess variable
3f12c94d f2fs: fix lock dependency in between dio_rwsem & i_mmap_sem
39685b35 f2fs: remove unused parameter
b8357704 f2fs: still write data if preallocate only partial blocks
b61cf217 f2fs: introduce sysfs readdir_ra to readahead inode block in readdir
44ed9b2d f2fs: fix concurrent problem for updating free bitmap
08be3792 f2fs: remove unneeded memory footprint accounting
33362399 f2fs: no need to read nat block if nat_block_bitmap is set
01bb5c8b f2fs: reserve nid resource for quota sysfile

Change-Id: Ie0beb18a04fc300d1591d64c7ae542a478644e26
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@google.com>
parent 474d3c46
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -186,3 +186,9 @@ Date: August 2017
Contact:	"Jaegeuk Kim" <jaegeuk@kernel.org>
Description:
		 Controls sleep time of GC urgent mode

What:		/sys/fs/f2fs/<disk>/readdir_ra
Date:		November 2017
Contact:	"Sheng Yong" <shengyong1@huawei.com>
Description:
		 Controls readahead inode block in readdir.
+1 −1
Original line number Diff line number Diff line
@@ -270,7 +270,7 @@ static struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl,
				sizeof(struct posix_acl_entry);
		clone = kmemdup(acl, size, flags);
		if (clone)
			atomic_set(&clone->a_refcount, 1);
			refcount_set(&clone->a_refcount, 1);
	}
	return clone;
}
+7 −3
Original line number Diff line number Diff line
@@ -237,12 +237,15 @@ static int __f2fs_write_meta_page(struct page *page,

	trace_f2fs_writepage(page, META);

	if (unlikely(f2fs_cp_error(sbi))) {
		dec_page_count(sbi, F2FS_DIRTY_META);
		unlock_page(page);
		return 0;
	}
	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
		goto redirty_out;
	if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
		goto redirty_out;
	if (unlikely(f2fs_cp_error(sbi)))
		goto redirty_out;

	write_meta_page(sbi, page, io_type);
	dec_page_count(sbi, F2FS_DIRTY_META);
@@ -796,7 +799,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
	block_t cp_blk_no;
	int i;

	sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL);
	sbi->ckpt = f2fs_kzalloc(sbi, cp_blks * blk_size, GFP_KERNEL);
	if (!sbi->ckpt)
		return -ENOMEM;
	/*
@@ -1157,6 +1160,7 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)

	/* set this flag to activate crc|cp_ver for recovery */
	__set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
	__clear_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG);

	spin_unlock_irqrestore(&sbi->cp_lock, flags);
}
+254 −45
Original line number Diff line number Diff line
@@ -112,8 +112,13 @@ static void f2fs_write_end_io(struct bio *bio)

		if (unlikely(bio->bi_status)) {
			mapping_set_error(page->mapping, -EIO);
			if (type == F2FS_WB_CP_DATA)
				f2fs_stop_checkpoint(sbi, true);
		}

		f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
					page->index != nid_of_node(page));

		dec_page_count(sbi, type);
		clear_cold_data(page);
		end_page_writeback(page);
@@ -170,6 +175,7 @@ static bool __same_bdev(struct f2fs_sb_info *sbi,
 * Low-level block read/write IO operations.
 */
static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
				struct writeback_control *wbc,
				int npages, bool is_read)
{
	struct bio *bio;
@@ -179,6 +185,8 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
	f2fs_target_device(sbi, blk_addr, bio);
	bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
	bio->bi_private = is_read ? NULL : sbi;
	if (wbc)
		wbc_init_bio(wbc, bio);

	return bio;
}
@@ -374,7 +382,8 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
	f2fs_trace_ios(fio, 0);

	/* Allocate a new bio */
	bio = __bio_alloc(fio->sbi, fio->new_blkaddr, 1, is_read_io(fio->op));
	bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
				1, is_read_io(fio->op));

	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
		bio_put(bio);
@@ -436,7 +445,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
			dec_page_count(sbi, WB_DATA_TYPE(bio_page));
			goto out_fail;
		}
		io->bio = __bio_alloc(sbi, fio->new_blkaddr,
		io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
						BIO_MAX_PAGES, false);
		io->fio = *fio;
	}
@@ -446,6 +455,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
		goto alloc_new;
	}

	if (fio->io_wbc)
		wbc_account_io(fio->io_wbc, bio_page, PAGE_SIZE);

	io->last_block_in_bio = fio->new_blkaddr;
	f2fs_trace_ios(fio, 0);

@@ -784,7 +796,7 @@ struct page *get_new_data_page(struct inode *inode,
	return page;
}

static int __allocate_data_block(struct dnode_of_data *dn)
static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
	struct f2fs_summary sum;
@@ -809,7 +821,7 @@ static int __allocate_data_block(struct dnode_of_data *dn)
	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);

	allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr,
					&sum, CURSEG_WARM_DATA, NULL, false);
					&sum, seg_type, NULL, false);
	set_data_blkaddr(dn);

	/* update i_size */
@@ -832,10 +844,12 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
{
	struct inode *inode = file_inode(iocb->ki_filp);
	struct f2fs_map_blocks map;
	int flag;
	int err = 0;
	bool direct_io = iocb->ki_flags & IOCB_DIRECT;

	/* convert inline data for Direct I/O*/
	if (iocb->ki_flags & IOCB_DIRECT) {
	if (direct_io) {
		err = f2fs_convert_inline_inode(inode);
		if (err)
			return err;
@@ -852,19 +866,33 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
		map.m_len = 0;

	map.m_next_pgofs = NULL;
	map.m_next_extent = NULL;
	map.m_seg_type = NO_CHECK_TYPE;

	if (iocb->ki_flags & IOCB_DIRECT)
		return f2fs_map_blocks(inode, &map, 1,
			__force_buffered_io(inode, WRITE) ?
	if (direct_io) {
		map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint);
		flag = __force_buffered_io(inode, WRITE) ?
					F2FS_GET_BLOCK_PRE_AIO :
				F2FS_GET_BLOCK_PRE_DIO);
					F2FS_GET_BLOCK_PRE_DIO;
		goto map_blocks;
	}
	if (iocb->ki_pos + iov_iter_count(from) > MAX_INLINE_DATA(inode)) {
		err = f2fs_convert_inline_inode(inode);
		if (err)
			return err;
	}
	if (!f2fs_has_inline_data(inode))
		return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
	if (f2fs_has_inline_data(inode))
		return err;

	flag = F2FS_GET_BLOCK_PRE_AIO;

map_blocks:
	err = f2fs_map_blocks(inode, &map, 1, flag);
	if (map.m_len > 0 && err == -ENOSPC) {
		if (!direct_io)
			set_inode_flag(inode, FI_NO_PREALLOC);
		err = 0;
	}
	return err;
}

@@ -905,6 +933,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
	blkcnt_t prealloc;
	struct extent_info ei = {0,0,0};
	block_t blkaddr;
	unsigned int start_pgofs;

	if (!maxblocks)
		return 0;
@@ -920,6 +949,8 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
		map->m_pblk = ei.blk + pgofs - ei.fofs;
		map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
		map->m_flags = F2FS_MAP_MAPPED;
		if (map->m_next_extent)
			*map->m_next_extent = pgofs + map->m_len;
		goto out;
	}

@@ -938,10 +969,14 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
			if (map->m_next_pgofs)
				*map->m_next_pgofs =
					get_next_page_offset(&dn, pgofs);
			if (map->m_next_extent)
				*map->m_next_extent =
					get_next_page_offset(&dn, pgofs);
		}
		goto unlock_out;
	}

	start_pgofs = pgofs;
	prealloc = 0;
	last_ofs_in_node = ofs_in_node = dn.ofs_in_node;
	end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
@@ -961,7 +996,8 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
					last_ofs_in_node = dn.ofs_in_node;
				}
			} else {
				err = __allocate_data_block(&dn);
				err = __allocate_data_block(&dn,
							map->m_seg_type);
				if (!err)
					set_inode_flag(inode, FI_APPEND_WRITE);
			}
@@ -974,16 +1010,22 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
				map->m_pblk = 0;
				goto sync_out;
			}
			if (flag == F2FS_GET_BLOCK_PRECACHE)
				goto sync_out;
			if (flag == F2FS_GET_BLOCK_FIEMAP &&
						blkaddr == NULL_ADDR) {
				if (map->m_next_pgofs)
					*map->m_next_pgofs = pgofs + 1;
				goto sync_out;
			}
			if (flag != F2FS_GET_BLOCK_FIEMAP ||
						blkaddr != NEW_ADDR)
			if (flag != F2FS_GET_BLOCK_FIEMAP) {
				/* for defragment case */
				if (map->m_next_pgofs)
					*map->m_next_pgofs = pgofs + 1;
				goto sync_out;
			}
		}
	}

	if (flag == F2FS_GET_BLOCK_PRE_AIO)
		goto skip;
@@ -1032,6 +1074,16 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
	else if (dn.ofs_in_node < end_offset)
		goto next_block;

	if (flag == F2FS_GET_BLOCK_PRECACHE) {
		if (map->m_flags & F2FS_MAP_MAPPED) {
			unsigned int ofs = start_pgofs - map->m_lblk;

			f2fs_update_extent_cache_range(&dn,
				start_pgofs, map->m_pblk + ofs,
				map->m_len - ofs);
		}
	}

	f2fs_put_dnode(&dn);

	if (create) {
@@ -1041,6 +1093,17 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
	goto next_dnode;

sync_out:
	if (flag == F2FS_GET_BLOCK_PRECACHE) {
		if (map->m_flags & F2FS_MAP_MAPPED) {
			unsigned int ofs = start_pgofs - map->m_lblk;

			f2fs_update_extent_cache_range(&dn,
				start_pgofs, map->m_pblk + ofs,
				map->m_len - ofs);
		}
		if (map->m_next_extent)
			*map->m_next_extent = pgofs + 1;
	}
	f2fs_put_dnode(&dn);
unlock_out:
	if (create) {
@@ -1054,7 +1117,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,

static int __get_data_block(struct inode *inode, sector_t iblock,
			struct buffer_head *bh, int create, int flag,
			pgoff_t *next_pgofs)
			pgoff_t *next_pgofs, int seg_type)
{
	struct f2fs_map_blocks map;
	int err;
@@ -1062,6 +1125,8 @@ static int __get_data_block(struct inode *inode, sector_t iblock,
	map.m_lblk = iblock;
	map.m_len = bh->b_size >> inode->i_blkbits;
	map.m_next_pgofs = next_pgofs;
	map.m_next_extent = NULL;
	map.m_seg_type = seg_type;

	err = f2fs_map_blocks(inode, &map, create, flag);
	if (!err) {
@@ -1077,14 +1142,17 @@ static int get_data_block(struct inode *inode, sector_t iblock,
			pgoff_t *next_pgofs)
{
	return __get_data_block(inode, iblock, bh_result, create,
							flag, next_pgofs);
							flag, next_pgofs,
							NO_CHECK_TYPE);
}

static int get_data_block_dio(struct inode *inode, sector_t iblock,
			struct buffer_head *bh_result, int create)
{
	return __get_data_block(inode, iblock, bh_result, create,
						F2FS_GET_BLOCK_DEFAULT, NULL);
						F2FS_GET_BLOCK_DEFAULT, NULL,
						rw_hint_to_seg_type(
							inode->i_write_hint));
}

static int get_data_block_bmap(struct inode *inode, sector_t iblock,
@@ -1095,7 +1163,8 @@ static int get_data_block_bmap(struct inode *inode, sector_t iblock,
		return -EFBIG;

	return __get_data_block(inode, iblock, bh_result, create,
						F2FS_GET_BLOCK_BMAP, NULL);
						F2FS_GET_BLOCK_BMAP, NULL,
						NO_CHECK_TYPE);
}

static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
@@ -1108,6 +1177,68 @@ static inline loff_t blk_to_logical(struct inode *inode, sector_t blk)
	return (blk << inode->i_blkbits);
}

static int f2fs_xattr_fiemap(struct inode *inode,
				struct fiemap_extent_info *fieinfo)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct page *page;
	struct node_info ni;
	__u64 phys = 0, len;
	__u32 flags;
	nid_t xnid = F2FS_I(inode)->i_xattr_nid;
	int err = 0;

	if (f2fs_has_inline_xattr(inode)) {
		int offset;

		page = f2fs_grab_cache_page(NODE_MAPPING(sbi),
						inode->i_ino, false);
		if (!page)
			return -ENOMEM;

		get_node_info(sbi, inode->i_ino, &ni);

		phys = (__u64)blk_to_logical(inode, ni.blk_addr);
		offset = offsetof(struct f2fs_inode, i_addr) +
					sizeof(__le32) * (DEF_ADDRS_PER_INODE -
					get_inline_xattr_addrs(inode));

		phys += offset;
		len = inline_xattr_size(inode);

		f2fs_put_page(page, 1);

		flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED;

		if (!xnid)
			flags |= FIEMAP_EXTENT_LAST;

		err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);
		if (err || err == 1)
			return err;
	}

	if (xnid) {
		page = f2fs_grab_cache_page(NODE_MAPPING(sbi), xnid, false);
		if (!page)
			return -ENOMEM;

		get_node_info(sbi, xnid, &ni);

		phys = (__u64)blk_to_logical(inode, ni.blk_addr);
		len = inode->i_sb->s_blocksize;

		f2fs_put_page(page, 1);

		flags = FIEMAP_EXTENT_LAST;
	}

	if (phys)
		err = fiemap_fill_next_extent(fieinfo, 0, phys, len, flags);

	return (err < 0 ? err : 0);
}

int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
		u64 start, u64 len)
{
@@ -1118,18 +1249,29 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
	u32 flags = 0;
	int ret = 0;

	ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
	if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) {
		ret = f2fs_precache_extents(inode);
		if (ret)
			return ret;
	}

	ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR);
	if (ret)
		return ret;

	inode_lock(inode);

	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
		ret = f2fs_xattr_fiemap(inode, fieinfo);
		goto out;
	}

	if (f2fs_has_inline_data(inode)) {
		ret = f2fs_inline_data_fiemap(inode, fieinfo, start, len);
		if (ret != -EAGAIN)
			return ret;
			goto out;
	}

	inode_lock(inode);

	if (logical_to_blk(inode, len) == 0)
		len = blk_to_logical(inode, 1);

@@ -1199,7 +1341,6 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
			unsigned nr_pages)
{
	struct bio *bio = NULL;
	unsigned page_idx;
	sector_t last_block_in_bio = 0;
	struct inode *inode = mapping->host;
	const unsigned blkbits = inode->i_blkbits;
@@ -1215,9 +1356,10 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
	map.m_len = 0;
	map.m_flags = 0;
	map.m_next_pgofs = NULL;
	map.m_next_extent = NULL;
	map.m_seg_type = NO_CHECK_TYPE;

	for (page_idx = 0; nr_pages; page_idx++, nr_pages--) {

	for (; nr_pages; nr_pages--) {
		if (pages) {
			page = list_last_entry(pages, struct page, lru);

@@ -1377,18 +1519,79 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
	return PTR_ERR(fio->encrypted_page);
}

static inline bool need_inplace_update(struct f2fs_io_info *fio)
static inline bool check_inplace_update_policy(struct inode *inode,
				struct f2fs_io_info *fio)
{
	struct inode *inode = fio->page->mapping->host;
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	unsigned int policy = SM_I(sbi)->ipu_policy;

	if (policy & (0x1 << F2FS_IPU_FORCE))
		return true;
	if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi))
		return true;
	if (policy & (0x1 << F2FS_IPU_UTIL) &&
			utilization(sbi) > SM_I(sbi)->min_ipu_util)
		return true;
	if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && need_SSR(sbi) &&
			utilization(sbi) > SM_I(sbi)->min_ipu_util)
		return true;

	/*
	 * IPU for rewrite async pages
	 */
	if (policy & (0x1 << F2FS_IPU_ASYNC) &&
			fio && fio->op == REQ_OP_WRITE &&
			!(fio->op_flags & REQ_SYNC) &&
			!f2fs_encrypted_inode(inode))
		return true;

	/* this is only set during fdatasync */
	if (policy & (0x1 << F2FS_IPU_FSYNC) &&
			is_inode_flag_set(inode, FI_NEED_IPU))
		return true;

	if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode))
	return false;
}

bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio)
{
	if (f2fs_is_pinned_file(inode))
		return true;

	/* if this is cold file, we should overwrite to avoid fragmentation */
	if (file_is_cold(inode))
		return true;

	return check_inplace_update_policy(inode, fio);
}

bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);

	if (test_opt(sbi, LFS))
		return true;
	if (S_ISDIR(inode->i_mode))
		return true;
	if (f2fs_is_atomic_file(inode))
		return true;
	if (fio) {
		if (is_cold_data(fio->page))
		return false;
			return true;
		if (IS_ATOMIC_WRITTEN_PAGE(fio->page))
			return true;
	}
	return false;
}

static inline bool need_inplace_update(struct f2fs_io_info *fio)
{
	struct inode *inode = fio->page->mapping->host;

	if (should_update_outplace(inode, fio))
		return false;

	return need_inplace_update_policy(inode, fio);
	return should_update_inplace(inode, fio);
}

static inline bool valid_ipu_blkaddr(struct f2fs_io_info *fio)
@@ -1509,10 +1712,17 @@ static int __write_data_page(struct page *page, bool *submitted,
		.submitted = false,
		.need_lock = LOCK_RETRY,
		.io_type = io_type,
		.io_wbc = wbc,
	};

	trace_f2fs_writepage(page, DATA);

	/* we should bypass data pages to proceed the kworkder jobs */
	if (unlikely(f2fs_cp_error(sbi))) {
		mapping_set_error(page->mapping, -EIO);
		goto out;
	}

	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
		goto redirty_out;

@@ -1537,12 +1747,6 @@ static int __write_data_page(struct page *page, bool *submitted,
			available_free_memory(sbi, BASE_CHECK))))
		goto redirty_out;

	/* we should bypass data pages to proceed the kworkder jobs */
	if (unlikely(f2fs_cp_error(sbi))) {
		mapping_set_error(page->mapping, -EIO);
		goto out;
	}

	/* Dentry blocks are controlled by checkpoint */
	if (S_ISDIR(inode->i_mode)) {
		fio.need_lock = LOCK_DONE;
@@ -1572,10 +1776,14 @@ static int __write_data_page(struct page *page, bool *submitted,
		}
	}

	if (err) {
		file_set_keep_isize(inode);
	} else {
		down_write(&F2FS_I(inode)->i_sem);
		if (F2FS_I(inode)->last_disk_size < psize)
			F2FS_I(inode)->last_disk_size = psize;
		up_write(&F2FS_I(inode)->i_sem);
	}

done:
	if (err && err != -ENOENT)
@@ -1939,7 +2147,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct page *page = NULL;
	pgoff_t index = ((unsigned long long) pos) >> PAGE_SHIFT;
	bool need_balance = false;
	bool need_balance = false, drop_atomic = false;
	block_t blkaddr = NULL_ADDR;
	int err = 0;

@@ -1958,6 +2166,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	if (f2fs_is_atomic_file(inode) &&
			!available_free_memory(sbi, INMEM_PAGES)) {
		err = -ENOMEM;
		drop_atomic = true;
		goto fail;
	}

@@ -2038,7 +2247,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
fail:
	f2fs_put_page(page, 1);
	f2fs_write_failed(mapping, pos + len);
	if (f2fs_is_atomic_file(inode))
	if (drop_atomic)
		drop_inmem_pages_all(sbi);
	return err;
}
+2 −10
Original line number Diff line number Diff line
@@ -49,14 +49,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
	si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
	si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
	si->ndirty_files = sbi->ndirty_inode[FILE_INODE];

	si->nquota_files = 0;
	if (f2fs_sb_has_quota_ino(sbi->sb)) {
		for (i = 0; i < MAXQUOTAS; i++) {
			if (f2fs_qf_ino(sbi->sb, i))
				si->nquota_files++;
		}
	}
	si->nquota_files = sbi->nquota_files;
	si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
	si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
	si->aw_cnt = atomic_read(&sbi->aw_cnt);
@@ -186,7 +179,6 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
	si->base_mem += sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
	si->base_mem += 2 * sizeof(struct f2fs_inode_info);
	si->base_mem += sizeof(*sbi->ckpt);
	si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE;

	/* build sm */
	si->base_mem += sizeof(struct f2fs_sm_info);
@@ -447,7 +439,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
	struct f2fs_stat_info *si;

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

Loading