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

Commit 4fc29c1a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "The major change in this version is mitigating cpu overheads on write
  paths by replacing redundant inode page updates with mark_inode_dirty
  calls.  And we tried to reduce lock contentions as well to improve
  filesystem scalability.  Other feature is setting F2FS automatically
  when detecting host-managed SMR.

  Enhancements:
   - ioctl to move a range of data between files
   - inject orphan inode errors
   - avoid flush commands congestion
   - support lazytime

  Bug fixes:
   - return proper results for some dentry operations
   - fix deadlock in add_link failure
   - disable extent_cache for fcollapse/finsert"

* tag 'for-f2fs-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (68 commits)
  f2fs: clean up coding style and redundancy
  f2fs: get victim segment again after new cp
  f2fs: handle error case with f2fs_bug_on
  f2fs: avoid data race when deciding checkpoin in f2fs_sync_file
  f2fs: support an ioctl to move a range of data blocks
  f2fs: fix to report error number of f2fs_find_entry
  f2fs: avoid memory allocation failure due to a long length
  f2fs: reset default idle interval value
  f2fs: use blk_plug in all the possible paths
  f2fs: fix to avoid data update racing between GC and DIO
  f2fs: add maximum prefree segments
  f2fs: disable extent_cache for fcollapse/finsert inodes
  f2fs: refactor __exchange_data_block for speed up
  f2fs: fix ERR_PTR returned by bio
  f2fs: avoid mark_inode_dirty
  f2fs: move i_size_write in f2fs_write_end
  f2fs: fix to avoid redundant discard during fstrim
  f2fs: avoid mismatching block range for discard
  f2fs: fix incorrect f_bfree calculation in ->statfs
  f2fs: use percpu_rw_semaphore
  ...
parents 0e6acf02 5302fb00
Loading
Loading
Loading
Loading
+6 −1
Original line number Original line Diff line number Diff line
@@ -109,7 +109,9 @@ background_gc=%s Turn on/off cleaning operations, namely garbage
disable_roll_forward   Disable the roll-forward recovery routine
disable_roll_forward   Disable the roll-forward recovery routine
norecovery             Disable the roll-forward recovery routine, mounted read-
norecovery             Disable the roll-forward recovery routine, mounted read-
                       only (i.e., -o ro,disable_roll_forward)
                       only (i.e., -o ro,disable_roll_forward)
discard                Issue discard/TRIM commands when a segment is cleaned.
discard/nodiscard      Enable/disable real-time discard in f2fs, if discard is
                       enabled, f2fs will issue discard/TRIM commands when a
		       segment is cleaned.
no_heap                Disable heap-style segment allocation which finds free
no_heap                Disable heap-style segment allocation which finds free
                       segments for data from the beginning of main area, while
                       segments for data from the beginning of main area, while
		       for node from the end of main area.
		       for node from the end of main area.
@@ -151,6 +153,9 @@ noinline_data Disable the inline data feature, inline data feature is
                       enabled by default.
                       enabled by default.
data_flush             Enable data flushing before checkpoint in order to
data_flush             Enable data flushing before checkpoint in order to
                       persist data of regular and symlink.
                       persist data of regular and symlink.
mode=%s                Control block allocation mode which supports "adaptive"
                       and "lfs". In "lfs" mode, there should be no random
                       writes towards main area.


================================================================================
================================================================================
DEBUGFS ENTRIES
DEBUGFS ENTRIES
+5 −4
Original line number Original line Diff line number Diff line
@@ -201,7 +201,6 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
static int __f2fs_set_acl(struct inode *inode, int type,
static int __f2fs_set_acl(struct inode *inode, int type,
			struct posix_acl *acl, struct page *ipage)
			struct posix_acl *acl, struct page *ipage)
{
{
	struct f2fs_inode_info *fi = F2FS_I(inode);
	int name_index;
	int name_index;
	void *value = NULL;
	void *value = NULL;
	size_t size = 0;
	size_t size = 0;
@@ -214,7 +213,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
			error = posix_acl_equiv_mode(acl, &inode->i_mode);
			error = posix_acl_equiv_mode(acl, &inode->i_mode);
			if (error < 0)
			if (error < 0)
				return error;
				return error;
			set_acl_inode(fi, inode->i_mode);
			set_acl_inode(inode, inode->i_mode);
			if (error == 0)
			if (error == 0)
				acl = NULL;
				acl = NULL;
		}
		}
@@ -233,7 +232,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
	if (acl) {
	if (acl) {
		value = f2fs_acl_to_disk(acl, &size);
		value = f2fs_acl_to_disk(acl, &size);
		if (IS_ERR(value)) {
		if (IS_ERR(value)) {
			clear_inode_flag(fi, FI_ACL_MODE);
			clear_inode_flag(inode, FI_ACL_MODE);
			return (int)PTR_ERR(value);
			return (int)PTR_ERR(value);
		}
		}
	}
	}
@@ -244,7 +243,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
	if (!error)
	if (!error)
		set_cached_acl(inode, type, acl);
		set_cached_acl(inode, type, acl);


	clear_inode_flag(fi, FI_ACL_MODE);
	clear_inode_flag(inode, FI_ACL_MODE);
	return error;
	return error;
}
}


