Commit 25c4e6c3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "This round introduces several interesting features such as on-disk NAT
  bitmaps, IO alignment, and a discard thread. And it includes a couple
  of major bug fixes as below.

  Enhancements:

   - introduce on-disk bitmaps to avoid scanning NAT blocks when getting
     free nids

   - support IO alignment to prepare open-channel SSD integration in
     future

   - introduce a discard thread to avoid long latency during checkpoint
     and fstrim

   - use SSR for warm node and enable inline_xattr by default

   - introduce in-memory bitmaps to check FS consistency for debugging

   - improve write_begin by avoiding needless read IO

  Bug fixes:

   - fix broken zone_reset behavior for SMR drive

   - fix wrong victim selection policy during GC

   - fix missing behavior when preparing discard commands

   - fix bugs in atomic write support and fiemap

   - workaround to handle multiple f2fs_add_link calls having same name

  ... and it includes a bunch of clean-up patches as well"

* tag 'for-f2fs-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (97 commits)
  f2fs: avoid to flush nat journal entries
  f2fs: avoid to issue redundant discard commands
  f2fs: fix a plint compile warning
  f2fs: add f2fs_drop_inode tracepoint
  f2fs: Fix zoned block device support
  f2fs: remove redundant set_page_dirty()
  f2fs: fix to enlarge size of write_io_dummy mempool
  f2fs: fix memory leak of write_io_dummy mempool during umount
  f2fs: fix to update F2FS_{CP_}WB_DATA count correctly
  f2fs: use MAX_FREE_NIDS for the free nids target
  f2fs: introduce free nid bitmap
  f2fs: new helper cur_cp_crc() getting crc in f2fs_checkpoint
  f2fs: update the comment of default nr_pages to skipping
  f2fs: drop the duplicate pval in f2fs_getxattr
  f2fs: Don't update the xattr data that same as the exist
  f2fs: kill __is_extent_same
  f2fs: avoid bggc->fggc when enough free segments are avaliable after cp
  f2fs: select target segment with closer temperature in SSR mode
  f2fs: show simple call stack in fault injection message
  f2fs: no need lock_op in f2fs_write_inline_data
  ...
parents 6053dc98 900f7362
Loading
Loading
Loading
Loading
+5 −2
Original line number Original line Diff line number Diff line
@@ -125,13 +125,14 @@ active_logs=%u Support configuring the number of active logs. In the
disable_ext_identify   Disable the extension list configured by mkfs, so f2fs
disable_ext_identify   Disable the extension list configured by mkfs, so f2fs
                       does not aware of cold files such as media files.
                       does not aware of cold files such as media files.
inline_xattr           Enable the inline xattrs feature.
inline_xattr           Enable the inline xattrs feature.
noinline_xattr         Disable the inline xattrs feature.
inline_data            Enable the inline data feature: New created small(<~3.4k)
inline_data            Enable the inline data feature: New created small(<~3.4k)
                       files can be written into inode block.
                       files can be written into inode block.
inline_dentry          Enable the inline dir feature: data in new created
inline_dentry          Enable the inline dir feature: data in new created
                       directory entries can be written into inode block. The
                       directory entries can be written into inode block. The
                       space of inode block which is used to store inline
                       space of inode block which is used to store inline
                       dentries is limited to ~3.4k.
                       dentries is limited to ~3.4k.
noinline_dentry        Diable the inline dentry feature.
noinline_dentry        Disable the inline dentry feature.
flush_merge	       Merge concurrent cache_flush commands as much as possible
flush_merge	       Merge concurrent cache_flush commands as much as possible
                       to eliminate redundant command issues. If the underlying
                       to eliminate redundant command issues. If the underlying
		       device handles the cache_flush command relatively slowly,
		       device handles the cache_flush command relatively slowly,
@@ -157,6 +158,8 @@ data_flush Enable data flushing before checkpoint in order to
mode=%s                Control block allocation mode which supports "adaptive"
mode=%s                Control block allocation mode which supports "adaptive"
                       and "lfs". In "lfs" mode, there should be no random
                       and "lfs". In "lfs" mode, there should be no random
                       writes towards main area.
                       writes towards main area.
io_bits=%u             Set the bit size of write IO requests. It should be set
                       with "mode=lfs".


================================================================================
================================================================================
DEBUGFS ENTRIES
DEBUGFS ENTRIES
@@ -174,7 +177,7 @@ f2fs. Each file shows the whole f2fs information.
SYSFS ENTRIES
SYSFS ENTRIES
================================================================================
================================================================================


Information about mounted f2f2 file systems can be found in
Information about mounted f2fs file systems can be found in
/sys/fs/f2fs.  Each mounted filesystem will have a directory in
/sys/fs/f2fs.  Each mounted filesystem will have a directory in
/sys/fs/f2fs based on its device name (i.e., /sys/fs/f2fs/sda).
/sys/fs/f2fs based on its device name (i.e., /sys/fs/f2fs/sda).
The files in each per-device directory are shown in table below.
The files in each per-device directory are shown in table below.
+49 −21
Original line number Original line Diff line number Diff line
@@ -249,7 +249,8 @@ static int f2fs_write_meta_page(struct page *page,
	dec_page_count(sbi, F2FS_DIRTY_META);
	dec_page_count(sbi, F2FS_DIRTY_META);


	if (wbc->for_reclaim)
	if (wbc->for_reclaim)
		f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, META, WRITE);
		f2fs_submit_merged_bio_cond(sbi, page->mapping->host,
						0, page->index, META, WRITE);


	unlock_page(page);
	unlock_page(page);


