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

Commit 4b0a268e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "This patch-set includes lots of bug fixes based on clean-ups and
  refactored codes.  And inline_dir was introduced and two minor mount
  options were added.  Details from signed tag:

  This series includes the following enhancement with refactored flows.
   - fix inmemory page operations
   - fix wrong inline_data & inline_dir logics
   - enhance memory and IO control under memory pressure
   - consider preemption on radix_tree operation
   - fix memory leaks and deadlocks

  But also, there are a couple of new features:
   - support inline_dir to store dentries inside inode page
   - add -o fastboot to reduce booting time
   - implement -o dirsync

  And a lot of clean-ups and minor bug fixes as well"

* tag 'for-f2fs-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (88 commits)
  f2fs: avoid to ra unneeded blocks in recover flow
  f2fs: introduce is_valid_blkaddr to cleanup codes in ra_meta_pages
  f2fs: fix to enable readahead for SSA/CP blocks
  f2fs: use atomic for counting inode with inline_{dir,inode} flag
  f2fs: cleanup path to need cp at fsync
  f2fs: check if inode state is dirty at fsync
  f2fs: count the number of inmemory pages
  f2fs: release inmemory pages when the file was closed
  f2fs: set page private for inmemory pages for truncation
  f2fs: count inline_xx in do_read_inode
  f2fs: do retry operations with cond_resched
  f2fs: call radix_tree_preload before radix_tree_insert
  f2fs: use rw_semaphore for nat entry lock
  f2fs: fix missing kmem_cache_free
  f2fs: more fast lookup for gc_inode list
  f2fs: cleanup redundant macro
  f2fs: fix to return correct error number in f2fs_write_begin
  f2fs: cleanup if-statement of phase in gc_data_segment
  f2fs: fix to recover converted inline_data
  f2fs: make clean the page before writing
  ...
parents a6b84957 635aee1f
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -122,6 +122,10 @@ disable_ext_identify Disable the extension list configured by mkfs, so f2fs
inline_xattr           Enable the inline xattrs feature.
inline_data            Enable the inline data feature: New created small(<~3.4k)
                       files can be written into inode block.
inline_dentry          Enable the inline dir feature: data in new created
                       directory entries can be written into inode block. The
                       space of inode block which is used to store inline
                       dentries is limited to ~3.4k.
flush_merge	       Merge concurrent cache_flush commands as much as possible
                       to eliminate redundant command issues. If the underlying
		       device handles the cache_flush command relatively slowly,
@@ -131,6 +135,9 @@ nobarrier This option can be used if underlying storage guarantees
		       If this option is set, no cache_flush commands are issued
		       but f2fs still guarantees the write ordering of all the
		       data writes.
fastboot               This option is used when a system wants to reduce mount
                       time as much as possible, even though normal performance
		       can be sacrificed.

================================================================================
DEBUGFS ENTRIES
+140 −8
Original line number Diff line number Diff line
@@ -162,7 +162,8 @@ static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size)
	return ERR_PTR(-EINVAL);
}

struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type,
						struct page *dpage)
{
	int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
	void *value = NULL;
@@ -172,12 +173,13 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
	if (type == ACL_TYPE_ACCESS)
		name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;

	retval = f2fs_getxattr(inode, name_index, "", NULL, 0);
	retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage);
	if (retval > 0) {
		value = kmalloc(retval, GFP_F2FS_ZERO);
		if (!value)
			return ERR_PTR(-ENOMEM);
		retval = f2fs_getxattr(inode, name_index, "", value, retval);
		retval = f2fs_getxattr(inode, name_index, "", value,
							retval, dpage);
	}

	if (retval > 0)
@@ -194,6 +196,11 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
	return acl;
}

struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
{
	return __f2fs_get_acl(inode, type, NULL);
}

static int __f2fs_set_acl(struct inode *inode, int type,
			struct posix_acl *acl, struct page *ipage)
{
@@ -229,7 +236,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
	if (acl) {
		value = f2fs_acl_to_disk(acl, &size);
		if (IS_ERR(value)) {
			cond_clear_inode_flag(fi, FI_ACL_MODE);
			clear_inode_flag(fi, FI_ACL_MODE);
			return (int)PTR_ERR(value);
		}
	}
@@ -240,7 +247,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
	if (!error)
		set_cached_acl(inode, type, acl);

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

@@ -249,12 +256,137 @@ int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
	return __f2fs_set_acl(inode, type, acl, NULL);
}

