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

Commit 64b2d1fb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "In this round, there is no special interesting feature, but we've
  investigated a couple of tuning points with respect to the I/O flow.
  Several major bug fixes and a bunch of clean-ups also have been made.

  This patch-set includes the following major enhancement patches:
   - enhance wait_on_page_writeback
   - support SEEK_DATA and SEEK_HOLE
   - enhance readahead flows
   - enhance IO flushes
   - support fiemap
   - add some tracepoints

  The other bug fixes are as follows:
   - fix to support a large volume > 2TB correctly
   - recovery bug fix wrt fallocated space
   - fix recursive lock on xattr operations
   - fix some cases on the remount flow

  And, there are a bunch of cleanups"

* tag 'for-f2fs-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (52 commits)
  f2fs: support f2fs_fiemap
  f2fs: avoid not to call remove_dirty_inode
  f2fs: recover fallocated space
  f2fs: fix to recover data written by dio
  f2fs: large volume support
  f2fs: avoid crash when trace f2fs_submit_page_mbio event in ra_sum_pages
  f2fs: avoid overflow when large directory feathure is enabled
  f2fs: fix recursive lock by f2fs_setxattr
  MAINTAINERS: add a co-maintainer from samsung for F2FS
  MAINTAINERS: change the email address for f2fs
  f2fs: use inode_init_owner() to simplify codes
  f2fs: avoid to use slab memory in f2fs_issue_flush for efficiency
  f2fs: add a tracepoint for f2fs_read_data_page
  f2fs: add a tracepoint for f2fs_write_{meta,node,data}_pages
  f2fs: add a tracepoint for f2fs_write_{meta,node,data}_page
  f2fs: add a tracepoint for f2fs_write_end
  f2fs: add a tracepoint for f2fs_write_begin
  f2fs: fix checkpatch warning
  f2fs: deactivate inode page if the inode is evicted
  f2fs: decrease the lock granularity during write_begin
  ...
parents b1cce803 9ab70134
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -462,9 +462,9 @@ The number of blocks and buckets are determined by,
                            `- 4, Otherwise
                            `- 4, Otherwise


                             ,- 2^(n + dir_level),
                             ,- 2^(n + dir_level),
			     |            if n < MAX_DIR_HASH_DEPTH / 2,
			     |        if n + dir_level < MAX_DIR_HASH_DEPTH / 2,
  # of buckets in level #n = |
  # of buckets in level #n = |
                             `- 2^((MAX_DIR_HASH_DEPTH / 2 + dir_level) - 1),
                             `- 2^((MAX_DIR_HASH_DEPTH / 2) - 1),
			              Otherwise
			              Otherwise


When F2FS finds a file name in a directory, at first a hash value of the file
When F2FS finds a file name in a directory, at first a hash value of the file
+2 −1
Original line number Original line Diff line number Diff line
@@ -3792,7 +3792,8 @@ F: fs/fscache/
F:	include/linux/fscache*.h
F:	include/linux/fscache*.h


F2FS FILE SYSTEM
F2FS FILE SYSTEM
M:	Jaegeuk Kim <jaegeuk.kim@samsung.com>
M:	Jaegeuk Kim <jaegeuk@kernel.org>
M:	Changman Lee <cm224.lee@samsung.com>
L:	linux-f2fs-devel@lists.sourceforge.net
L:	linux-f2fs-devel@lists.sourceforge.net
W:	http://en.wikipedia.org/wiki/F2FS
W:	http://en.wikipedia.org/wiki/F2FS
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
+1 −1
Original line number Original line Diff line number Diff line
@@ -240,7 +240,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
		}
		}
	}
	}


	error = f2fs_setxattr(inode, name_index, "", value, size, ipage);
	error = f2fs_setxattr(inode, name_index, "", value, size, ipage, 0);


	kfree(value);
	kfree(value);
	if (!error)
	if (!error)
+67 −51
Original line number Original line Diff line number Diff line
@@ -33,12 +33,12 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
	struct address_space *mapping = META_MAPPING(sbi);
	struct address_space *mapping = META_MAPPING(sbi);
	struct page *page = NULL;
	struct page *page = NULL;
