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

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 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
                       does not aware of cold files such as media files.
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)
                       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.
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
                       to eliminate redundant command issues. If the underlying
		       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"
                       and "lfs". In "lfs" mode, there should be no random
                       writes towards main area.
io_bits=%u             Set the bit size of write IO requests. It should be set
                       with "mode=lfs".

================================================================================
DEBUGFS ENTRIES
@@ -174,7 +177,7 @@ f2fs. Each file shows the whole f2fs information.
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 based on its device name (i.e., /sys/fs/f2fs/sda).
The files in each per-device directory are shown in table below.
+49 −21
Original line number 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);

	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);

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

	crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block
							+ crc_offset)));
	crc = cur_cp_crc(*cp_block);
	if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
		f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
		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));
		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);
	spin_unlock(&sbi->inode_lock[type]);
	if (inode) {
@@ -924,7 +925,7 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
			spin_unlock(&sbi->inode_lock[DIRTY_META]);
			return 0;
		}
		fi = list_entry(head->next, struct f2fs_inode_info,
		fi = list_first_entry(head, struct f2fs_inode_info,
							gdirty_list);
		inode = igrab(&fi->vfs_inode);
		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)
{
	up_write(&sbi->node_write);

	build_free_nids(sbi, false);
	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);

	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)
		__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
	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);

	/* 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 */
	wait_on_all_pages_writeback(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);

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

	/*
	 * 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);

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

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

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

#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;
	}
#endif

	if (f2fs_bio_encrypted(bio)) {
@@ -93,6 +95,17 @@ static void f2fs_write_end_io(struct bio *bio)
		struct page *page = bvec->bv_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);

		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)
{
	if (!is_read_io(bio_op(bio))) {
		unsigned int start;

		if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
			current->plug && (type == DATA || type == NODE))
			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);
}

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

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

	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
		trace_f2fs_submit_write_bio(io->sbi->sb, fio, io->bio);

	bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
		trace_f2fs_prepare_write_bio(io->sbi->sb, fio->type, io->bio);

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

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

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

	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
			target = fscrypt_control_page(bvec->bv_page);

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

		if (inode && inode == target->mapping->host)
			return true;
		if (page && page == target)
			return true;
		if (ino && ino == ino_of_node(target))
			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,
						struct page *page, nid_t ino,
						enum page_type type)
				nid_t ino, pgoff_t idx, enum page_type type)
{
	enum page_type btype = PAGE_TYPE_OF_BIO(type);
	struct f2fs_bio_info *io = &sbi->write_io[btype];
	bool ret;

	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);
	return ret;
}

static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
				struct inode *inode, struct page *page,
				nid_t ino, enum page_type type, int rw)
				struct inode *inode, nid_t ino, pgoff_t idx,
				enum page_type type, int rw)
{
	enum page_type btype = PAGE_TYPE_OF_BIO(type);
	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);

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

	/* change META to META_FLUSH in the checkpoint procedure */
	if (type >= META_FLUSH) {
		io->fio.type = META_FLUSH;
		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))
			io->fio.op_flags |= REQ_FUA;
			io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
	}
	__submit_merged_bio(io);
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,
									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,
				struct inode *inode, struct page *page,
				nid_t ino, enum page_type type, int rw)
				struct inode *inode, nid_t ino, pgoff_t idx,
				enum page_type type, int rw)
{
	if (has_merged_page(sbi, inode, page, ino, type))
		__f2fs_submit_merged_bio(sbi, inode, page, ino, type, rw);
	if (has_merged_page(sbi, inode, ino, idx, type))
		__f2fs_submit_merged_bio(sbi, inode, ino, idx, type, rw);
}

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;
}

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;
	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
	struct f2fs_bio_info *io;
	bool is_read = is_read_io(fio->op);
	struct page *bio_page;
	int err = 0;

	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;

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

	if (!is_read)
		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);