int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
/*
 * Most part of f2fs_acl_clone, f2fs_acl_create_masq, f2fs_acl_create
 * are copied from posix_acl.c
 */
static struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl,
							gfp_t flags)
{
	struct posix_acl *clone = NULL;

	if (acl) {
		int size = sizeof(struct posix_acl) + acl->a_count *
				sizeof(struct posix_acl_entry);
		clone = kmemdup(acl, size, flags);
		if (clone)
			atomic_set(&clone->a_refcount, 1);
	}
	return clone;
}

static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
{
	struct posix_acl_entry *pa, *pe;
	struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
	umode_t mode = *mode_p;
	int not_equiv = 0;

	/* assert(atomic_read(acl->a_refcount) == 1); */

	FOREACH_ACL_ENTRY(pa, acl, pe) {
		switch(pa->e_tag) {
		case ACL_USER_OBJ:
			pa->e_perm &= (mode >> 6) | ~S_IRWXO;
			mode &= (pa->e_perm << 6) | ~S_IRWXU;
			break;

		case ACL_USER:
		case ACL_GROUP:
			not_equiv = 1;
			break;

		case ACL_GROUP_OBJ:
			group_obj = pa;
			break;

		case ACL_OTHER:
			pa->e_perm &= mode | ~S_IRWXO;
			mode &= pa->e_perm | ~S_IRWXO;
			break;

		case ACL_MASK:
			mask_obj = pa;
			not_equiv = 1;
			break;

		default:
			return -EIO;
		}
	}

	if (mask_obj) {
		mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
		mode &= (mask_obj->e_perm << 3) | ~S_IRWXG;
	} else {
		if (!group_obj)
			return -EIO;
		group_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
		mode &= (group_obj->e_perm << 3) | ~S_IRWXG;
	}

	*mode_p = (*mode_p & ~S_IRWXUGO) | mode;
        return not_equiv;
}

static int f2fs_acl_create(struct inode *dir, umode_t *mode,
		struct posix_acl **default_acl, struct posix_acl **acl,
		struct page *dpage)
{
	struct posix_acl *p;
	int ret;

	if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
		goto no_acl;

	p = __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage);
	if (IS_ERR(p)) {
		if (p == ERR_PTR(-EOPNOTSUPP))
			goto apply_umask;
		return PTR_ERR(p);
	}

	if (!p)
		goto apply_umask;

	*acl = f2fs_acl_clone(p, GFP_NOFS);
	if (!*acl)
		return -ENOMEM;

	ret = f2fs_acl_create_masq(*acl, mode);
	if (ret < 0) {
		posix_acl_release(*acl);
		return -ENOMEM;
	}

	if (ret == 0) {
		posix_acl_release(*acl);
		*acl = NULL;
	}

	if (!S_ISDIR(*mode)) {
		posix_acl_release(p);
		*default_acl = NULL;
	} else {
		*default_acl = p;
	}
	return 0;

apply_umask:
	*mode &= ~current_umask();
no_acl:
	*default_acl = NULL;
	*acl = NULL;
	return 0;
}

int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
							struct page *dpage)
{
	struct posix_acl *default_acl, *acl;
	struct posix_acl *default_acl = NULL, *acl = NULL;
	int error = 0;

	error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	error = f2fs_acl_create(dir, &inode->i_mode, &default_acl, &acl, dpage);
	if (error)
		return error;

+3 −2
Original line number Diff line number Diff line
@@ -38,14 +38,15 @@ struct f2fs_acl_header {

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_init_acl(struct inode *, struct inode *, struct page *);
extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
							struct page *);
#else
#define f2fs_check_acl	NULL
#define f2fs_get_acl	NULL
#define f2fs_set_acl	NULL

static inline int f2fs_init_acl(struct inode *inode, struct inode *dir,
							struct page *page)
				struct page *ipage, struct page *dpage)
{
	return 0;
}
+115 −71
Original line number Diff line number Diff line
@@ -72,36 +72,36 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
	return page;
}