repeat:
repeat:
	page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
	page = grab_cache_page(mapping, index);
	if (!page) {
	if (!page) {
		cond_resched();
		cond_resched();
		goto repeat;
		goto repeat;
	}
	}

	f2fs_wait_on_page_writeback(page, META);
	SetPageUptodate(page);
	SetPageUptodate(page);
	return page;
	return page;
}
}
@@ -72,7 +72,7 @@ out:
	return page;
	return page;
}
}


inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
static inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
{
{
	switch (type) {
	switch (type) {
	case META_NAT:
	case META_NAT:
@@ -154,6 +154,8 @@ static int f2fs_write_meta_page(struct page *page,
	struct inode *inode = page->mapping->host;
	struct inode *inode = page->mapping->host;
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);


	trace_f2fs_writepage(page, META);

	if (unlikely(sbi->por_doing))
	if (unlikely(sbi->por_doing))
		goto redirty_out;
		goto redirty_out;
	if (wbc->for_reclaim)
	if (wbc->for_reclaim)
@@ -171,10 +173,7 @@ no_write:
	return 0;
	return 0;


redirty_out:
redirty_out:
	dec_page_count(sbi, F2FS_DIRTY_META);
	redirty_page_for_writepage(wbc, page);
	wbc->pages_skipped++;
	account_page_redirty(page);
	set_page_dirty(page);
	return AOP_WRITEPAGE_ACTIVATE;
	return AOP_WRITEPAGE_ACTIVATE;
}
}


@@ -184,6 +183,8 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
	struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
	struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
	long diff, written;
	long diff, written;


	trace_f2fs_writepages(mapping->host, wbc, META);

	/* collect a number of dirty meta pages and write together */
	/* collect a number of dirty meta pages and write together */
	if (wbc->for_kupdate ||
	if (wbc->for_kupdate ||
		get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
		get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
@@ -367,7 +368,9 @@ void recover_orphan_inodes(struct f2fs_sb_info *sbi)
		return;
		return;


	sbi->por_doing = true;
	sbi->por_doing = true;
	start_blk = __start_cp_addr(sbi) + 1;

	start_blk = __start_cp_addr(sbi) + 1 +
		le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
	orphan_blkaddr = __start_sum_addr(sbi) - 1;
	orphan_blkaddr = __start_sum_addr(sbi) - 1;


	ra_meta_pages(sbi, start_blk, orphan_blkaddr, META_CP);
	ra_meta_pages(sbi, start_blk, orphan_blkaddr, META_CP);
@@ -508,8 +511,11 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
	unsigned long blk_size = sbi->blocksize;
	unsigned long blk_size = sbi->blocksize;
	unsigned long long cp1_version = 0, cp2_version = 0;
	unsigned long long cp1_version = 0, cp2_version = 0;
	unsigned long long cp_start_blk_no;
	unsigned long long cp_start_blk_no;
	unsigned int cp_blks = 1 + le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
	block_t cp_blk_no;
	int i;


	sbi->ckpt = kzalloc(blk_size, GFP_KERNEL);
	sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL);
	if (!sbi->ckpt)
	if (!sbi->ckpt)
		return -ENOMEM;
		return -ENOMEM;
	/*
	/*
@@ -540,6 +546,23 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
	cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
	cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
	memcpy(sbi->ckpt, cp_block, blk_size);
	memcpy(sbi->ckpt, cp_block, blk_size);


	if (cp_blks <= 1)
		goto done;

	cp_blk_no = le32_to_cpu(fsb->cp_blkaddr);
	if (cur_page == cp2)
		cp_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg);

	for (i = 1; i < cp_blks; i++) {
		void *sit_bitmap_ptr;
		unsigned char *ckpt = (unsigned char *)sbi->ckpt;

		cur_page = get_meta_page(sbi, cp_blk_no + i);
		sit_bitmap_ptr = page_address(cur_page);
		memcpy(ckpt + i * blk_size, sit_bitmap_ptr, blk_size);
		f2fs_put_page(cur_page, 1);
	}
done:
	f2fs_put_page(cp1, 1);
	f2fs_put_page(cp1, 1);
	f2fs_put_page(cp2, 1);
	f2fs_put_page(cp2, 1);
	return 0;
	return 0;
@@ -552,14 +575,13 @@ fail_no_cp:
static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
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_SB(inode->i_sb);
	struct list_head *head = &sbi->dir_inode_list;
	struct dir_inode_entry *entry;


	list_for_each_entry(entry, head, list)
	if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
		if (unlikely(entry->inode == inode))
		return -EEXIST;
		return -EEXIST;


	list_add_tail(&new->list, head);
	set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
	F2FS_I(inode)->dirty_dir = new;
	list_add_tail(&new->list, &sbi->dir_inode_list);
	stat_inc_dirty_dir(sbi);
	stat_inc_dirty_dir(sbi);
	return 0;
	return 0;
}
}
@@ -608,31 +630,26 @@ void add_dirty_dir_inode(struct inode *inode)
void remove_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_SB(inode->i_sb);
	struct list_head *head;
	struct dir_inode_entry *entry;
	struct dir_inode_entry *entry;


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


	spin_lock(&sbi->dir_inode_lock);
	spin_lock(&sbi->dir_inode_lock);
	if (get_dirty_dents(inode)) {
	if (get_dirty_dents(inode) ||
			!is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) {
		spin_unlock(&sbi->dir_inode_lock);
		spin_unlock(&sbi->dir_inode_lock);
		return;
		return;
	}
	}


	head = &sbi->dir_inode_list;
	entry = F2FS_I(inode)->dirty_dir;
	list_for_each_entry(entry, head, list) {
		if (entry->inode == inode) {
	list_del(&entry->list);
	list_del(&entry->list);
	F2FS_I(inode)->dirty_dir = NULL;
	clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
	stat_dec_dirty_dir(sbi);
	stat_dec_dirty_dir(sbi);
	spin_unlock(&sbi->dir_inode_lock);
	spin_unlock(&sbi->dir_inode_lock);
	kmem_cache_free(inode_entry_slab, entry);
	kmem_cache_free(inode_entry_slab, entry);
			goto done;
		}
	}
	spin_unlock(&sbi->dir_inode_lock);


done:
	/* Only from the recovery routine */
	/* Only from the recovery routine */
	if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
	if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
		clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
		clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
@@ -640,26 +657,6 @@ done:
	}
	}
}
}


struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
{

	struct list_head *head;
	struct inode *inode = NULL;
	struct dir_inode_entry *entry;

	spin_lock(&sbi->dir_inode_lock);

	head = &sbi->dir_inode_list;
	list_for_each_entry(entry, head, list) {
		if (entry->inode->i_ino == ino) {
			inode = entry->inode;
			break;
		}
	}
	spin_unlock(&sbi->dir_inode_lock);
	return inode;
}

void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
{
{
	struct list_head *head;
	struct list_head *head;
@@ -758,6 +755,13 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
	__u32 crc32 = 0;
	__u32 crc32 = 0;
	void *kaddr;
	void *kaddr;
	int i;
	int i;
	int cp_payload_blks = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);

	/*
	 * This avoids to conduct wrong roll-forward operations and uses
	 * metapages, so should be called prior to sync_meta_pages below.
	 */
	discard_next_dnode(sbi);


	/* Flush all the NAT/SIT pages */
	/* Flush all the NAT/SIT pages */
	while (get_pages(sbi, F2FS_DIRTY_META))
	while (get_pages(sbi, F2FS_DIRTY_META))
@@ -802,16 +806,19 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)


	orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1)
	orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1)
					/ F2FS_ORPHANS_PER_BLOCK;
					/ F2FS_ORPHANS_PER_BLOCK;
	ckpt->cp_pack_start_sum = cpu_to_le32(1 + orphan_blocks);
	ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
			orphan_blocks);


	if (is_umount) {
	if (is_umount) {
		set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
		set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
		ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
		ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
			data_sum_blocks + orphan_blocks + NR_CURSEG_NODE_TYPE);
				cp_payload_blks + data_sum_blocks +
				orphan_blocks + NR_CURSEG_NODE_TYPE);
	} else {
	} else {
		clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
		clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
		ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
		ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
			data_sum_blocks + orphan_blocks);
				cp_payload_blks + data_sum_blocks +
				orphan_blocks);
	}
	}


	if (sbi->n_orphans)
	if (sbi->n_orphans)