@@ -385,6 +384,8 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
	if (error)
	if (error)
		return error;
		return error;


	f2fs_mark_inode_dirty_sync(inode);

	if (default_acl) {
	if (default_acl) {
		error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
		error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
				       ipage);
				       ipage);
+1 −1
Original line number Original line Diff line number Diff line
@@ -37,7 +37,7 @@ struct f2fs_acl_header {
#ifdef CONFIG_F2FS_FS_POSIX_ACL
#ifdef CONFIG_F2FS_FS_POSIX_ACL


extern struct posix_acl *f2fs_get_acl(struct inode *, int);
extern struct posix_acl *f2fs_get_acl(struct inode *, int);
extern int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
extern int f2fs_set_acl(struct inode *, struct posix_acl *, int);
extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
							struct page *);
							struct page *);
#else
#else
+60 −20
Original line number Original line Diff line number Diff line
@@ -48,6 +48,7 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
		goto repeat;
		goto repeat;
	}
	}
	f2fs_wait_on_page_writeback(page, META, true);
	f2fs_wait_on_page_writeback(page, META, true);
	if (!PageUptodate(page))
		SetPageUptodate(page);
		SetPageUptodate(page);
	return page;
	return page;
}
}
@@ -266,6 +267,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
				struct writeback_control *wbc)
				struct writeback_control *wbc)
{
{
	struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
	struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
	struct blk_plug plug;
	long diff, written;
	long diff, written;


	/* collect a number of dirty meta pages and write together */
	/* collect a number of dirty meta pages and write together */
@@ -278,7 +280,9 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
	/* if mounting is failed, skip writing node pages */
	/* if mounting is failed, skip writing node pages */
	mutex_lock(&sbi->cp_mutex);
	mutex_lock(&sbi->cp_mutex);
	diff = nr_pages_to_write(sbi, META, wbc);
	diff = nr_pages_to_write(sbi, META, wbc);
	blk_start_plug(&plug);
	written = sync_meta_pages(sbi, META, wbc->nr_to_write);
	written = sync_meta_pages(sbi, META, wbc->nr_to_write);
	blk_finish_plug(&plug);
	mutex_unlock(&sbi->cp_mutex);
	mutex_unlock(&sbi->cp_mutex);
	wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
	wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
	return 0;
	return 0;
@@ -366,9 +370,10 @@ static int f2fs_set_meta_page_dirty(struct page *page)
{
{
	trace_f2fs_set_page_dirty(page, META);
	trace_f2fs_set_page_dirty(page, META);


	if (!PageUptodate(page))
		SetPageUptodate(page);
		SetPageUptodate(page);
	if (!PageDirty(page)) {
	if (!PageDirty(page)) {
		__set_page_dirty_nobuffers(page);
		f2fs_set_page_dirty_nobuffers(page);
		inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
		inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
		SetPagePrivate(page);
		SetPagePrivate(page);
		f2fs_trace_pid(page);
		f2fs_trace_pid(page);
@@ -510,10 +515,11 @@ void release_orphan_inode(struct f2fs_sb_info *sbi)
	spin_unlock(&im->ino_lock);
	spin_unlock(&im->ino_lock);
}
}


void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
void add_orphan_inode(struct inode *inode)
{
{
	/* add new orphan ino entry into list */
	/* add new orphan ino entry into list */
	__add_ino_entry(sbi, ino, ORPHAN_INO);
	__add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO);
	update_inode_page(inode);
}
}


void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
@@ -761,28 +767,25 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
static void __add_dirty_inode(struct inode *inode, enum inode_type type)
static void __add_dirty_inode(struct inode *inode, enum inode_type type)
{
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct f2fs_inode_info *fi = F2FS_I(inode);
	int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
	int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;


	if (is_inode_flag_set(fi, flag))
	if (is_inode_flag_set(inode, flag))
		return;
		return;


	set_inode_flag(fi, flag);
	set_inode_flag(inode, flag);
	list_add_tail(&fi->dirty_list, &sbi->inode_list[type]);
	list_add_tail(&F2FS_I(inode)->dirty_list, &sbi->inode_list[type]);
	stat_inc_dirty_inode(sbi, type);
	stat_inc_dirty_inode(sbi, type);
}
}


static void __remove_dirty_inode(struct inode *inode, enum inode_type type)
static void __remove_dirty_inode(struct inode *inode, enum inode_type type)
{
{
	struct f2fs_inode_info *fi = F2FS_I(inode);
	int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
	int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;


	if (get_dirty_pages(inode) ||
	if (get_dirty_pages(inode) || !is_inode_flag_set(inode, flag))
			!is_inode_flag_set(F2FS_I(inode), flag))
		return;
		return;


	list_del_init(&fi->dirty_list);
	list_del_init(&F2FS_I(inode)->dirty_list);
	clear_inode_flag(fi, flag);
	clear_inode_flag(inode, flag);
	stat_dec_dirty_inode(F2FS_I_SB(inode), type);
	stat_dec_dirty_inode(F2FS_I_SB(inode), type);
}
}


@@ -795,13 +798,12 @@ void update_dirty_page(struct inode *inode, struct page *page)
			!S_ISLNK(inode->i_mode))
			!S_ISLNK(inode->i_mode))
		return;
		return;


	if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH)) {
	spin_lock(&sbi->inode_lock[type]);
	spin_lock(&sbi->inode_lock[type]);
	if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH))
		__add_dirty_inode(inode, type);
		__add_dirty_inode(inode, type);
	inode_inc_dirty_pages(inode);
	spin_unlock(&sbi->inode_lock[type]);
	spin_unlock(&sbi->inode_lock[type]);
	}


	inode_inc_dirty_pages(inode);
	SetPagePrivate(page);
	SetPagePrivate(page);
	f2fs_trace_pid(page);
	f2fs_trace_pid(page);
}
}
@@ -864,6 +866,34 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
	goto retry;
	goto retry;
}
}