alloc_new:
	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,
						BIO_MAX_PAGES, is_read);
		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;
	f2fs_trace_ios(fio, 0);

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

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)
{
	struct extent_info ei;
	struct extent_info ei  = {0,0,0};
	struct inode *inode = dn->inode;

	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 dnode_of_data dn;
	struct page *page;
	struct extent_info ei;
	struct extent_info ei = {0,0,0};
	int err;
	struct f2fs_io_info fio = {
		.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;
	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_len = F2FS_BYTES_TO_BLK(iocb->ki_pos + iov_iter_count(from));
	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;
	unsigned int ofs_in_node, last_ofs_in_node;
	blkcnt_t prealloc;
	struct extent_info ei;
	struct extent_info ei = {0,0,0};
	block_t blkaddr;

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

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

@@ -1288,7 +1352,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
	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 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),
		.page = page,
		.encrypted_page = NULL,
		.submitted = false,
	};

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

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

	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);
		submitted = NULL;
	}

	unlock_page(page);
	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);
		submitted = NULL;
	}

	if (submitted)
		*submitted = fio.submitted;

	return 0;

@@ -1390,6 +1465,12 @@ static int f2fs_write_data_page(struct page *page,
	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.
 * 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 end;		/* Inclusive */
	pgoff_t done_index;
	pgoff_t last_idx = ULONG_MAX;
	int cycled;
	int range_whole = 0;
	int tag;
	int nwritten = 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++) {
			struct page *page = pvec.pages[i];
			bool submitted = false;

			if (page->index > end) {
				done = 1;
@@ -1479,7 +1561,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
			if (!clear_page_dirty_for_io(page))
				goto continue_unlock;

			ret = mapping->a_ops->writepage(page, wbc);
			ret = __write_data_page(page, &submitted, wbc);
			if (unlikely(ret)) {
				/*
				 * 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 = 1;
				break;
			} else {
				nwritten++;
			} else if (submitted) {
				last_idx = page->index;
			}

			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))
		mapping->writeback_index = done_index;

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

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

	/*
	 * 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.
	 */
	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;

	if (f2fs_has_inline_data(inode) ||
@@ -1682,7 +1765,12 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
			goto fail;
	}
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) {
		err = -ENOMEM;
		goto fail;
@@ -1715,6 +1803,11 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	if (len == PAGE_SIZE || PageUptodate(page))
		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) {
		zero_user_segment(page, 0, PAGE_SIZE);
		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.
	 */
	if (!PageUptodate(page)) {
		if (unlikely(copied != PAGE_SIZE))
		if (unlikely(copied != len))
			copied = 0;
		else
			SetPageUptodate(page);
@@ -1917,7 +2010,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
	if (!PageUptodate(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)) {
			register_inmem_page(inode, page);
			return 1;
+26 −5
Original line number 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_all = sbi->ndirty_inode[DIRTY_META];
	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_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->rsvd_segs = reserved_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_inode = atomic_read(&sbi->inline_inode);
	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->utilization = utilization(sbi);

@@ -183,6 +193,9 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
	/* build nm */
	si->base_mem += sizeof(struct f2fs_nm_info);
	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:
	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);

	/* 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);
	if (SM_I(sbi)->dcc_info)
		si->cache_mem += sizeof(struct discard_cmd_control);

	/* free nids */
	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);
		seq_printf(s, "  - Inline_dentry Inode: %u\n",
			   si->inline_dir);
		seq_printf(s, "  - Orphan Inode: %u\n",
			   si->orphans);
		seq_printf(s, "  - Orphan/Append/Update Inode: %u, %u, %u\n",
			   si->orphans, si->append, si->update);
		seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
			   si->main_area_segs, si->main_area_sections,
			   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",
				si->ext_tree, si->zombie_tree, si->ext_node);
		seq_puts(s, "\nBalancing F2FS Async:\n");
		seq_printf(s, "  - inmem: %4d, wb_cp_data: %4d, wb_data: %4d\n",
			   si->inmem_pages, si->nr_wb_cp_data, si->nr_wb_data);
		seq_printf(s, "  - IO (CP: %4d, Data: %4d, Flush: %4d, Discard: %4d)\n",
			   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",
			   si->ndirty_node, si->node_pages);
		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->inplace_count, 0);

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

	mutex_lock(&f2fs_stat_mutex);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
	mutex_unlock(&f2fs_stat_mutex);
+32 −6
Original line number 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);
	}

	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)->clevel = level;
		}
	}

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

start:
#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;
	}
#endif
	if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
		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 fscrypt_name fname;
	struct page *page = NULL;
	struct f2fs_dir_entry *de = NULL;
	int err;

	err = fscrypt_setup_filename(dir, name, 0, &fname);
	if (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);

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