@@ -837,6 +844,15 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
	set_page_dirty(cp_page);
	set_page_dirty(cp_page);
	f2fs_put_page(cp_page, 1);
	f2fs_put_page(cp_page, 1);


	for (i = 1; i < 1 + cp_payload_blks; i++) {
		cp_page = grab_meta_page(sbi, start_blk++);
		kaddr = page_address(cp_page);
		memcpy(kaddr, (char *)ckpt + i * F2FS_BLKSIZE,
				(1 << sbi->log_blocksize));
		set_page_dirty(cp_page);
		f2fs_put_page(cp_page, 1);
	}

	if (sbi->n_orphans) {
	if (sbi->n_orphans) {
		write_orphan_inodes(sbi, start_blk);
		write_orphan_inodes(sbi, start_blk);
		start_blk += orphan_blocks;
		start_blk += orphan_blocks;
+48 −15
Original line number Original line Diff line number Diff line
@@ -417,7 +417,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync)
	if (unlikely(dn.data_blkaddr == NEW_ADDR))
	if (unlikely(dn.data_blkaddr == NEW_ADDR))
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);


	page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
	page = grab_cache_page(mapping, index);
	if (!page)
	if (!page)
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);


@@ -455,7 +455,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
	int err;
	int err;


repeat:
repeat:
	page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
	page = grab_cache_page(mapping, index);
	if (!page)
	if (!page)
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);


@@ -652,8 +652,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
		goto put_out;
		goto put_out;
	}
	}


	end_offset = IS_INODE(dn.node_page) ?
	end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
			ADDRS_PER_INODE(F2FS_I(inode)) : ADDRS_PER_BLOCK;
	bh_result->b_size = (((size_t)1) << blkbits);
	bh_result->b_size = (((size_t)1) << blkbits);
	dn.ofs_in_node++;
	dn.ofs_in_node++;
	pgofs++;
	pgofs++;
@@ -675,8 +674,7 @@ get_next:
		if (dn.data_blkaddr == NEW_ADDR)
		if (dn.data_blkaddr == NEW_ADDR)
			goto put_out;
			goto put_out;


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


	if (maxblocks > (bh_result->b_size >> blkbits)) {
	if (maxblocks > (bh_result->b_size >> blkbits)) {
@@ -710,11 +708,19 @@ out:
	return err;
	return err;
}
}


int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
		u64 start, u64 len)
{
	return generic_block_fiemap(inode, fieinfo, start, len, get_data_block);
}

static int f2fs_read_data_page(struct file *file, struct page *page)
static int f2fs_read_data_page(struct file *file, struct page *page)
{
{
	struct inode *inode = page->mapping->host;
	struct inode *inode = page->mapping->host;
	int ret;
	int ret;


	trace_f2fs_readpage(page, DATA);

	/* If the file has inline data, try to read it directlly */
	/* If the file has inline data, try to read it directlly */
	if (f2fs_has_inline_data(inode))
	if (f2fs_has_inline_data(inode))
		ret = f2fs_read_inline_data(inode, page);
		ret = f2fs_read_inline_data(inode, page);
@@ -790,6 +796,8 @@ static int f2fs_write_data_page(struct page *page,
		.rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE,
		.rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE,
	};
	};


	trace_f2fs_writepage(page, DATA);

	if (page->index < end_index)
	if (page->index < end_index)
		goto write;
		goto write;


@@ -798,10 +806,8 @@ static int f2fs_write_data_page(struct page *page,
	 * this page does not have to be written to disk.
	 * this page does not have to be written to disk.
	 */
	 */
	offset = i_size & (PAGE_CACHE_SIZE - 1);
	offset = i_size & (PAGE_CACHE_SIZE - 1);
	if ((page->index >= end_index + 1) || !offset) {
	if ((page->index >= end_index + 1) || !offset)
		inode_dec_dirty_dents(inode);
		goto out;
		goto out;
	}


	zero_user_segment(page, offset, PAGE_CACHE_SIZE);
	zero_user_segment(page, offset, PAGE_CACHE_SIZE);
write:
write:
@@ -810,7 +816,6 @@ write:


	/* Dentry blocks are controlled by checkpoint */
	/* Dentry blocks are controlled by checkpoint */
	if (S_ISDIR(inode->i_mode)) {
	if (S_ISDIR(inode->i_mode)) {
		inode_dec_dirty_dents(inode);
		err = do_write_data_page(page, &fio);
		err = do_write_data_page(page, &fio);
		goto done;
		goto done;
	}
	}
@@ -832,15 +837,16 @@ done:


	clear_cold_data(page);
	clear_cold_data(page);
out:
out:
	inode_dec_dirty_dents(inode);
	unlock_page(page);
	unlock_page(page);
	if (need_balance_fs)
	if (need_balance_fs)
		f2fs_balance_fs(sbi);
		f2fs_balance_fs(sbi);
	if (wbc->for_reclaim)
		f2fs_submit_merged_bio(sbi, DATA, WRITE);
	return 0;
	return 0;


redirty_out:
redirty_out:
	wbc->pages_skipped++;
	redirty_page_for_writepage(wbc, page);
	account_page_redirty(page);
	set_page_dirty(page);
	return AOP_WRITEPAGE_ACTIVATE;
	return AOP_WRITEPAGE_ACTIVATE;
}
}