int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
{
	struct list_head *head = &sbi->inode_list[DIRTY_META];
	struct inode *inode;
	struct f2fs_inode_info *fi;
	s64 total = get_pages(sbi, F2FS_DIRTY_IMETA);

	while (total--) {
		if (unlikely(f2fs_cp_error(sbi)))
			return -EIO;

		spin_lock(&sbi->inode_lock[DIRTY_META]);
		if (list_empty(head)) {
			spin_unlock(&sbi->inode_lock[DIRTY_META]);
			return 0;
		}
		fi = list_entry(head->next, struct f2fs_inode_info,
							gdirty_list);
		inode = igrab(&fi->vfs_inode);
		spin_unlock(&sbi->inode_lock[DIRTY_META]);
		if (inode) {
			update_inode_page(inode);
			iput(inode);
		}
	};
	return 0;
}

/*
/*
 * Freeze all the FS-operations for checkpoint.
 * Freeze all the FS-operations for checkpoint.
 */
 */
@@ -890,6 +920,14 @@ static int block_operations(struct f2fs_sb_info *sbi)
		goto retry_flush_dents;
		goto retry_flush_dents;
	}
	}


	if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
		f2fs_unlock_all(sbi);
		err = f2fs_sync_inode_meta(sbi);
		if (err)
			goto out;
		goto retry_flush_dents;
	}

	/*
	/*
	 * POR: we should ensure that there are no dirty node pages
	 * POR: we should ensure that there are no dirty node pages
	 * until finishing nat/sit flush.
	 * until finishing nat/sit flush.
@@ -914,6 +952,8 @@ static int block_operations(struct f2fs_sb_info *sbi)
static void unblock_operations(struct f2fs_sb_info *sbi)
static void unblock_operations(struct f2fs_sb_info *sbi)
{
{
	up_write(&sbi->node_write);
	up_write(&sbi->node_write);

	build_free_nids(sbi);
	f2fs_unlock_all(sbi);
	f2fs_unlock_all(sbi);
}
}


@@ -954,7 +994,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	 * This avoids to conduct wrong roll-forward operations and uses
	 * This avoids to conduct wrong roll-forward operations and uses
	 * metapages, so should be called prior to sync_meta_pages below.
	 * metapages, so should be called prior to sync_meta_pages below.
	 */
	 */
	if (discard_next_dnode(sbi, discard_blk))
	if (!test_opt(sbi, LFS) && discard_next_dnode(sbi, discard_blk))
		invalidate = true;
		invalidate = true;


	/* Flush all the NAT/SIT pages */
	/* Flush all the NAT/SIT pages */
+162 −149
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@
#include <linux/bio.h>
#include <linux/bio.h>
#include <linux/prefetch.h>
#include <linux/prefetch.h>
#include <linux/uio.h>
#include <linux/uio.h>
#include <linux/mm.h>
#include <linux/memcontrol.h>
#include <linux/cleancache.h>
#include <linux/cleancache.h>


#include "f2fs.h"
#include "f2fs.h"
@@ -45,6 +47,7 @@ static void f2fs_read_end_io(struct bio *bio)
		struct page *page = bvec->bv_page;
		struct page *page = bvec->bv_page;


		if (!bio->bi_error) {
		if (!bio->bi_error) {
			if (!PageUptodate(page))
				SetPageUptodate(page);
				SetPageUptodate(page);
		} else {
		} else {
			ClearPageUptodate(page);
			ClearPageUptodate(page);
@@ -97,10 +100,15 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
	return bio;
	return bio;
}
}


static inline void __submit_bio(struct f2fs_sb_info *sbi, struct bio *bio)
static inline void __submit_bio(struct f2fs_sb_info *sbi,
				struct bio *bio, enum page_type type)
{
{
	if (!is_read_io(bio_op(bio)))
	if (!is_read_io(bio_op(bio))) {
		atomic_inc(&sbi->nr_wb_bios);
		atomic_inc(&sbi->nr_wb_bios);
		if (f2fs_sb_mounted_hmsmr(sbi->sb) &&
			current->plug && (type == DATA || type == NODE))
			blk_finish_plug(current->plug);
	}
	submit_bio(bio);
	submit_bio(bio);
}
}


@@ -118,7 +126,7 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)


	bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
	bio_set_op_attrs(io->bio, fio->op, fio->op_flags);


	__submit_bio(io->sbi, io->bio);
	__submit_bio(io->sbi, io->bio, fio->type);
	io->bio = NULL;
	io->bio = NULL;
}
}