struct page *get_meta_page_ra(struct f2fs_sb_info *sbi, pgoff_t index)
{
	bool readahead = false;
	struct page *page;

	page = find_get_page(META_MAPPING(sbi), index);
	if (!page || (page && !PageUptodate(page)))
		readahead = true;
	f2fs_put_page(page, 0);

	if (readahead)
		ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR);
	return get_meta_page(sbi, index);
}

static inline block_t get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
static inline bool is_valid_blkaddr(struct f2fs_sb_info *sbi,
						block_t blkaddr, int type)
{
	switch (type) {
	case META_NAT:
		return NM_I(sbi)->max_nid / NAT_ENTRY_PER_BLOCK;
		break;
	case META_SIT:
		return SIT_BLK_CNT(sbi);
		if (unlikely(blkaddr >= SIT_BLK_CNT(sbi)))
			return false;
		break;
	case META_SSA:
		if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) ||
			blkaddr < SM_I(sbi)->ssa_blkaddr))
			return false;
		break;
	case META_CP:
		return 0;
		if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr ||
			blkaddr < __start_cp_addr(sbi)))
			return false;
		break;
	case META_POR:
		return MAX_BLKADDR(sbi);
		if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
			blkaddr < MAIN_BLKADDR(sbi)))
			return false;
		break;
	default:
		BUG();
	}

	return true;
}

/*
@@ -112,7 +112,6 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
	block_t prev_blk_addr = 0;
	struct page *page;
	block_t blkno = start;
	block_t max_blks = get_max_meta_blks(sbi, type);

	struct f2fs_io_info fio = {
		.type = META,
@@ -122,18 +121,20 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
	for (; nrpages-- > 0; blkno++) {
		block_t blk_addr;

		if (!is_valid_blkaddr(sbi, blkno, type))
			goto out;

		switch (type) {
		case META_NAT:
			/* get nat block addr */
			if (unlikely(blkno >= max_blks))
			if (unlikely(blkno >=
					NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid)))
				blkno = 0;
			/* get nat block addr */
			blk_addr = current_nat_addr(sbi,
					blkno * NAT_ENTRY_PER_BLOCK);
			break;
		case META_SIT:
			/* get sit block addr */
			if (unlikely(blkno >= max_blks))
				goto out;
			blk_addr = current_sit_addr(sbi,
					blkno * SIT_ENTRY_PER_BLOCK);
			if (blkno != start && prev_blk_addr + 1 != blk_addr)
@@ -143,10 +144,6 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
		case META_SSA:
		case META_CP:
		case META_POR:
			if (unlikely(blkno >= max_blks))
				goto out;
			if (unlikely(blkno < SEG0_BLKADDR(sbi)))
				goto out;
			blk_addr = blkno;
			break;
		default:
@@ -169,6 +166,20 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
	return blkno - start;
}

void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
{
	struct page *page;
	bool readahead = false;

	page = find_get_page(META_MAPPING(sbi), index);
	if (!page || (page && !PageUptodate(page)))
		readahead = true;
	f2fs_put_page(page, 0);

	if (readahead)
		ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR);
}

