f2fs: keep POSIX_FADV_NOREUSE ranges

[ Upstream commit ef0c333cad8d1940f132a7ce15f15920216a3bd5 ]

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

Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Stable-dep-of: 10b591e7fb7c ("f2fs: fix to avoid updating compression context during writeback")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jaegeuk Kim
2025-12-30 12:05:38 -05:00
committed by Greg Kroah-Hartman
parent 64ed96a21f
commit 1a00afcdae
5 changed files with 84 additions and 6 deletions

View File

@@ -100,6 +100,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);
@@ -436,6 +437,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",

View File

@@ -837,6 +837,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 */
@@ -1261,6 +1266,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,
};
@@ -1613,6 +1619,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 */
@@ -3948,7 +3957,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;

View File

@@ -2435,6 +2435,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);
@@ -5078,12 +5124,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;
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

View File

@@ -811,6 +811,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
*/
@@ -844,6 +857,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);
f2fs_destroy_extent_tree(inode);

View File

@@ -1413,6 +1413,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);