@@ -240,7 +248,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
	bio->bi_rw = fio->op_flags;
	bio->bi_rw = fio->op_flags;
	bio_set_op_attrs(bio, fio->op, fio->op_flags);
	bio_set_op_attrs(bio, fio->op, fio->op_flags);


	__submit_bio(fio->sbi, bio);
	__submit_bio(fio->sbi, bio, fio->type);
	return 0;
	return 0;
}
}


@@ -326,7 +334,7 @@ int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
	if (!count)
	if (!count)
		return 0;
		return 0;


	if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)))
	if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
		return -EPERM;
		return -EPERM;
	if (unlikely(!inc_valid_block_count(sbi, dn->inode, &count)))
	if (unlikely(!inc_valid_block_count(sbi, dn->inode, &count)))
		return -ENOSPC;
		return -ENOSPC;
@@ -348,9 +356,6 @@ int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)


	if (set_page_dirty(dn->node_page))
	if (set_page_dirty(dn->node_page))
		dn->node_changed = true;
		dn->node_changed = true;

	mark_inode_dirty(dn->inode);
	sync_inode_page(dn);
	return 0;
	return 0;
}
}


@@ -446,6 +451,7 @@ struct page *get_read_data_page(struct inode *inode, pgoff_t index,
	 */
	 */
	if (dn.data_blkaddr == NEW_ADDR) {
	if (dn.data_blkaddr == NEW_ADDR) {
		zero_user_segment(page, 0, PAGE_SIZE);
		zero_user_segment(page, 0, PAGE_SIZE);
		if (!PageUptodate(page))
			SetPageUptodate(page);
			SetPageUptodate(page);
		unlock_page(page);
		unlock_page(page);
		return page;
		return page;
@@ -505,14 +511,14 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index,


	/* wait for read completion */
	/* wait for read completion */
	lock_page(page);
	lock_page(page);
	if (unlikely(!PageUptodate(page))) {
		f2fs_put_page(page, 1);
		return ERR_PTR(-EIO);
	}
	if (unlikely(page->mapping != mapping)) {
	if (unlikely(page->mapping != mapping)) {
		f2fs_put_page(page, 1);
		f2fs_put_page(page, 1);
		goto repeat;
		goto repeat;
	}
	}
	if (unlikely(!PageUptodate(page))) {
		f2fs_put_page(page, 1);
		return ERR_PTR(-EIO);
	}
	return page;
	return page;
}
}


@@ -557,6 +563,7 @@ struct page *get_new_data_page(struct inode *inode,


	if (dn.data_blkaddr == NEW_ADDR) {
	if (dn.data_blkaddr == NEW_ADDR) {
		zero_user_segment(page, 0, PAGE_SIZE);
		zero_user_segment(page, 0, PAGE_SIZE);
		if (!PageUptodate(page))
			SetPageUptodate(page);
			SetPageUptodate(page);
	} else {
	} else {
		f2fs_put_page(page, 1);
		f2fs_put_page(page, 1);
@@ -569,11 +576,8 @@ struct page *get_new_data_page(struct inode *inode,
	}
	}
got_it:
got_it:
	if (new_i_size && i_size_read(inode) <
	if (new_i_size && i_size_read(inode) <
				((loff_t)(index + 1) << PAGE_SHIFT)) {
				((loff_t)(index + 1) << PAGE_SHIFT))
		i_size_write(inode, ((loff_t)(index + 1) << PAGE_SHIFT));
		f2fs_i_size_write(inode, ((loff_t)(index + 1) << PAGE_SHIFT));
		/* Only the directory inode sets new_i_size */
		set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR);
	}
	return page;
	return page;
}
}


@@ -586,7 +590,7 @@ static int __allocate_data_block(struct dnode_of_data *dn)
	pgoff_t fofs;
	pgoff_t fofs;
	blkcnt_t count = 1;
	blkcnt_t count = 1;


	if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)))
	if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
		return -EPERM;
		return -EPERM;


	dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node);
	dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node);
@@ -611,7 +615,7 @@ static int __allocate_data_block(struct dnode_of_data *dn)
	fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
	fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
							dn->ofs_in_node;
							dn->ofs_in_node;
	if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_SHIFT))
	if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_SHIFT))
		i_size_write(dn->inode,
		f2fs_i_size_write(dn->inode,
				((loff_t)(fofs + 1) << PAGE_SHIFT));
				((loff_t)(fofs + 1) << PAGE_SHIFT));
	return 0;
	return 0;
}
}
@@ -660,7 +664,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
	unsigned int maxblocks = map->m_len;
	unsigned int maxblocks = map->m_len;
	struct dnode_of_data dn;
	struct dnode_of_data dn;
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	int mode = create ? ALLOC_NODE : LOOKUP_NODE_RA;
	int mode = create ? ALLOC_NODE : LOOKUP_NODE;
	pgoff_t pgofs, end_offset, end;
	pgoff_t pgofs, end_offset, end;
	int err = 0, ofs = 1;
	int err = 0, ofs = 1;
	unsigned int ofs_in_node, last_ofs_in_node;
	unsigned int ofs_in_node, last_ofs_in_node;