@@ -862,12 +868,15 @@ static int f2fs_write_data_pages(struct address_space *mapping,
	int ret;
	int ret;
	long diff;
	long diff;


	trace_f2fs_writepages(mapping->host, wbc, DATA);

	/* deal with chardevs and other special file */
	/* deal with chardevs and other special file */
	if (!mapping->a_ops->writepage)
	if (!mapping->a_ops->writepage)
		return 0;
		return 0;


	if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
	if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
			get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA))
			get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA) &&
			available_free_memory(sbi, DIRTY_DENTS))
		goto skip_write;
		goto skip_write;


	diff = nr_pages_to_write(sbi, DATA, wbc);
	diff = nr_pages_to_write(sbi, DATA, wbc);
@@ -903,6 +912,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	struct dnode_of_data dn;
	struct dnode_of_data dn;
	int err = 0;
	int err = 0;


	trace_f2fs_write_begin(inode, pos, len, flags);

	f2fs_balance_fs(sbi);
	f2fs_balance_fs(sbi);
repeat:
repeat:
	err = f2fs_convert_inline_data(inode, pos + len);
	err = f2fs_convert_inline_data(inode, pos + len);
@@ -912,6 +923,10 @@ repeat:
	page = grab_cache_page_write_begin(mapping, index, flags);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
	if (!page)
		return -ENOMEM;
		return -ENOMEM;

	/* to avoid latency during memory pressure */
	unlock_page(page);

	*pagep = page;
	*pagep = page;


	if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
	if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
@@ -923,10 +938,18 @@ repeat:
	f2fs_unlock_op(sbi);
	f2fs_unlock_op(sbi);


	if (err) {
	if (err) {
		f2fs_put_page(page, 1);
		f2fs_put_page(page, 0);
		return err;
		return err;
	}
	}
inline_data:
inline_data:
	lock_page(page);
	if (unlikely(page->mapping != mapping)) {
		f2fs_put_page(page, 1);
		goto repeat;
	}

	f2fs_wait_on_page_writeback(page, DATA);

	if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
	if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
		return 0;
		return 0;


@@ -978,6 +1001,8 @@ static int f2fs_write_end(struct file *file,
{
{
	struct inode *inode = page->mapping->host;
	struct inode *inode = page->mapping->host;


	trace_f2fs_write_end(inode, pos, len, copied);

	SetPageUptodate(page);
	SetPageUptodate(page);
	set_page_dirty(page);
	set_page_dirty(page);


@@ -1022,6 +1047,9 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
	if (check_direct_IO(inode, rw, iov, offset, nr_segs))
	if (check_direct_IO(inode, rw, iov, offset, nr_segs))
		return 0;
		return 0;


	/* clear fsync mark to recover these blocks */
	fsync_mark_clear(F2FS_SB(inode->i_sb), inode->i_ino);

	return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
	return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
							get_data_block);
							get_data_block);
}
}
@@ -1061,6 +1089,11 @@ static int f2fs_set_data_page_dirty(struct page *page)


static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
{
{
	struct inode *inode = mapping->host;

	if (f2fs_has_inline_data(inode))
		return 0;

	return generic_block_bmap(mapping, block, get_data_block);
	return generic_block_bmap(mapping, block, get_data_block);
}
}


Loading