@@ -493,6 +494,7 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
#ifdef CONFIG_F2FS_FAULT_INJECTION
#ifdef CONFIG_F2FS_FAULT_INJECTION
	if (time_to_inject(sbi, FAULT_ORPHAN)) {
	if (time_to_inject(sbi, FAULT_ORPHAN)) {
		spin_unlock(&im->ino_lock);
		spin_unlock(&im->ino_lock);
		f2fs_show_injection_info(FAULT_ORPHAN);
		return -ENOSPC;
		return -ENOSPC;
	}
	}
#endif
#endif
@@ -681,8 +683,7 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
		return -EINVAL;
		return -EINVAL;
	}
	}


	crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block
	crc = cur_cp_crc(*cp_block);
							+ crc_offset)));
	if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
	if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
		f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
		f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
		return -EINVAL;
		return -EINVAL;
@@ -891,7 +892,7 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
				F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA));
				F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA));
		return 0;
		return 0;
	}
	}
	fi = list_entry(head->next, struct f2fs_inode_info, dirty_list);
	fi = list_first_entry(head, struct f2fs_inode_info, dirty_list);
	inode = igrab(&fi->vfs_inode);
	inode = igrab(&fi->vfs_inode);
	spin_unlock(&sbi->inode_lock[type]);
	spin_unlock(&sbi->inode_lock[type]);
	if (inode) {
	if (inode) {
@@ -924,7 +925,7 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
			spin_unlock(&sbi->inode_lock[DIRTY_META]);
			spin_unlock(&sbi->inode_lock[DIRTY_META]);
			return 0;
			return 0;
		}
		}
		fi = list_entry(head->next, struct f2fs_inode_info,
		fi = list_first_entry(head, struct f2fs_inode_info,
							gdirty_list);
							gdirty_list);
		inode = igrab(&fi->vfs_inode);
		inode = igrab(&fi->vfs_inode);
		spin_unlock(&sbi->inode_lock[DIRTY_META]);
		spin_unlock(&sbi->inode_lock[DIRTY_META]);
@@ -998,8 +999,6 @@ 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, false);
	f2fs_unlock_all(sbi);
	f2fs_unlock_all(sbi);
}
}


@@ -1025,6 +1024,10 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)


	spin_lock(&sbi->cp_lock);
	spin_lock(&sbi->cp_lock);


	if (cpc->reason == CP_UMOUNT && ckpt->cp_pack_total_block_count >
			sbi->blocks_per_seg - NM_I(sbi)->nat_bits_blocks)
		disable_nat_bits(sbi, false);

	if (cpc->reason == CP_UMOUNT)
	if (cpc->reason == CP_UMOUNT)
		__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
		__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
	else
	else
@@ -1137,6 +1140,28 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)


	start_blk = __start_cp_next_addr(sbi);
	start_blk = __start_cp_next_addr(sbi);


	/* write nat bits */
	if (enabled_nat_bits(sbi, cpc)) {
		__u64 cp_ver = cur_cp_version(ckpt);
		unsigned int i;
		block_t blk;

		cp_ver |= ((__u64)crc32 << 32);
		*(__le64 *)nm_i->nat_bits = cpu_to_le64(cp_ver);

		blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks;
		for (i = 0; i < nm_i->nat_bits_blocks; i++)
			update_meta_page(sbi, nm_i->nat_bits +
					(i << F2FS_BLKSIZE_BITS), blk + i);

		/* Flush all the NAT BITS pages */
		while (get_pages(sbi, F2FS_DIRTY_META)) {
			sync_meta_pages(sbi, META, LONG_MAX);
			if (unlikely(f2fs_cp_error(sbi)))
				return -EIO;
		}
	}

	/* need to wait for end_io results */
	/* need to wait for end_io results */
	wait_on_all_pages_writeback(sbi);
	wait_on_all_pages_writeback(sbi);
	if (unlikely(f2fs_cp_error(sbi)))
	if (unlikely(f2fs_cp_error(sbi)))