@@ -723,8 +727,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
			} else {
			} else {
				err = __allocate_data_block(&dn);
				err = __allocate_data_block(&dn);
				if (!err) {
				if (!err) {
					set_inode_flag(F2FS_I(inode),
					set_inode_flag(inode, FI_APPEND_WRITE);
							FI_APPEND_WRITE);
					allocated = true;
					allocated = true;
				}
				}
			}
			}
@@ -795,8 +798,6 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
	else if (dn.ofs_in_node < end_offset)
	else if (dn.ofs_in_node < end_offset)
		goto next_block;
		goto next_block;


	if (allocated)
		sync_inode_page(&dn);
	f2fs_put_dnode(&dn);
	f2fs_put_dnode(&dn);


	if (create) {
	if (create) {
@@ -807,8 +808,6 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
	goto next_dnode;
	goto next_dnode;


sync_out:
sync_out:
	if (allocated)
		sync_inode_page(&dn);
	f2fs_put_dnode(&dn);
	f2fs_put_dnode(&dn);
unlock_out:
unlock_out:
	if (create) {
	if (create) {
@@ -968,6 +967,37 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
	return ret;
	return ret;
}
}


struct bio *f2fs_grab_bio(struct inode *inode, block_t blkaddr,
							unsigned nr_pages)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct fscrypt_ctx *ctx = NULL;
	struct block_device *bdev = sbi->sb->s_bdev;
	struct bio *bio;

	if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
		ctx = fscrypt_get_ctx(inode, GFP_NOFS);
		if (IS_ERR(ctx))
			return ERR_CAST(ctx);

		/* wait the page to be moved by cleaning */
		f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);
	}

	bio = bio_alloc(GFP_KERNEL, min_t(int, nr_pages, BIO_MAX_PAGES));
	if (!bio) {
		if (ctx)
			fscrypt_release_ctx(ctx);
		return ERR_PTR(-ENOMEM);
	}
	bio->bi_bdev = bdev;
	bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(blkaddr);
	bio->bi_end_io = f2fs_read_end_io;
	bio->bi_private = ctx;

	return bio;
}

/*
/*
 * This function was originally taken from fs/mpage.c, and customized for f2fs.
 * This function was originally taken from fs/mpage.c, and customized for f2fs.
 * Major change was from block_size == page_size in f2fs by default.
 * Major change was from block_size == page_size in f2fs by default.
@@ -986,7 +1016,6 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
	sector_t last_block;
	sector_t last_block;
	sector_t last_block_in_file;
	sector_t last_block_in_file;
	sector_t block_nr;
	sector_t block_nr;
	struct block_device *bdev = inode->i_sb->s_bdev;
	struct f2fs_map_blocks map;
	struct f2fs_map_blocks map;


	map.m_pblk = 0;
	map.m_pblk = 0;
@@ -1047,6 +1076,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
			}
			}
		} else {
		} else {
			zero_user_segment(page, 0, PAGE_SIZE);
			zero_user_segment(page, 0, PAGE_SIZE);
			if (!PageUptodate(page))
				SetPageUptodate(page);
				SetPageUptodate(page);
			unlock_page(page);
			unlock_page(page);
			goto next_page;
			goto next_page;
@@ -1058,35 +1088,15 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
		 */
		 */
		if (bio && (last_block_in_bio != block_nr - 1)) {
		if (bio && (last_block_in_bio != block_nr - 1)) {
submit_and_realloc:
submit_and_realloc:
			__submit_bio(F2FS_I_SB(inode), bio);
			__submit_bio(F2FS_I_SB(inode), bio, DATA);
			bio = NULL;
			bio = NULL;
		}
		}
		if (bio == NULL) {
		if (bio == NULL) {
			struct fscrypt_ctx *ctx = NULL;
			bio = f2fs_grab_bio(inode, block_nr, nr_pages);

			if (IS_ERR(bio)) {
			if (f2fs_encrypted_inode(inode) &&
				bio = NULL;
					S_ISREG(inode->i_mode)) {

				ctx = fscrypt_get_ctx(inode, GFP_NOFS);
				if (IS_ERR(ctx))
					goto set_error_page;

				/* wait the page to be moved by cleaning */
				f2fs_wait_on_encrypted_page_writeback(
						F2FS_I_SB(inode), block_nr);
			}

			bio = bio_alloc(GFP_KERNEL,
				min_t(int, nr_pages, BIO_MAX_PAGES));
			if (!bio) {
				if (ctx)
					fscrypt_release_ctx(ctx);
				goto set_error_page;
				goto set_error_page;
			}
			}
			bio->bi_bdev = bdev;
			bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(block_nr);
			bio->bi_end_io = f2fs_read_end_io;
			bio->bi_private = ctx;
			bio_set_op_attrs(bio, REQ_OP_READ, 0);
			bio_set_op_attrs(bio, REQ_OP_READ, 0);
		}
		}


@@ -1102,7 +1112,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
		goto next_page;
		goto next_page;
confused:
confused:
		if (bio) {
		if (bio) {
			__submit_bio(F2FS_I_SB(inode), bio);
			__submit_bio(F2FS_I_SB(inode), bio, DATA);
			bio = NULL;
			bio = NULL;
		}
		}
		unlock_page(page);
		unlock_page(page);