static int f2fs_write_meta_page(struct page *page,
				struct writeback_control *wbc)
{
@@ -178,7 +189,7 @@ static int f2fs_write_meta_page(struct page *page,

	if (unlikely(sbi->por_doing))
		goto redirty_out;
	if (wbc->for_reclaim)
	if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
		goto redirty_out;
	if (unlikely(f2fs_cp_error(sbi)))
		goto redirty_out;
@@ -187,6 +198,9 @@ static int f2fs_write_meta_page(struct page *page,
	write_meta_page(sbi, page);
	dec_page_count(sbi, F2FS_DIRTY_META);
	unlock_page(page);

	if (wbc->for_reclaim)
		f2fs_submit_merged_bio(sbi, META, WRITE);
	return 0;

redirty_out:
@@ -298,46 +312,57 @@ const struct address_space_operations f2fs_meta_aops = {

static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{
	struct inode_management *im = &sbi->im[type];
	struct ino_entry *e;
retry:
	spin_lock(&sbi->ino_lock[type]);
	if (radix_tree_preload(GFP_NOFS)) {
		cond_resched();
		goto retry;
	}

	spin_lock(&im->ino_lock);

	e = radix_tree_lookup(&sbi->ino_root[type], ino);
	e = radix_tree_lookup(&im->ino_root, ino);
	if (!e) {
		e = kmem_cache_alloc(ino_entry_slab, GFP_ATOMIC);
		if (!e) {
			spin_unlock(&sbi->ino_lock[type]);
			spin_unlock(&im->ino_lock);
			radix_tree_preload_end();
			goto retry;
		}
		if (radix_tree_insert(&sbi->ino_root[type], ino, e)) {
			spin_unlock(&sbi->ino_lock[type]);
		if (radix_tree_insert(&im->ino_root, ino, e)) {
			spin_unlock(&im->ino_lock);
			kmem_cache_free(ino_entry_slab, e);
			radix_tree_preload_end();
			goto retry;
		}
		memset(e, 0, sizeof(struct ino_entry));
		e->ino = ino;

		list_add_tail(&e->list, &sbi->ino_list[type]);
		list_add_tail(&e->list, &im->ino_list);
		if (type != ORPHAN_INO)
			im->ino_num++;
	}
	spin_unlock(&sbi->ino_lock[type]);
	spin_unlock(&im->ino_lock);
	radix_tree_preload_end();
}

static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{
	struct inode_management *im = &sbi->im[type];
	struct ino_entry *e;

	spin_lock(&sbi->ino_lock[type]);
	e = radix_tree_lookup(&sbi->ino_root[type], ino);
	spin_lock(&im->ino_lock);
	e = radix_tree_lookup(&im->ino_root, ino);
	if (e) {
		list_del(&e->list);
		radix_tree_delete(&sbi->ino_root[type], ino);
		if (type == ORPHAN_INO)
			sbi->n_orphans--;
		spin_unlock(&sbi->ino_lock[type]);
		radix_tree_delete(&im->ino_root, ino);
		im->ino_num--;
		spin_unlock(&im->ino_lock);
		kmem_cache_free(ino_entry_slab, e);
		return;
	}
	spin_unlock(&sbi->ino_lock[type]);
	spin_unlock(&im->ino_lock);
}

void add_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
@@ -355,10 +380,12 @@ void remove_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
/* mode should be APPEND_INO or UPDATE_INO */
bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
{
	struct inode_management *im = &sbi->im[mode];
	struct ino_entry *e;
	spin_lock(&sbi->ino_lock[mode]);
	e = radix_tree_lookup(&sbi->ino_root[mode], ino);
	spin_unlock(&sbi->ino_lock[mode]);

	spin_lock(&im->ino_lock);
	e = radix_tree_lookup(&im->ino_root, ino);
	spin_unlock(&im->ino_lock);
	return e ? true : false;
}

@@ -368,36 +395,42 @@ void release_dirty_inode(struct f2fs_sb_info *sbi)
	int i;

	for (i = APPEND_INO; i <= UPDATE_INO; i++) {
		spin_lock(&sbi->ino_lock[i]);
		list_for_each_entry_safe(e, tmp, &sbi->ino_list[i], list) {
		struct inode_management *im = &sbi->im[i];

		spin_lock(&im->ino_lock);
		list_for_each_entry_safe(e, tmp, &im->ino_list, list) {
			list_del(&e->list);
			radix_tree_delete(&sbi->ino_root[i], e->ino);
			radix_tree_delete(&im->ino_root, e->ino);
			kmem_cache_free(ino_entry_slab, e);
			im->ino_num--;
		}
		spin_unlock(&sbi->ino_lock[i]);
		spin_unlock(&im->ino_lock);
	}
}

int acquire_orphan_inode(struct f2fs_sb_info *sbi)
{
	struct inode_management *im = &sbi->im[ORPHAN_INO];
	int err = 0;

	spin_lock(&sbi->ino_lock[ORPHAN_INO]);
	if (unlikely(sbi->n_orphans >= sbi->max_orphans))
	spin_lock(&im->ino_lock);
	if (unlikely(im->ino_num >= sbi->max_orphans))
		err = -ENOSPC;
	else
		sbi->n_orphans++;
	spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
		im->ino_num++;
	spin_unlock(&im->ino_lock);

	return err;
}

void release_orphan_inode(struct f2fs_sb_info *sbi)
{
	spin_lock(&sbi->ino_lock[ORPHAN_INO]);
	f2fs_bug_on(sbi, sbi->n_orphans == 0);
	sbi->n_orphans--;
	spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
	struct inode_management *im = &sbi->im[ORPHAN_INO];

	spin_lock(&im->ino_lock);
	f2fs_bug_on(sbi, im->ino_num == 0);
	im->ino_num--;
	spin_unlock(&im->ino_lock);
}

void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
@@ -460,17 +493,19 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
	struct f2fs_orphan_block *orphan_blk = NULL;
	unsigned int nentries = 0;
	unsigned short index;
	unsigned short orphan_blocks =
			(unsigned short)GET_ORPHAN_BLOCKS(sbi->n_orphans);
	unsigned short orphan_blocks;
	struct page *page = NULL;
	struct ino_entry *orphan = NULL;
	struct inode_management *im = &sbi->im[ORPHAN_INO];

	orphan_blocks = GET_ORPHAN_BLOCKS(im->ino_num);

	for (index = 0; index < orphan_blocks; index++)
		grab_meta_page(sbi, start_blk + index);

	index = 1;
	spin_lock(&sbi->ino_lock[ORPHAN_INO]);
	head = &sbi->ino_list[ORPHAN_INO];
	spin_lock(&im->ino_lock);
	head = &im->ino_list;

	/* loop for each orphan inode entry and write them in Jornal block */
	list_for_each_entry(orphan, head, list) {
@@ -510,7 +545,7 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
		f2fs_put_page(page, 1);
	}

	spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
	spin_unlock(&im->ino_lock);
}

static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
@@ -731,6 +766,9 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
	struct dir_inode_entry *entry;
	struct inode *inode;
retry:
	if (unlikely(f2fs_cp_error(sbi)))
		return;

	spin_lock(&sbi->dir_inode_lock);

	head = &sbi->dir_inode_list;
@@ -830,6 +868,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
	struct f2fs_nm_info *nm_i = NM_I(sbi);
	unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
	nid_t last_nid = nm_i->next_scan_nid;
	block_t start_blk;
	struct page *cp_page;
@@ -889,7 +928,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	else
		clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);

	orphan_blocks = GET_ORPHAN_BLOCKS(sbi->n_orphans);
	orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num);
	ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
			orphan_blocks);

@@ -905,7 +944,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
				orphan_blocks);
	}

	if (sbi->n_orphans)
	if (orphan_num)
		set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
	else
		clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