@@ -1248,16 +1273,21 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	f2fs_flush_merged_bios(sbi);
	f2fs_flush_merged_bios(sbi);


	/* this is the case of multiple fstrims without any changes */
	/* this is the case of multiple fstrims without any changes */
	if (cpc->reason == CP_DISCARD && !is_sbi_flag_set(sbi, SBI_IS_DIRTY)) {
	if (cpc->reason == CP_DISCARD) {
		f2fs_bug_on(sbi, NM_I(sbi)->dirty_nat_cnt);
		if (!exist_trim_candidates(sbi, cpc)) {
		f2fs_bug_on(sbi, SIT_I(sbi)->dirty_sentries);
			unblock_operations(sbi);
		f2fs_bug_on(sbi, prefree_segments(sbi));
			goto out;
		}

		if (NM_I(sbi)->dirty_nat_cnt == 0 &&
				SIT_I(sbi)->dirty_sentries == 0 &&
				prefree_segments(sbi) == 0) {
			flush_sit_entries(sbi, cpc);
			flush_sit_entries(sbi, cpc);
			clear_prefree_segments(sbi, cpc);
			clear_prefree_segments(sbi, cpc);
		f2fs_wait_all_discard_bio(sbi);
			unblock_operations(sbi);
			unblock_operations(sbi);
			goto out;
			goto out;
		}
		}
	}


	/*
	/*
	 * update checkpoint pack index
	 * update checkpoint pack index
@@ -1268,17 +1298,15 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);
	ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);


	/* write cached NAT/SIT entries to NAT/SIT area */
	/* write cached NAT/SIT entries to NAT/SIT area */
	flush_nat_entries(sbi);
	flush_nat_entries(sbi, cpc);
	flush_sit_entries(sbi, cpc);
	flush_sit_entries(sbi, cpc);


	/* unlock all the fs_lock[] in do_checkpoint() */
	/* unlock all the fs_lock[] in do_checkpoint() */
	err = do_checkpoint(sbi, cpc);
	err = do_checkpoint(sbi, cpc);
	if (err) {
	if (err)
		release_discard_addrs(sbi);
		release_discard_addrs(sbi);
	} else {
	else
		clear_prefree_segments(sbi, cpc);
		clear_prefree_segments(sbi, cpc);
		f2fs_wait_all_discard_bio(sbi);
	}


	unblock_operations(sbi);
	unblock_operations(sbi);
	stat_inc_cp_count(sbi->stat_info);
	stat_inc_cp_count(sbi->stat_info);
+142 −49
Original line number Original line Diff line number Diff line
@@ -55,8 +55,10 @@ static void f2fs_read_end_io(struct bio *bio)
	int i;
	int i;


#ifdef CONFIG_F2FS_FAULT_INJECTION
#ifdef CONFIG_F2FS_FAULT_INJECTION
	if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO))
	if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) {
		f2fs_show_injection_info(FAULT_IO);
		bio->bi_error = -EIO;
		bio->bi_error = -EIO;
	}
#endif
#endif


	if (f2fs_bio_encrypted(bio)) {
	if (f2fs_bio_encrypted(bio)) {
@@ -93,6 +95,17 @@ static void f2fs_write_end_io(struct bio *bio)
		struct page *page = bvec->bv_page;
		struct page *page = bvec->bv_page;
		enum count_type type = WB_DATA_TYPE(page);
		enum count_type type = WB_DATA_TYPE(page);


		if (IS_DUMMY_WRITTEN_PAGE(page)) {
			set_page_private(page, (unsigned long)NULL);
			ClearPagePrivate(page);
			unlock_page(page);
			mempool_free(page, sbi->write_io_dummy);

			if (unlikely(bio->bi_error))
				f2fs_stop_checkpoint(sbi, true);
			continue;
		}

		fscrypt_pullback_bio_page(&page, true);
		fscrypt_pullback_bio_page(&page, true);


		if (unlikely(bio->bi_error)) {
		if (unlikely(bio->bi_error)) {
@@ -171,10 +184,46 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
				struct bio *bio, enum page_type type)
				struct bio *bio, enum page_type type)
{
{
	if (!is_read_io(bio_op(bio))) {
	if (!is_read_io(bio_op(bio))) {
		unsigned int start;

		if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
		if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
			current->plug && (type == DATA || type == NODE))
			current->plug && (type == DATA || type == NODE))
			blk_finish_plug(current->plug);
			blk_finish_plug(current->plug);

		if (type != DATA && type != NODE)
			goto submit_io;

		start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
		start %= F2FS_IO_SIZE(sbi);

		if (start == 0)
			goto submit_io;

		/* fill dummy pages */
		for (; start < F2FS_IO_SIZE(sbi); start++) {
			struct page *page =
				mempool_alloc(sbi->write_io_dummy,
					GFP_NOIO | __GFP_ZERO | __GFP_NOFAIL);
			f2fs_bug_on(sbi, !page);

			SetPagePrivate(page);
			set_page_private(page, (unsigned long)DUMMY_WRITTEN_PAGE);
			lock_page(page);
			if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
				f2fs_bug_on(sbi, 1);
		}
		}
		/*
		 * In the NODE case, we lose next block address chain. So, we
		 * need to do checkpoint in f2fs_sync_file.
		 */
		if (type == NODE)
			set_sbi_flag(sbi, SBI_NEED_CP);
	}
submit_io:
	if (is_read_io(bio_op(bio)))
		trace_f2fs_submit_read_bio(sbi->sb, type, bio);
	else
		trace_f2fs_submit_write_bio(sbi->sb, type, bio);
	submit_bio(bio);
	submit_bio(bio);
}
}


@@ -185,19 +234,19 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)
	if (!io->bio)
	if (!io->bio)
		return;
		return;


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

	if (is_read_io(fio->op))
	if (is_read_io(fio->op))
		trace_f2fs_submit_read_bio(io->sbi->sb, fio, io->bio);
		trace_f2fs_prepare_read_bio(io->sbi->sb, fio->type, io->bio);
	else
	else
		trace_f2fs_submit_write_bio(io->sbi->sb, fio, io->bio);
		trace_f2fs_prepare_write_bio(io->sbi->sb, fio->type, io->bio);

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


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