@@ -1112,7 +1122,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
	}
	}
	BUG_ON(pages && !list_empty(pages));
	BUG_ON(pages && !list_empty(pages));
	if (bio)
	if (bio)
		__submit_bio(F2FS_I_SB(inode), bio);
		__submit_bio(F2FS_I_SB(inode), bio, DATA);
	return 0;
	return 0;
}
}


@@ -1201,14 +1211,14 @@ int do_write_data_page(struct f2fs_io_info *fio)
			!IS_ATOMIC_WRITTEN_PAGE(page) &&
			!IS_ATOMIC_WRITTEN_PAGE(page) &&
			need_inplace_update(inode))) {
			need_inplace_update(inode))) {
		rewrite_data_page(fio);
		rewrite_data_page(fio);
		set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE);
		set_inode_flag(inode, FI_UPDATE_WRITE);
		trace_f2fs_do_write_data_page(page, IPU);
		trace_f2fs_do_write_data_page(page, IPU);
	} else {
	} else {
		write_data_page(&dn, fio);
		write_data_page(&dn, fio);
		trace_f2fs_do_write_data_page(page, OPU);
		trace_f2fs_do_write_data_page(page, OPU);
		set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
		set_inode_flag(inode, FI_APPEND_WRITE);
		if (page->index == 0)
		if (page->index == 0)
			set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
			set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
	}
	}
out_writepage:
out_writepage:
	f2fs_put_dnode(&dn);
	f2fs_put_dnode(&dn);
@@ -1223,6 +1233,7 @@ static int f2fs_write_data_page(struct page *page,
	loff_t i_size = i_size_read(inode);
	loff_t i_size = i_size_read(inode);
	const pgoff_t end_index = ((unsigned long long) i_size)
	const pgoff_t end_index = ((unsigned long long) i_size)
							>> PAGE_SHIFT;
							>> PAGE_SHIFT;
	loff_t psize = (page->index + 1) << PAGE_SHIFT;
	unsigned offset = 0;
	unsigned offset = 0;
	bool need_balance_fs = false;
	bool need_balance_fs = false;
	int err = 0;
	int err = 0;
@@ -1260,20 +1271,18 @@ static int f2fs_write_data_page(struct page *page,
			available_free_memory(sbi, BASE_CHECK))))
			available_free_memory(sbi, BASE_CHECK))))
		goto redirty_out;
		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 */
	/* Dentry blocks are controlled by checkpoint */
	if (S_ISDIR(inode->i_mode)) {
	if (S_ISDIR(inode->i_mode)) {
		if (unlikely(f2fs_cp_error(sbi)))
			goto redirty_out;
		err = do_write_data_page(&fio);
		err = do_write_data_page(&fio);
		goto done;
		goto done;
	}
	}


	/* we should bypass data pages to proceed the kworkder jobs */
	if (unlikely(f2fs_cp_error(sbi))) {
		SetPageError(page);
		goto out;
	}

	if (!wbc->for_reclaim)
	if (!wbc->for_reclaim)
		need_balance_fs = true;
		need_balance_fs = true;
	else if (has_not_enough_free_secs(sbi, 0))
	else if (has_not_enough_free_secs(sbi, 0))
@@ -1285,6 +1294,8 @@ static int f2fs_write_data_page(struct page *page,
		err = f2fs_write_inline_data(inode, page);
		err = f2fs_write_inline_data(inode, page);
	if (err == -EAGAIN)
	if (err == -EAGAIN)
		err = do_write_data_page(&fio);
		err = do_write_data_page(&fio);
	if (F2FS_I(inode)->last_disk_size < psize)
		F2FS_I(inode)->last_disk_size = psize;
	f2fs_unlock_op(sbi);
	f2fs_unlock_op(sbi);
done:
done:
	if (err && err != -ENOENT)
	if (err && err != -ENOENT)
@@ -1311,16 +1322,8 @@ static int f2fs_write_data_page(struct page *page,


redirty_out:
redirty_out:
	redirty_page_for_writepage(wbc, page);
	redirty_page_for_writepage(wbc, page);
	return AOP_WRITEPAGE_ACTIVATE;
	unlock_page(page);
}
	return err;

static int __f2fs_writepage(struct page *page, struct writeback_control *wbc,
			void *data)
{
	struct address_space *mapping = data;
	int ret = mapping->a_ops->writepage(page, wbc);
	mapping_set_error(mapping, ret);
	return ret;
}
}


/*
/*
@@ -1329,8 +1332,7 @@ static int __f2fs_writepage(struct page *page, struct writeback_control *wbc,
 * warm/hot data page.
 * warm/hot data page.
 */
 */