@@ -940,7 +979,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
		f2fs_put_page(cp_page, 1);
	}

	if (sbi->n_orphans) {
	if (orphan_num) {
		write_orphan_inodes(sbi, start_blk);
		start_blk += orphan_blocks;
	}
@@ -975,6 +1014,9 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	/* Here, we only have one bio having CP pack */
	sync_meta_pages(sbi, META_FLUSH, LONG_MAX);

	/* wait for previous submitted meta pages writeback */
	wait_on_all_pages_writeback(sbi);

	release_dirty_inode(sbi);

	if (unlikely(f2fs_cp_error(sbi)))
@@ -1036,9 +1078,12 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
	int i;

	for (i = 0; i < MAX_INO_ENTRY; i++) {
		INIT_RADIX_TREE(&sbi->ino_root[i], GFP_ATOMIC);
		spin_lock_init(&sbi->ino_lock[i]);
		INIT_LIST_HEAD(&sbi->ino_list[i]);
		struct inode_management *im = &sbi->im[i];

		INIT_RADIX_TREE(&im->ino_root, GFP_ATOMIC);
		spin_lock_init(&im->ino_lock);
		INIT_LIST_HEAD(&im->ino_list);
		im->ino_num = 0;
	}

	/*
@@ -1047,7 +1092,6 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
	 * orphan entries with the limitation one reserved segment
	 * for cp pack we can have max 1020*504 orphan entries
	 */
	sbi->n_orphans = 0;
	sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
			NR_CURSEG_TYPE) * F2FS_ORPHANS_PER_BLOCK;
}
+84 −82
Original line number Diff line number Diff line
@@ -61,11 +61,6 @@ static void f2fs_write_end_io(struct bio *bio, int err)
		dec_page_count(sbi, F2FS_WRITEBACK);
	}

	if (sbi->wait_io) {
		complete(sbi->wait_io);
		sbi->wait_io = NULL;
	}

	if (!get_pages(sbi, F2FS_WRITEBACK) &&
			!list_empty(&sbi->cp_wait.task_list))
		wake_up(&sbi->cp_wait);