static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,
static bool __has_merged_page(struct f2fs_bio_info *io,
						struct page *page, nid_t ino)
				struct inode *inode, nid_t ino, pgoff_t idx)
{
{
	struct bio_vec *bvec;
	struct bio_vec *bvec;
	struct page *target;
	struct page *target;
@@ -206,7 +255,7 @@ static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,
	if (!io->bio)
	if (!io->bio)
		return false;
		return false;


	if (!inode && !page && !ino)
	if (!inode && !ino)
		return true;
		return true;


	bio_for_each_segment_all(bvec, io->bio, i) {
	bio_for_each_segment_all(bvec, io->bio, i) {
@@ -216,10 +265,11 @@ static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,
		else
		else
			target = fscrypt_control_page(bvec->bv_page);
			target = fscrypt_control_page(bvec->bv_page);


		if (idx != target->index)
			continue;

		if (inode && inode == target->mapping->host)
		if (inode && inode == target->mapping->host)
			return true;
			return true;
		if (page && page == target)
			return true;
		if (ino && ino == ino_of_node(target))
		if (ino && ino == ino_of_node(target))
			return true;
			return true;
	}
	}
@@ -228,22 +278,21 @@ static bool __has_merged_page(struct f2fs_bio_info *io, struct inode *inode,
}
}


static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
						struct page *page, nid_t ino,
				nid_t ino, pgoff_t idx, enum page_type type)
						enum page_type type)
{
{
	enum page_type btype = PAGE_TYPE_OF_BIO(type);
	enum page_type btype = PAGE_TYPE_OF_BIO(type);
	struct f2fs_bio_info *io = &sbi->write_io[btype];
	struct f2fs_bio_info *io = &sbi->write_io[btype];
	bool ret;
	bool ret;


	down_read(&io->io_rwsem);
	down_read(&io->io_rwsem);
	ret = __has_merged_page(io, inode, page, ino);
	ret = __has_merged_page(io, inode, ino, idx);
	up_read(&io->io_rwsem);
	up_read(&io->io_rwsem);
	return ret;
	return ret;
}
}


static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
				struct inode *inode, struct page *page,
				struct inode *inode, nid_t ino, pgoff_t idx,
				nid_t ino, enum page_type type, int rw)
				enum page_type type, int rw)
{
{
	enum page_type btype = PAGE_TYPE_OF_BIO(type);
	enum page_type btype = PAGE_TYPE_OF_BIO(type);
	struct f2fs_bio_info *io;
	struct f2fs_bio_info *io;
@@ -252,16 +301,16 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,


	down_write(&io->io_rwsem);
	down_write(&io->io_rwsem);


	if (!__has_merged_page(io, inode, page, ino))
	if (!__has_merged_page(io, inode, ino, idx))
		goto out;
		goto out;


	/* change META to META_FLUSH in the checkpoint procedure */
	/* change META to META_FLUSH in the checkpoint procedure */
	if (type >= META_FLUSH) {
	if (type >= META_FLUSH) {
		io->fio.type = META_FLUSH;
		io->fio.type = META_FLUSH;
		io->fio.op = REQ_OP_WRITE;
		io->fio.op = REQ_OP_WRITE;
		io->fio.op_flags = REQ_PREFLUSH | REQ_META | REQ_PRIO;
		io->fio.op_flags = REQ_META | REQ_PRIO;
		if (!test_opt(sbi, NOBARRIER))
		if (!test_opt(sbi, NOBARRIER))
			io->fio.op_flags |= REQ_FUA;
			io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
	}
	}
	__submit_merged_bio(io);
	__submit_merged_bio(io);
out:
out:
@@ -271,15 +320,15 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
									int rw)
									int rw)
{
{
	__f2fs_submit_merged_bio(sbi, NULL, NULL, 0, type, rw);
	__f2fs_submit_merged_bio(sbi, NULL, 0, 0, type, rw);
}
}


void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
				struct inode *inode, struct page *page,
				struct inode *inode, nid_t ino, pgoff_t idx,
				nid_t ino, enum page_type type, int rw)
				enum page_type type, int rw)
{
{
	if (has_merged_page(sbi, inode, page, ino, type))
	if (has_merged_page(sbi, inode, ino, idx, type))
		__f2fs_submit_merged_bio(sbi, inode, page, ino, type, rw);
		__f2fs_submit_merged_bio(sbi, inode, ino, idx, type, rw);
}
}


void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
@@ -315,13 +364,14 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
	return 0;
	return 0;
}
}


void f2fs_submit_page_mbio(struct f2fs_io_info *fio)
int f2fs_submit_page_mbio(struct f2fs_io_info *fio)
{
{
	struct f2fs_sb_info *sbi = fio->sbi;
	struct f2fs_sb_info *sbi = fio->sbi;
	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
	struct f2fs_bio_info *io;
	struct f2fs_bio_info *io;
	bool is_read = is_read_io(fio->op);
	bool is_read = is_read_io(fio->op);
	struct page *bio_page;
	struct page *bio_page;
	int err = 0;


	io = is_read ? &sbi->read_io : &sbi->write_io[btype];
	io = is_read ? &sbi->read_io : &sbi->write_io[btype];


@@ -331,6 +381,9 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio)


	bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
	bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;


	/* set submitted = 1 as a return value */
	fio->submitted = 1;

	if (!is_read)
	if (!is_read)
		inc_page_count(sbi, WB_DATA_TYPE(bio_page));
		inc_page_count(sbi, WB_DATA_TYPE(bio_page));


@@ -342,6 +395,13 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio)
		__submit_merged_bio(io);
		__submit_merged_bio(io);