static int f2fs_write_cache_pages(struct address_space *mapping,
static int f2fs_write_cache_pages(struct address_space *mapping,
			struct writeback_control *wbc, writepage_t writepage,
					struct writeback_control *wbc)
			void *data)
{
{
	int ret = 0;
	int ret = 0;
	int done = 0;
	int done = 0;
@@ -1343,10 +1345,9 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
	int cycled;
	int cycled;
	int range_whole = 0;
	int range_whole = 0;
	int tag;
	int tag;
	int step = 0;


	pagevec_init(&pvec, 0);
	pagevec_init(&pvec, 0);
next:

	if (wbc->range_cyclic) {
	if (wbc->range_cyclic) {
		writeback_index = mapping->writeback_index; /* prev offset */
		writeback_index = mapping->writeback_index; /* prev offset */
		index = writeback_index;
		index = writeback_index;
@@ -1401,9 +1402,6 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
				goto continue_unlock;
				goto continue_unlock;
			}
			}


			if (step == is_cold_data(page))
				goto continue_unlock;

			if (PageWriteback(page)) {
			if (PageWriteback(page)) {
				if (wbc->sync_mode != WB_SYNC_NONE)
				if (wbc->sync_mode != WB_SYNC_NONE)
					f2fs_wait_on_page_writeback(page,
					f2fs_wait_on_page_writeback(page,
@@ -1416,17 +1414,12 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
			if (!clear_page_dirty_for_io(page))
			if (!clear_page_dirty_for_io(page))
				goto continue_unlock;
				goto continue_unlock;


			ret = (*writepage)(page, wbc, data);
			ret = mapping->a_ops->writepage(page, wbc);
			if (unlikely(ret)) {
			if (unlikely(ret)) {
				if (ret == AOP_WRITEPAGE_ACTIVATE) {
					unlock_page(page);
					ret = 0;
				} else {
				done_index = page->index + 1;
				done_index = page->index + 1;
				done = 1;
				done = 1;
				break;
				break;
			}
			}
			}


			if (--wbc->nr_to_write <= 0 &&
			if (--wbc->nr_to_write <= 0 &&
			    wbc->sync_mode == WB_SYNC_NONE) {
			    wbc->sync_mode == WB_SYNC_NONE) {
@@ -1438,11 +1431,6 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
		cond_resched();
		cond_resched();
	}
	}


	if (step < 1) {
		step++;
		goto next;
	}

	if (!cycled && !done) {
	if (!cycled && !done) {
		cycled = 1;
		cycled = 1;
		index = 0;
		index = 0;
@@ -1460,9 +1448,8 @@ static int f2fs_write_data_pages(struct address_space *mapping,
{
{
	struct inode *inode = mapping->host;
	struct inode *inode = mapping->host;
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	bool locked = false;
	struct blk_plug plug;
	int ret;
	int ret;
	long diff;


	/* deal with chardevs and other special file */
	/* deal with chardevs and other special file */
	if (!mapping->a_ops->writepage)
	if (!mapping->a_ops->writepage)
@@ -1478,7 +1465,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
		goto skip_write;
		goto skip_write;


	/* skip writing during file defragment */
	/* skip writing during file defragment */
	if (is_inode_flag_set(F2FS_I(inode), FI_DO_DEFRAG))
	if (is_inode_flag_set(inode, FI_DO_DEFRAG))
		goto skip_write;
		goto skip_write;


	/* during POR, we don't need to trigger writepage at all. */
	/* during POR, we don't need to trigger writepage at all. */
@@ -1487,20 +1474,16 @@ static int f2fs_write_data_pages(struct address_space *mapping,


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


	diff = nr_pages_to_write(sbi, DATA, wbc);
	blk_start_plug(&plug);

	ret = f2fs_write_cache_pages(mapping, wbc);
	if (!S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_ALL) {
	blk_finish_plug(&plug);
		mutex_lock(&sbi->writepages);
	/*
		locked = true;
	 * if some pages were truncated, we cannot guarantee its mapping->host
	}
	 * to detect pending bios.
	ret = f2fs_write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
	 */
	f2fs_submit_merged_bio_cond(sbi, inode, NULL, 0, DATA, WRITE);
	f2fs_submit_merged_bio(sbi, DATA, WRITE);
	if (locked)
		mutex_unlock(&sbi->writepages);


	remove_dirty_inode(inode);
	remove_dirty_inode(inode);

	wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
	return ret;
	return ret;


skip_write:
skip_write:
@@ -1558,7 +1541,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
	if (f2fs_has_inline_data(inode)) {
	if (f2fs_has_inline_data(inode)) {
		if (pos + len <= MAX_INLINE_DATA) {
		if (pos + len <= MAX_INLINE_DATA) {
			read_inline_data(page, ipage);
			read_inline_data(page, ipage);
			set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
			set_inode_flag(inode, FI_DATA_EXIST);
			if (inode->i_nlink)
			if (inode->i_nlink)
				set_inline_node(ipage);
				set_inline_node(ipage);
		} else {
		} else {
@@ -1668,38 +1651,34 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	if (blkaddr == NEW_ADDR) {
	if (blkaddr == NEW_ADDR) {
		zero_user_segment(page, 0, PAGE_SIZE);
		zero_user_segment(page, 0, PAGE_SIZE);
	} else {
	} else {
		struct f2fs_io_info fio = {
		struct bio *bio;
			.sbi = sbi,
			.type = DATA,
			.op = REQ_OP_READ,
			.op_flags = READ_SYNC,
			.old_blkaddr = blkaddr,
			.new_blkaddr = blkaddr,
			.page = page,
			.encrypted_page = NULL,
		};
		err = f2fs_submit_page_bio(&fio);
		if (err)
			goto fail;


		lock_page(page);
		bio = f2fs_grab_bio(inode, blkaddr, 1);
		if (unlikely(!PageUptodate(page))) {
		if (IS_ERR(bio)) {
			err = -EIO;
			err = PTR_ERR(bio);
			goto fail;
		}
		bio_set_op_attrs(bio, REQ_OP_READ, READ_SYNC);
		if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
			bio_put(bio);
			err = -EFAULT;
			goto fail;
			goto fail;
		}
		}

		__submit_bio(sbi, bio, DATA);

		lock_page(page);
		if (unlikely(page->mapping != mapping)) {
		if (unlikely(page->mapping != mapping)) {
			f2fs_put_page(page, 1);
			f2fs_put_page(page, 1);
			goto repeat;
			goto repeat;
		}
		}

		if (unlikely(!PageUptodate(page))) {
		/* avoid symlink page */
			err = -EIO;
		if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
			err = fscrypt_decrypt_page(page);
			if (err)
			goto fail;
			goto fail;
		}
		}
	}
	}
out_update:
out_update:
	if (!PageUptodate(page))
		SetPageUptodate(page);
		SetPageUptodate(page);
out_clear:
out_clear:
	clear_cold_data(page);
	clear_cold_data(page);
@@ -1721,13 +1700,11 @@ static int f2fs_write_end(struct file *file,
	trace_f2fs_write_end(inode, pos, len, copied);
	trace_f2fs_write_end(inode, pos, len, copied);


	set_page_dirty(page);
	set_page_dirty(page);
	f2fs_put_page(page, 1);


	if (pos + copied > i_size_read(inode)) {
	if (pos + copied > i_size_read(inode))
		i_size_write(inode, pos + copied);
		f2fs_i_size_write(inode, pos + copied);
		mark_inode_dirty(inode);
	}


	f2fs_put_page(page, 1);
	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
	return copied;
	return copied;
}
}
@@ -1752,6 +1729,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
	struct inode *inode = mapping->host;
	struct inode *inode = mapping->host;
	size_t count = iov_iter_count(iter);
	size_t count = iov_iter_count(iter);
	loff_t offset = iocb->ki_pos;
	loff_t offset = iocb->ki_pos;
	int rw = iov_iter_rw(iter);
	int err;
	int err;


	err = check_direct_IO(inode, iter, offset);
	err = check_direct_IO(inode, iter, offset);
@@ -1760,18 +1738,23 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)


	if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
	if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))
		return 0;
		return 0;
	if (test_opt(F2FS_I_SB(inode), LFS))
		return 0;


	trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
	trace_f2fs_direct_IO_enter(inode, offset, count, rw);


	down_read(&F2FS_I(inode)->dio_rwsem[rw]);
	err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
	err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
	if (iov_iter_rw(iter) == WRITE) {
	up_read(&F2FS_I(inode)->dio_rwsem[rw]);

	if (rw == WRITE) {
		if (err > 0)
		if (err > 0)
			set_inode_flag(F2FS_I(inode), FI_UPDATE_WRITE);
			set_inode_flag(inode, FI_UPDATE_WRITE);
		else if (err < 0)
		else if (err < 0)
			f2fs_write_failed(mapping, offset + count);
			f2fs_write_failed(mapping, offset + count);
	}
	}


	trace_f2fs_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), err);
	trace_f2fs_direct_IO_exit(inode, offset, count, rw, err);


	return err;
	return err;
}
}
@@ -1818,6 +1801,35 @@ int f2fs_release_page(struct page *page, gfp_t wait)
	return 1;
	return 1;
}
}


/*
 * This was copied from __set_page_dirty_buffers which gives higher performance
 * in very high speed storages. (e.g., pmem)
 */
void f2fs_set_page_dirty_nobuffers(struct page *page)
{
	struct address_space *mapping = page->mapping;
	unsigned long flags;

	if (unlikely(!mapping))
		return;

	spin_lock(&mapping->private_lock);
	lock_page_memcg(page);
	SetPageDirty(page);
	spin_unlock(&mapping->private_lock);

	spin_lock_irqsave(&mapping->tree_lock, flags);
	WARN_ON_ONCE(!PageUptodate(page));
	account_page_dirtied(page, mapping);
	radix_tree_tag_set(&mapping->page_tree,
			page_index(page), PAGECACHE_TAG_DIRTY);
	spin_unlock_irqrestore(&mapping->tree_lock, flags);
	unlock_page_memcg(page);

	__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
	return;
}

static int f2fs_set_data_page_dirty(struct page *page)
static int f2fs_set_data_page_dirty(struct page *page)
{
{
	struct address_space *mapping = page->mapping;
	struct address_space *mapping = page->mapping;
@@ -1825,6 +1837,7 @@ static int f2fs_set_data_page_dirty(struct page *page)


	trace_f2fs_set_page_dirty(page, DATA);
	trace_f2fs_set_page_dirty(page, DATA);


	if (!PageUptodate(page))
		SetPageUptodate(page);
		SetPageUptodate(page);


	if (f2fs_is_atomic_file(inode)) {
	if (f2fs_is_atomic_file(inode)) {
@@ -1840,7 +1853,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
	}
	}


	if (!PageDirty(page)) {
	if (!PageDirty(page)) {
		__set_page_dirty_nobuffers(page);
		f2fs_set_page_dirty_nobuffers(page);
		update_dirty_page(inode, page);
		update_dirty_page(inode, page);
		return 1;
		return 1;
	}
	}
Loading