@@ -95,34 +90,18 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
static void __submit_merged_bio(struct f2fs_bio_info *io)
{
	struct f2fs_io_info *fio = &io->fio;
	int rw;

	if (!io->bio)
		return;

	rw = fio->rw;

	if (is_read_io(rw)) {
		trace_f2fs_submit_read_bio(io->sbi->sb, rw,
	if (is_read_io(fio->rw))
		trace_f2fs_submit_read_bio(io->sbi->sb, fio->rw,
							fio->type, io->bio);
		submit_bio(rw, io->bio);
	} else {
		trace_f2fs_submit_write_bio(io->sbi->sb, rw,
	else
		trace_f2fs_submit_write_bio(io->sbi->sb, fio->rw,
							fio->type, io->bio);
		/*
		 * META_FLUSH is only from the checkpoint procedure, and we
		 * should wait this metadata bio for FS consistency.
		 */
		if (fio->type == META_FLUSH) {
			DECLARE_COMPLETION_ONSTACK(wait);
			io->sbi->wait_io = &wait;
			submit_bio(rw, io->bio);
			wait_for_completion(&wait);
		} else {
			submit_bio(rw, io->bio);
		}
	}

	submit_bio(fio->rw, io->bio);
	io->bio = NULL;
}

@@ -257,9 +236,6 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index)
	bool need_put = dn->inode_page ? false : true;
	int err;

	/* if inode_page exists, index should be zero */
	f2fs_bug_on(F2FS_I_SB(dn->inode), !need_put && index);

	err = get_dnode_of_data(dn, index, ALLOC_NODE);
	if (err)
		return err;
@@ -740,14 +716,14 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
static int f2fs_read_data_page(struct file *file, struct page *page)
{
	struct inode *inode = page->mapping->host;
	int ret;
	int ret = -EAGAIN;

	trace_f2fs_readpage(page, DATA);

	/* If the file has inline data, try to read it directly */
	if (f2fs_has_inline_data(inode))
		ret = f2fs_read_inline_data(inode, page);
	else
	if (ret == -EAGAIN)
		ret = mpage_readpage(page, get_data_block);

	return ret;
@@ -859,10 +835,11 @@ static int f2fs_write_data_page(struct page *page,
	else if (has_not_enough_free_secs(sbi, 0))
		goto redirty_out;

	err = -EAGAIN;
	f2fs_lock_op(sbi);
	if (f2fs_has_inline_data(inode) || f2fs_may_inline(inode))
		err = f2fs_write_inline_data(inode, page, offset);
	else
	if (f2fs_has_inline_data(inode))
		err = f2fs_write_inline_data(inode, page);
	if (err == -EAGAIN)
		err = do_write_data_page(page, &fio);
	f2fs_unlock_op(sbi);
done:
@@ -951,7 +928,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
{
	struct inode *inode = mapping->host;
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct page *page;
	struct page *page, *ipage;
	pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
	struct dnode_of_data dn;
	int err = 0;
@@ -959,45 +936,60 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	trace_f2fs_write_begin(inode, pos, len, flags);

	f2fs_balance_fs(sbi);
repeat:
	err = f2fs_convert_inline_data(inode, pos + len, NULL);

	/*
	 * We should check this at this moment to avoid deadlock on inode page
	 * and #0 page. The locking rule for inline_data conversion should be:
	 * lock_page(page #0) -> lock_page(inode_page)
	 */
	if (index != 0) {
		err = f2fs_convert_inline_inode(inode);
		if (err)
			goto fail;

	}
repeat:
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page) {
		err = -ENOMEM;
		goto fail;
	}

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

	*pagep = page;

	if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
		goto inline_data;

	f2fs_lock_op(sbi);
	set_new_dnode(&dn, inode, NULL, NULL, 0);
	err = f2fs_reserve_block(&dn, index);
	f2fs_unlock_op(sbi);
	if (err) {
		f2fs_put_page(page, 0);
		goto fail;
	}
inline_data:
	lock_page(page);
	if (unlikely(page->mapping != mapping)) {
		f2fs_put_page(page, 1);
		goto repeat;

	/* check inline_data */
	ipage = get_node_page(sbi, inode->i_ino);
	if (IS_ERR(ipage)) {
		err = PTR_ERR(ipage);
		goto unlock_fail;
	}

	f2fs_wait_on_page_writeback(page, DATA);
	set_new_dnode(&dn, inode, ipage, ipage, 0);

	if (f2fs_has_inline_data(inode)) {
		if (pos + len <= MAX_INLINE_DATA) {
			read_inline_data(page, ipage);
			set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
			sync_inode_page(&dn);
			goto put_next;
		}
		err = f2fs_convert_inline_page(&dn, page);
		if (err)
			goto put_fail;
	}
	err = f2fs_reserve_block(&dn, index);
	if (err)
		goto put_fail;
put_next:
	f2fs_put_dnode(&dn);
	f2fs_unlock_op(sbi);

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

	f2fs_wait_on_page_writeback(page, DATA);

	if ((pos & PAGE_CACHE_MASK) >= i_size_read(inode)) {
		unsigned start = pos & (PAGE_CACHE_SIZE - 1);
		unsigned end = start + len;
@@ -1009,19 +1001,11 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,

	if (dn.data_blkaddr == NEW_ADDR) {
		zero_user_segment(page, 0, PAGE_CACHE_SIZE);
	} else {
		if (f2fs_has_inline_data(inode)) {
			err = f2fs_read_inline_data(inode, page);
			if (err) {
				page_cache_release(page);
				goto fail;
			}
	} else {
		err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
					   READ_SYNC);
		if (err)
			goto fail;
		}

		lock_page(page);
		if (unlikely(!PageUptodate(page))) {
@@ -1038,6 +1022,12 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	SetPageUptodate(page);
	clear_cold_data(page);
	return 0;

put_fail:
	f2fs_put_dnode(&dn);
unlock_fail:
	f2fs_unlock_op(sbi);
	f2fs_put_page(page, 1);
fail:
	f2fs_write_failed(mapping, pos + len);
	return err;
@@ -1052,9 +1042,6 @@ static int f2fs_write_end(struct file *file,

	trace_f2fs_write_end(inode, pos, len, copied);

	if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
		register_inmem_page(inode, page);
	else
	set_page_dirty(page);

	if (pos + copied > i_size_read(inode)) {
@@ -1093,9 +1080,12 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
	size_t count = iov_iter_count(iter);
	int err;

	/* Let buffer I/O handle the inline data case. */
	if (f2fs_has_inline_data(inode))
		return 0;
	/* we don't need to use inline_data strictly */
	if (f2fs_has_inline_data(inode)) {
		err = f2fs_convert_inline_inode(inode);
		if (err)
			return err;
	}

	if (check_direct_IO(inode, rw, iter, offset))
		return 0;
@@ -1119,6 +1109,9 @@ static void f2fs_invalidate_data_page(struct page *page, unsigned int offset,
	if (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE)
		return;

	if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
		invalidate_inmem_page(inode, page);

	if (PageDirty(page))
		inode_dec_dirty_pages(inode);
	ClearPagePrivate(page);
@@ -1138,6 +1131,12 @@ static int f2fs_set_data_page_dirty(struct page *page)
	trace_f2fs_set_page_dirty(page, DATA);

	SetPageUptodate(page);

	if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) {
		register_inmem_page(inode, page);
		return 1;
	}

	mark_inode_dirty(inode);

	if (!PageDirty(page)) {
@@ -1152,9 +1151,12 @@ 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;

	/* we don't need to use inline_data strictly */
	if (f2fs_has_inline_data(inode)) {
		int err = f2fs_convert_inline_inode(inode);
		if (err)
			return err;
	}
	return generic_block_bmap(mapping, block, get_data_block);
}

Loading