alloc_new:
alloc_new:
	if (io->bio == NULL) {
	if (io->bio == NULL) {
		if ((fio->type == DATA || fio->type == NODE) &&
				fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) {
			err = -EAGAIN;
			if (!is_read)
				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,
						BIO_MAX_PAGES, is_read);
						BIO_MAX_PAGES, is_read);
		io->fio = *fio;
		io->fio = *fio;
@@ -355,9 +415,10 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio)


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

out_fail:
	up_write(&io->io_rwsem);
	up_write(&io->io_rwsem);
	trace_f2fs_submit_page_mbio(fio->page, fio);
	trace_f2fs_submit_page_mbio(fio->page, fio);
	return err;
}
}


static void __set_data_blkaddr(struct dnode_of_data *dn)
static void __set_data_blkaddr(struct dnode_of_data *dn)
@@ -453,7 +514,7 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index)


int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
{
{
	struct extent_info ei;
	struct extent_info ei  = {0,0,0};
	struct inode *inode = dn->inode;
	struct inode *inode = dn->inode;


	if (f2fs_lookup_extent_cache(inode, index, &ei)) {
	if (f2fs_lookup_extent_cache(inode, index, &ei)) {
@@ -470,7 +531,7 @@ struct page *get_read_data_page(struct inode *inode, pgoff_t index,
	struct address_space *mapping = inode->i_mapping;
	struct address_space *mapping = inode->i_mapping;
	struct dnode_of_data dn;
	struct dnode_of_data dn;
	struct page *page;
	struct page *page;
	struct extent_info ei;
	struct extent_info ei = {0,0,0};
	int err;
	int err;
	struct f2fs_io_info fio = {
	struct f2fs_io_info fio = {
		.sbi = F2FS_I_SB(inode),
		.sbi = F2FS_I_SB(inode),
@@ -694,6 +755,9 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
	struct f2fs_map_blocks map;
	struct f2fs_map_blocks map;
	int err = 0;
	int err = 0;


	if (is_inode_flag_set(inode, FI_NO_PREALLOC))
		return 0;

	map.m_lblk = F2FS_BLK_ALIGN(iocb->ki_pos);
	map.m_lblk = F2FS_BLK_ALIGN(iocb->ki_pos);
	map.m_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from));
	map.m_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from));
	if (map.m_len > map.m_lblk)
	if (map.m_len > map.m_lblk)
@@ -742,7 +806,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
	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;
	blkcnt_t prealloc;
	blkcnt_t prealloc;
	struct extent_info ei;
	struct extent_info ei = {0,0,0};
	block_t blkaddr;
	block_t blkaddr;


	if (!maxblocks)
	if (!maxblocks)
@@ -806,7 +870,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
			}
			}
			if (err)
			if (err)
				goto sync_out;
				goto sync_out;
			map->m_flags = F2FS_MAP_NEW;
			map->m_flags |= F2FS_MAP_NEW;
			blkaddr = dn.data_blkaddr;
			blkaddr = dn.data_blkaddr;
		} else {
		} else {
			if (flag == F2FS_GET_BLOCK_BMAP) {
			if (flag == F2FS_GET_BLOCK_BMAP) {
@@ -906,7 +970,7 @@ static int __get_data_block(struct inode *inode, sector_t iblock,
	if (!err) {
	if (!err) {
		map_bh(bh, inode->i_sb, map.m_pblk);
		map_bh(bh, inode->i_sb, map.m_pblk);
		bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags;
		bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags;
		bh->b_size = map.m_len << inode->i_blkbits;
		bh->b_size = (u64)map.m_len << inode->i_blkbits;
	}
	}
	return err;
	return err;
}
}
@@ -1088,7 +1152,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping,


		prefetchw(&page->flags);
		prefetchw(&page->flags);
		if (pages) {
		if (pages) {
			page = list_entry(pages->prev, struct page, lru);
			page = list_last_entry(pages, struct page, lru);
			list_del(&page->lru);
			list_del(&page->lru);
			if (add_to_page_cache_lru(page, mapping,
			if (add_to_page_cache_lru(page, mapping,
						  page->index,
						  page->index,
@@ -1207,7 +1271,7 @@ static int f2fs_read_data_pages(struct file *file,
			struct list_head *pages, unsigned nr_pages)
			struct list_head *pages, unsigned nr_pages)
{
{
	struct inode *inode = file->f_mapping->host;
	struct inode *inode = file->f_mapping->host;
	struct page *page = list_entry(pages->prev, struct page, lru);
	struct page *page = list_last_entry(pages, struct page, lru);


	trace_f2fs_readpages(inode, page, nr_pages);
	trace_f2fs_readpages(inode, page, nr_pages);


@@ -1288,7 +1352,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
	return err;
	return err;
}
}


static int f2fs_write_data_page(struct page *page,
static int __write_data_page(struct page *page, bool *submitted,
				struct writeback_control *wbc)
				struct writeback_control *wbc)
{
{
	struct inode *inode = page->mapping->host;
	struct inode *inode = page->mapping->host;
@@ -1307,6 +1371,7 @@ static int f2fs_write_data_page(struct page *page,
		.op_flags = wbc_to_write_flags(wbc),
		.op_flags = wbc_to_write_flags(wbc),
		.page = page,
		.page = page,
		.encrypted_page = NULL,
		.encrypted_page = NULL,
		.submitted = false,
	};
	};


	trace_f2fs_writepage(page, DATA);
	trace_f2fs_writepage(page, DATA);
@@ -1352,9 +1417,12 @@ static int f2fs_write_data_page(struct page *page,
		goto redirty_out;
		goto redirty_out;


	err = -EAGAIN;
	err = -EAGAIN;
	f2fs_lock_op(sbi);
	if (f2fs_has_inline_data(inode)) {
	if (f2fs_has_inline_data(inode))
		err = f2fs_write_inline_data(inode, page);
		err = f2fs_write_inline_data(inode, page);
		if (!err)
			goto out;
	}
	f2fs_lock_op(sbi);
	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)
	if (F2FS_I(inode)->last_disk_size < psize)
@@ -1370,15 +1438,22 @@ static int f2fs_write_data_page(struct page *page,
		ClearPageUptodate(page);
		ClearPageUptodate(page);


	if (wbc->for_reclaim) {
	if (wbc->for_reclaim) {
		f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, DATA, WRITE);
		f2fs_submit_merged_bio_cond(sbi, inode, 0, page->index,
						DATA, WRITE);
		remove_dirty_inode(inode);
		remove_dirty_inode(inode);
		submitted = NULL;
	}
	}


	unlock_page(page);
	unlock_page(page);
	f2fs_balance_fs(sbi, need_balance_fs);
	f2fs_balance_fs(sbi, need_balance_fs);


	if (unlikely(f2fs_cp_error(sbi)))
	if (unlikely(f2fs_cp_error(sbi))) {
		f2fs_submit_merged_bio(sbi, DATA, WRITE);
		f2fs_submit_merged_bio(sbi, DATA, WRITE);
		submitted = NULL;
	}

	if (submitted)
		*submitted = fio.submitted;


	return 0;
	return 0;


@@ -1390,6 +1465,12 @@ static int f2fs_write_data_page(struct page *page,
	return err;
	return err;
}
}


static int f2fs_write_data_page(struct page *page,
					struct writeback_control *wbc)
{
	return __write_data_page(page, NULL, wbc);
}

/*
/*
 * This function was copied from write_cche_pages from mm/page-writeback.c.
 * This function was copied from write_cche_pages from mm/page-writeback.c.
 * The major change is making write step of cold data page separately from
 * The major change is making write step of cold data page separately from
@@ -1406,10 +1487,10 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
	pgoff_t index;
	pgoff_t index;
	pgoff_t end;		/* Inclusive */
	pgoff_t end;		/* Inclusive */
	pgoff_t done_index;
	pgoff_t done_index;
	pgoff_t last_idx = ULONG_MAX;
	int cycled;
	int cycled;
	int range_whole = 0;
	int range_whole = 0;
	int tag;
	int tag;
	int nwritten = 0;


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


@@ -1446,6 +1527,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,


		for (i = 0; i < nr_pages; i++) {
		for (i = 0; i < nr_pages; i++) {
			struct page *page = pvec.pages[i];
			struct page *page = pvec.pages[i];
			bool submitted = false;


			if (page->index > end) {
			if (page->index > end) {
				done = 1;
				done = 1;
@@ -1479,7 +1561,7 @@ 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 = mapping->a_ops->writepage(page, wbc);
			ret = __write_data_page(page, &submitted, wbc);
			if (unlikely(ret)) {
			if (unlikely(ret)) {
				/*
				/*
				 * keep nr_to_write, since vfs uses this to
				 * keep nr_to_write, since vfs uses this to
@@ -1493,8 +1575,8 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
				done_index = page->index + 1;
				done_index = page->index + 1;
				done = 1;
				done = 1;
				break;
				break;
			} else {
			} else if (submitted) {
				nwritten++;
				last_idx = page->index;
			}
			}


			if (--wbc->nr_to_write <= 0 &&
			if (--wbc->nr_to_write <= 0 &&
@@ -1516,9 +1598,9 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
		mapping->writeback_index = done_index;
		mapping->writeback_index = done_index;


	if (nwritten)
	if (last_idx != ULONG_MAX)
		f2fs_submit_merged_bio_cond(F2FS_M_SB(mapping), mapping->host,
		f2fs_submit_merged_bio_cond(F2FS_M_SB(mapping), mapping->host,
							NULL, 0, DATA, WRITE);
						0, last_idx, DATA, WRITE);


	return ret;
	return ret;
}
}
@@ -1591,14 +1673,15 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
	struct dnode_of_data dn;
	struct dnode_of_data dn;
	struct page *ipage;
	struct page *ipage;
	bool locked = false;
	bool locked = false;
	struct extent_info ei;
	struct extent_info ei = {0,0,0};
	int err = 0;
	int err = 0;


	/*
	/*
	 * we already allocated all the blocks, so we don't need to get
	 * we already allocated all the blocks, so we don't need to get
	 * the block addresses when there is no need to fill the page.
	 * the block addresses when there is no need to fill the page.
	 */
	 */
	if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE)
	if (!f2fs_has_inline_data(inode) && len == PAGE_SIZE &&
			!is_inode_flag_set(inode, FI_NO_PREALLOC))
		return 0;
		return 0;


	if (f2fs_has_inline_data(inode) ||
	if (f2fs_has_inline_data(inode) ||
@@ -1682,7 +1765,12 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
			goto fail;
			goto fail;
	}
	}
repeat:
repeat:
	page = grab_cache_page_write_begin(mapping, index, flags);
	/*
	 * Do not use grab_cache_page_write_begin() to avoid deadlock due to
	 * wait_for_stable_page. Will wait that below with our IO control.
	 */
	page = pagecache_get_page(mapping, index,
				FGP_LOCK | FGP_WRITE | FGP_CREAT, GFP_NOFS);
	if (!page) {
	if (!page) {
		err = -ENOMEM;
		err = -ENOMEM;
		goto fail;
		goto fail;
@@ -1715,6 +1803,11 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	if (len == PAGE_SIZE || PageUptodate(page))
	if (len == PAGE_SIZE || PageUptodate(page))
		return 0;
		return 0;


	if (!(pos & (PAGE_SIZE - 1)) && (pos + len) >= i_size_read(inode)) {
		zero_user_segment(page, len, PAGE_SIZE);
		return 0;
	}

	if (blkaddr == NEW_ADDR) {
	if (blkaddr == NEW_ADDR) {
		zero_user_segment(page, 0, PAGE_SIZE);
		zero_user_segment(page, 0, PAGE_SIZE);
		SetPageUptodate(page);
		SetPageUptodate(page);
@@ -1768,7 +1861,7 @@ static int f2fs_write_end(struct file *file,
	 * let generic_perform_write() try to copy data again through copied=0.
	 * let generic_perform_write() try to copy data again through copied=0.
	 */
	 */
	if (!PageUptodate(page)) {
	if (!PageUptodate(page)) {
		if (unlikely(copied != PAGE_SIZE))
		if (unlikely(copied != len))
			copied = 0;
			copied = 0;
		else
		else
			SetPageUptodate(page);
			SetPageUptodate(page);
@@ -1917,7 +2010,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
	if (!PageUptodate(page))
	if (!PageUptodate(page))
		SetPageUptodate(page);
		SetPageUptodate(page);


	if (f2fs_is_atomic_file(inode)) {
	if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
		if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
		if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
			register_inmem_page(inode, page);
			register_inmem_page(inode, page);
			return 1;
			return 1;
+26 −5
Original line number Original line Diff line number Diff line
@@ -50,8 +50,16 @@ static void update_general_status(struct f2fs_sb_info *sbi)
	si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
	si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
	si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
	si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
	si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
	si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
	si->aw_cnt = atomic_read(&sbi->aw_cnt);
	si->max_aw_cnt = atomic_read(&sbi->max_aw_cnt);
	si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA);
	si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA);
	si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA);
	si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA);
	if (SM_I(sbi) && SM_I(sbi)->fcc_info)
		si->nr_flush =
			atomic_read(&SM_I(sbi)->fcc_info->submit_flush);
	if (SM_I(sbi) && SM_I(sbi)->dcc_info)
		si->nr_discard =
			atomic_read(&SM_I(sbi)->dcc_info->submit_discard);
	si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
	si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
	si->rsvd_segs = reserved_segments(sbi);
	si->rsvd_segs = reserved_segments(sbi);
	si->overp_segs = overprovision_segments(sbi);
	si->overp_segs = overprovision_segments(sbi);
@@ -62,6 +70,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
	si->inline_xattr = atomic_read(&sbi->inline_xattr);
	si->inline_xattr = atomic_read(&sbi->inline_xattr);
	si->inline_inode = atomic_read(&sbi->inline_inode);
	si->inline_inode = atomic_read(&sbi->inline_inode);
	si->inline_dir = atomic_read(&sbi->inline_dir);
	si->inline_dir = atomic_read(&sbi->inline_dir);
	si->append = sbi->im[APPEND_INO].ino_num;
	si->update = sbi->im[UPDATE_INO].ino_num;
	si->orphans = sbi->im[ORPHAN_INO].ino_num;
	si->orphans = sbi->im[ORPHAN_INO].ino_num;
	si->utilization = utilization(sbi);
	si->utilization = utilization(sbi);


@@ -183,6 +193,9 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
	/* build nm */
	/* build nm */
	si->base_mem += sizeof(struct f2fs_nm_info);
	si->base_mem += sizeof(struct f2fs_nm_info);
	si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
	si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
	si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
	si->base_mem += NM_I(sbi)->nat_blocks * NAT_ENTRY_BITMAP_SIZE;
	si->base_mem += NM_I(sbi)->nat_blocks / 8;


get_cache:
get_cache:
	si->cache_mem = 0;
	si->cache_mem = 0;
@@ -192,8 +205,10 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
		si->cache_mem += sizeof(struct f2fs_gc_kthread);
		si->cache_mem += sizeof(struct f2fs_gc_kthread);


	/* build merge flush thread */
	/* build merge flush thread */
	if (SM_I(sbi)->cmd_control_info)
	if (SM_I(sbi)->fcc_info)
		si->cache_mem += sizeof(struct flush_cmd_control);
		si->cache_mem += sizeof(struct flush_cmd_control);
	if (SM_I(sbi)->dcc_info)
		si->cache_mem += sizeof(struct discard_cmd_control);


	/* free nids */
	/* free nids */
	si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] +
	si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] +
@@ -254,8 +269,8 @@ static int stat_show(struct seq_file *s, void *v)
			   si->inline_inode);
			   si->inline_inode);
		seq_printf(s, "  - Inline_dentry Inode: %u\n",
		seq_printf(s, "  - Inline_dentry Inode: %u\n",
			   si->inline_dir);
			   si->inline_dir);
		seq_printf(s, "  - Orphan Inode: %u\n",
		seq_printf(s, "  - Orphan/Append/Update Inode: %u, %u, %u\n",
			   si->orphans);
			   si->orphans, si->append, si->update);
		seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
		seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
			   si->main_area_segs, si->main_area_sections,
			   si->main_area_segs, si->main_area_sections,
			   si->main_area_zones);
			   si->main_area_zones);
@@ -314,8 +329,11 @@ static int stat_show(struct seq_file *s, void *v)
		seq_printf(s, "  - Inner Struct Count: tree: %d(%d), node: %d\n",
		seq_printf(s, "  - Inner Struct Count: tree: %d(%d), node: %d\n",
				si->ext_tree, si->zombie_tree, si->ext_node);
				si->ext_tree, si->zombie_tree, si->ext_node);
		seq_puts(s, "\nBalancing F2FS Async:\n");
		seq_puts(s, "\nBalancing F2FS Async:\n");
		seq_printf(s, "  - inmem: %4d, wb_cp_data: %4d, wb_data: %4d\n",
		seq_printf(s, "  - IO (CP: %4d, Data: %4d, Flush: %4d, Discard: %4d)\n",
			   si->inmem_pages, si->nr_wb_cp_data, si->nr_wb_data);
			   si->nr_wb_cp_data, si->nr_wb_data,
			   si->nr_flush, si->nr_discard);
		seq_printf(s, "  - inmem: %4d, atomic IO: %4d (Max. %4d)\n",
			   si->inmem_pages, si->aw_cnt, si->max_aw_cnt);
		seq_printf(s, "  - nodes: %4d in %4d\n",
		seq_printf(s, "  - nodes: %4d in %4d\n",
			   si->ndirty_node, si->node_pages);
			   si->ndirty_node, si->node_pages);
		seq_printf(s, "  - dents: %4d in dirs:%4d (%4d)\n",
		seq_printf(s, "  - dents: %4d in dirs:%4d (%4d)\n",
@@ -414,6 +432,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
	atomic_set(&sbi->inline_dir, 0);
	atomic_set(&sbi->inline_dir, 0);
	atomic_set(&sbi->inplace_count, 0);
	atomic_set(&sbi->inplace_count, 0);


	atomic_set(&sbi->aw_cnt, 0);
	atomic_set(&sbi->max_aw_cnt, 0);

	mutex_lock(&f2fs_stat_mutex);
	mutex_lock(&f2fs_stat_mutex);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
	mutex_unlock(&f2fs_stat_mutex);
	mutex_unlock(&f2fs_stat_mutex);
+32 −6
Original line number Original line Diff line number Diff line
@@ -207,10 +207,14 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
		f2fs_put_page(dentry_page, 0);
		f2fs_put_page(dentry_page, 0);
	}
	}


	if (!de && room && F2FS_I(dir)->chash != namehash) {
	/* This is to increase the speed of f2fs_create */
	if (!de && room) {
		F2FS_I(dir)->task = current;
		if (F2FS_I(dir)->chash != namehash) {
			F2FS_I(dir)->chash = namehash;
			F2FS_I(dir)->chash = namehash;
			F2FS_I(dir)->clevel = level;
			F2FS_I(dir)->clevel = level;
		}
		}
	}


	return de;
	return de;
}
}
@@ -548,8 +552,10 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,


start:
start:
#ifdef CONFIG_F2FS_FAULT_INJECTION
#ifdef CONFIG_F2FS_FAULT_INJECTION
	if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH))
	if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH)) {
		f2fs_show_injection_info(FAULT_DIR_DEPTH);
		return -ENOSPC;
		return -ENOSPC;
	}
#endif
#endif
	if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
	if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
		return -ENOSPC;
		return -ENOSPC;
@@ -646,14 +652,34 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
				struct inode *inode, nid_t ino, umode_t mode)
				struct inode *inode, nid_t ino, umode_t mode)
{
{
	struct fscrypt_name fname;
	struct fscrypt_name fname;
	struct page *page = NULL;
	struct f2fs_dir_entry *de = NULL;
	int err;
	int err;


	err = fscrypt_setup_filename(dir, name, 0, &fname);
	err = fscrypt_setup_filename(dir, name, 0, &fname);
	if (err)
	if (err)
		return err;
		return err;


	/*
	 * An immature stakable filesystem shows a race condition between lookup
	 * and create. If we have same task when doing lookup and create, it's
	 * definitely fine as expected by VFS normally. Otherwise, let's just
	 * verify on-disk dentry one more time, which guarantees filesystem
	 * consistency more.
	 */
	if (current != F2FS_I(dir)->task) {
		de = __f2fs_find_entry(dir, &fname, &page);
		F2FS_I(dir)->task = NULL;
	}
	if (de) {
		f2fs_dentry_kunmap(dir, page);
		f2fs_put_page(page, 0);
		err = -EEXIST;
	} else if (IS_ERR(page)) {
		err = PTR_ERR(page);
	} else {
		err = __f2fs_do_add_link(dir, &fname, inode, ino, mode);
		err = __f2fs_do_add_link(dir, &fname, inode, ino, mode);

	}
	fscrypt_free_filename(&fname);
	fscrypt_free_filename(&fname);
	return err;
	return err;
}
}
Loading