Commit ef0c333c authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: keep POSIX_FADV_NOREUSE ranges



This patch records POSIX_FADV_NOREUSE ranges for users to reclaim the caches
instantly off from LRU.

Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 48ea8b20
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
	si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
	si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
	si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
	si->ndonate_files = sbi->donate_files;
	si->nquota_files = sbi->nquota_files;
	si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
	si->aw_cnt = atomic_read(&sbi->atomic_files);
@@ -501,6 +502,8 @@ static int stat_show(struct seq_file *s, void *v)
			   si->compr_inode, si->compr_blocks);
		seq_printf(s, "  - Swapfile Inode: %u\n",
			   si->swapfile_inode);
		seq_printf(s, "  - Donate Inode: %u\n",
			   si->ndonate_files);
		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",
+11 −1
Original line number Diff line number Diff line
@@ -850,6 +850,11 @@ struct f2fs_inode_info {
#endif
	struct list_head dirty_list;	/* dirty list for dirs and files */
	struct list_head gdirty_list;	/* linked in global dirty list */

	/* linked in global inode list for cache donation */
	struct list_head gdonate_list;
	pgoff_t donate_start, donate_end; /* inclusive */

	struct task_struct *atomic_write_task;	/* store atomic write task */
	struct extent_tree *extent_tree[NR_EXTENT_CACHES];
					/* cached extent_tree entry */
@@ -1274,6 +1279,7 @@ enum inode_type {
	DIR_INODE,			/* for dirty dir inode */
	FILE_INODE,			/* for dirty regular/symlink inode */
	DIRTY_META,			/* for all dirtied inode metadata */
	DONATE_INODE,			/* for all inode to donate pages */
	NR_INODE_TYPE,
};

@@ -1629,6 +1635,9 @@ struct f2fs_sb_info {
	unsigned int warm_data_age_threshold;
	unsigned int last_age_weight;

	/* control donate caches */
	unsigned int donate_files;

	/* basic filesystem units */
	unsigned int log_sectors_per_block;	/* log2 sectors per block */
	unsigned int log_blocksize;		/* log2 block size */
@@ -3968,7 +3977,8 @@ struct f2fs_stat_info {
	unsigned long long allocated_data_blocks;
	int ndirty_node, ndirty_dent, ndirty_meta, ndirty_imeta;
	int ndirty_data, ndirty_qdata;
	unsigned int ndirty_dirs, ndirty_files, nquota_files, ndirty_all;
	unsigned int ndirty_dirs, ndirty_files, ndirty_all;
	unsigned int nquota_files, ndonate_files;
	int nats, dirty_nats, sits, dirty_sits;
	int free_nids, avail_nids, alloc_nids;
	int total_count, utilization;
+55 −5
Original line number Diff line number Diff line
@@ -2450,6 +2450,52 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
	return ret;
}

static void f2fs_keep_noreuse_range(struct inode *inode,
				loff_t offset, loff_t len)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	u64 max_bytes = F2FS_BLK_TO_BYTES(max_file_blocks(inode));
	u64 start, end;

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

	if (offset >= max_bytes || len > max_bytes ||
	    (offset + len) > max_bytes)
		return;

	start = offset >> PAGE_SHIFT;
	end = DIV_ROUND_UP(offset + len, PAGE_SIZE);

	inode_lock(inode);
	if (f2fs_is_atomic_file(inode)) {
		inode_unlock(inode);
		return;
	}

	spin_lock(&sbi->inode_lock[DONATE_INODE]);
	/* let's remove the range, if len = 0 */
	if (!len) {
		if (!list_empty(&F2FS_I(inode)->gdonate_list)) {
			list_del_init(&F2FS_I(inode)->gdonate_list);
			sbi->donate_files--;
		}
	} else {
		if (list_empty(&F2FS_I(inode)->gdonate_list)) {
			list_add_tail(&F2FS_I(inode)->gdonate_list,
					&sbi->inode_list[DONATE_INODE]);
			sbi->donate_files++;
		} else {
			list_move_tail(&F2FS_I(inode)->gdonate_list,
					&sbi->inode_list[DONATE_INODE]);
		}
		F2FS_I(inode)->donate_start = start;
		F2FS_I(inode)->donate_end = end - 1;
	}
	spin_unlock(&sbi->inode_lock[DONATE_INODE]);
	inode_unlock(inode);
}

static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
{
	struct inode *inode = file_inode(filp);
@@ -5168,12 +5214,16 @@ static int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len,
	}

	err = generic_fadvise(filp, offset, len, advice);
	if (!err && advice == POSIX_FADV_DONTNEED &&
		test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) &&
		f2fs_compressed_file(inode))
		f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino);

	if (err)
		return err;

	if (advice == POSIX_FADV_DONTNEED &&
	    (test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) &&
	     f2fs_compressed_file(inode)))
		f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino);
	else if (advice == POSIX_FADV_NOREUSE)
		f2fs_keep_noreuse_range(inode, offset, len);
	return 0;
}

#ifdef CONFIG_COMPAT
+14 −0
Original line number Diff line number Diff line
@@ -808,6 +808,19 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
	return 0;
}

static void f2fs_remove_donate_inode(struct inode *inode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);

	if (list_empty(&F2FS_I(inode)->gdonate_list))
		return;

	spin_lock(&sbi->inode_lock[DONATE_INODE]);
	list_del_init(&F2FS_I(inode)->gdonate_list);
	sbi->donate_files--;
	spin_unlock(&sbi->inode_lock[DONATE_INODE]);
}

/*
 * Called at the last iput() if i_nlink is zero
 */
@@ -842,6 +855,7 @@ void f2fs_evict_inode(struct inode *inode)

	f2fs_bug_on(sbi, get_dirty_pages(inode));
	f2fs_remove_dirty_inode(inode);
	f2fs_remove_donate_inode(inode);

	if (!IS_DEVICE_ALIASING(inode))
		f2fs_destroy_extent_tree(inode);
+1 −0
Original line number Diff line number Diff line
@@ -1441,6 +1441,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
	spin_lock_init(&fi->i_size_lock);
	INIT_LIST_HEAD(&fi->dirty_list);
	INIT_LIST_HEAD(&fi->gdirty_list);
	INIT_LIST_HEAD(&fi->gdonate_list);
	init_f2fs_rwsem(&fi->i_gc_rwsem[READ]);
	init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]);
	init_f2fs_rwsem(&fi->i_xattr_sem);