* [PATCH v2 0/2] f2fs: Fix DIO flags and add ioprio hint
@ 2025-06-15 14:42 Daniel Lee
2025-06-15 14:42 ` [PATCH v2 1/2] f2fs: Apply bio flags to direct I/O Daniel Lee
2025-06-15 14:42 ` [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files Daniel Lee
0 siblings, 2 replies; 8+ messages in thread
From: Daniel Lee @ 2025-06-15 14:42 UTC (permalink / raw)
To: Jaegeuk Kim, Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, Daniel Lee
The first patch corrects an issue where Direct I/O (DIO) writes ignore
bio flag hints (e.g., F2FS_IOPRIO_WRITE for REQ_PRIO),
making them inconsistent with buffered I/O.
The second patch is to set an I/O priority hint for hot files on creation
and pinned files by default.
---
Changes in v2:
- f2fs: Apply bio flags to direct I/O
- Changed f2fs_io_flags() to accept a direct inode pointer
- f2fs: use ioprio hint for hot and pinned files
- Removed an unnecessary f2fs_mark_inode_dirty_sync() call
Daniel Lee (2):
f2fs: Apply bio flags to direct I/O
f2fs: use ioprio hint for hot and pinned files
fs/f2fs/data.c | 10 +++++-----
fs/f2fs/f2fs.h | 20 ++++++++++++++++++++
fs/f2fs/file.c | 14 ++++++++++++++
fs/f2fs/namei.c | 11 +++++++----
4 files changed, 46 insertions(+), 9 deletions(-)
--
2.50.0.rc1.591.g9c95f17f64-goog
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] f2fs: Apply bio flags to direct I/O
2025-06-15 14:42 [PATCH v2 0/2] f2fs: Fix DIO flags and add ioprio hint Daniel Lee
@ 2025-06-15 14:42 ` Daniel Lee
2025-06-16 12:41 ` Chao Yu
2025-06-15 14:42 ` [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files Daniel Lee
1 sibling, 1 reply; 8+ messages in thread
From: Daniel Lee @ 2025-06-15 14:42 UTC (permalink / raw)
To: Jaegeuk Kim, Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, Daniel Lee
Bio flags like REQ_PRIO, REQ_META, and REQ_FUA, determined by
f2fs_io_flags(), were not being applied to direct I/O (DIO) writes.
This meant that DIO writes would not respect filesystem-level hints
(for REQ_META/FUA) or inode-level hints (like F2FS_IOPRIO_WRITE).
This patch refactors f2fs_io_flags() to use a direct inode pointer
instead of deriving it from a page. The function is then called from
the DIO write path, ensuring that bio flags are handled consistently
for both buffered and DIO writes.
Signed-off-by: Daniel Lee <chullee@google.com>
---
fs/f2fs/data.c | 10 +++++-----
fs/f2fs/f2fs.h | 1 +
fs/f2fs/file.c | 11 +++++++++++
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 31e892842625..71dde494b892 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -416,10 +416,9 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
return 0;
}
-static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio)
+blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio, struct inode *inode)
{
unsigned int temp_mask = GENMASK(NR_TEMP_TYPE - 1, 0);
- struct folio *fio_folio = page_folio(fio->page);
unsigned int fua_flag, meta_flag, io_flag;
blk_opf_t op_flags = 0;
@@ -446,8 +445,8 @@ static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio)
if (BIT(fio->temp) & fua_flag)
op_flags |= REQ_FUA;
- if (fio->type == DATA &&
- F2FS_I(fio_folio->mapping->host)->ioprio_hint == F2FS_IOPRIO_WRITE)
+ if (inode && fio->type == DATA &&
+ F2FS_I(inode)->ioprio_hint == F2FS_IOPRIO_WRITE)
op_flags |= REQ_PRIO;
return op_flags;
@@ -459,10 +458,11 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
struct block_device *bdev;
sector_t sector;
struct bio *bio;
+ struct inode *inode = fio->page ? fio->page->mapping->host : NULL;
bdev = f2fs_target_device(sbi, fio->new_blkaddr, §or);
bio = bio_alloc_bioset(bdev, npages,
- fio->op | fio->op_flags | f2fs_io_flags(fio),
+ fio->op | fio->op_flags | f2fs_io_flags(fio, inode),
GFP_NOIO, &f2fs_bioset);
bio->bi_iter.bi_sector = sector;
if (is_read_io(fio->op)) {
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9333a22b9a01..3e02687c1b58 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3972,6 +3972,7 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio);
struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
block_t blk_addr, sector_t *sector);
int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr);
+blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio, struct inode *inode);
void f2fs_set_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 696131e655ed..3eb40d7bf602 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -5015,6 +5015,17 @@ static void f2fs_dio_write_submit_io(const struct iomap_iter *iter,
enum log_type type = f2fs_rw_hint_to_seg_type(sbi, inode->i_write_hint);
enum temp_type temp = f2fs_get_segment_temp(sbi, type);
+ /* if fadvise set to hot, override the temperature */
+ struct f2fs_io_info fio = {
+ .sbi = sbi,
+ .type = DATA,
+ .op = REQ_OP_WRITE,
+ .temp = file_is_hot(inode) ? HOT : temp,
+ .op_flags = bio->bi_opf,
+ .page = NULL,
+ };
+ bio->bi_opf |= f2fs_io_flags(&fio, inode);
+
bio->bi_write_hint = f2fs_io_type_to_rw_hint(sbi, DATA, temp);
submit_bio(bio);
}
--
2.50.0.rc1.591.g9c95f17f64-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files
2025-06-15 14:42 [PATCH v2 0/2] f2fs: Fix DIO flags and add ioprio hint Daniel Lee
2025-06-15 14:42 ` [PATCH v2 1/2] f2fs: Apply bio flags to direct I/O Daniel Lee
@ 2025-06-15 14:42 ` Daniel Lee
2025-06-16 12:50 ` Chao Yu
1 sibling, 1 reply; 8+ messages in thread
From: Daniel Lee @ 2025-06-15 14:42 UTC (permalink / raw)
To: Jaegeuk Kim, Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, Daniel Lee
Apply the `ioprio_hint` to set `F2FS_IOPRIO_WRITE` priority
on files identified as "hot" at creation and on files that are
pinned via ioctl.
Signed-off-by: Daniel Lee <chullee@google.com>
---
fs/f2fs/f2fs.h | 19 +++++++++++++++++++
fs/f2fs/file.c | 3 +++
fs/f2fs/namei.c | 11 +++++++----
3 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 3e02687c1b58..0c4f52892ff7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3440,6 +3440,25 @@ static inline void set_file(struct inode *inode, int type)
f2fs_mark_inode_dirty_sync(inode, true);
}
+static inline int get_ioprio(struct inode *inode)
+{
+ return F2FS_I(inode)->ioprio_hint;
+}
+
+static inline void set_ioprio(struct inode *inode, int level)
+{
+ if (get_ioprio(inode) == level)
+ return;
+ F2FS_I(inode)->ioprio_hint = level;
+}
+
+static inline void clear_ioprio(struct inode *inode)
+{
+ if (get_ioprio(inode) == 0)
+ return;
+ F2FS_I(inode)->ioprio_hint = 0;
+}
+
static inline void clear_file(struct inode *inode, int type)
{
if (!is_file(inode, type))
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 3eb40d7bf602..a18fb7f3d019 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3496,6 +3496,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
if (!pin) {
clear_inode_flag(inode, FI_PIN_FILE);
+ clear_ioprio(inode);
f2fs_i_gc_failures_write(inode, 0);
goto done;
} else if (f2fs_is_pinned_file(inode)) {
@@ -3529,6 +3530,8 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
}
set_inode_flag(inode, FI_PIN_FILE);
+ file_set_hot(inode);
+ set_ioprio(inode, F2FS_IOPRIO_WRITE);
ret = F2FS_I(inode)->i_gc_failures;
done:
f2fs_update_time(sbi, REQ_TIME);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 07e333ee21b7..0f96a0b86c40 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -191,9 +191,10 @@ static void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
}
/*
- * Set file's temperature for hot/cold data separation
+ * Set file's temperature (for hot/cold data separation) and
+ * I/O priority, based on filename extension
*/
-static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
+static void set_file_temp_prio(struct f2fs_sb_info *sbi, struct inode *inode,
const unsigned char *name)
{
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
@@ -212,8 +213,10 @@ static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
if (i < cold_count)
file_set_cold(inode);
- else
+ else {
file_set_hot(inode);
+ set_ioprio(inode, F2FS_IOPRIO_WRITE);
+ }
}
static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
@@ -317,7 +320,7 @@ static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
set_inode_flag(inode, FI_INLINE_DATA);
if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
- set_file_temperature(sbi, inode, name);
+ set_file_temp_prio(sbi, inode, name);
stat_inc_inline_xattr(inode);
stat_inc_inline_inode(inode);
--
2.50.0.rc1.591.g9c95f17f64-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] f2fs: Apply bio flags to direct I/O
2025-06-15 14:42 ` [PATCH v2 1/2] f2fs: Apply bio flags to direct I/O Daniel Lee
@ 2025-06-16 12:41 ` Chao Yu
2025-06-30 23:02 ` Daniel Lee
0 siblings, 1 reply; 8+ messages in thread
From: Chao Yu @ 2025-06-16 12:41 UTC (permalink / raw)
To: Daniel Lee, Jaegeuk Kim; +Cc: chao, linux-f2fs-devel, linux-kernel
On 6/15/25 22:42, Daniel Lee wrote:
> Bio flags like REQ_PRIO, REQ_META, and REQ_FUA, determined by
> f2fs_io_flags(), were not being applied to direct I/O (DIO) writes.
> This meant that DIO writes would not respect filesystem-level hints
> (for REQ_META/FUA) or inode-level hints (like F2FS_IOPRIO_WRITE).
>
> This patch refactors f2fs_io_flags() to use a direct inode pointer
> instead of deriving it from a page. The function is then called from
> the DIO write path, ensuring that bio flags are handled consistently
> for both buffered and DIO writes.
>
> Signed-off-by: Daniel Lee <chullee@google.com>
> ---
> fs/f2fs/data.c | 10 +++++-----
> fs/f2fs/f2fs.h | 1 +
> fs/f2fs/file.c | 11 +++++++++++
> 3 files changed, 17 insertions(+), 5 deletions(-)
>
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index 31e892842625..71dde494b892 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -416,10 +416,9 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
> return 0;
> }
>
> -static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio)
> +blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio, struct inode *inode)
> {
> unsigned int temp_mask = GENMASK(NR_TEMP_TYPE - 1, 0);
> - struct folio *fio_folio = page_folio(fio->page);
> unsigned int fua_flag, meta_flag, io_flag;
> blk_opf_t op_flags = 0;
>
> @@ -446,8 +445,8 @@ static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio)
> if (BIT(fio->temp) & fua_flag)
> op_flags |= REQ_FUA;
>
> - if (fio->type == DATA &&
> - F2FS_I(fio_folio->mapping->host)->ioprio_hint == F2FS_IOPRIO_WRITE)
> + if (inode && fio->type == DATA &&
> + F2FS_I(inode)->ioprio_hint == F2FS_IOPRIO_WRITE)
> op_flags |= REQ_PRIO;
>
> return op_flags;
> @@ -459,10 +458,11 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
> struct block_device *bdev;
> sector_t sector;
> struct bio *bio;
> + struct inode *inode = fio->page ? fio->page->mapping->host : NULL;
fio->page will always be true now? We can pass fio->page->mapping->host to f2fs_io_flags()
directly?
Thanks,
>
> bdev = f2fs_target_device(sbi, fio->new_blkaddr, §or);
> bio = bio_alloc_bioset(bdev, npages,
> - fio->op | fio->op_flags | f2fs_io_flags(fio),
> + fio->op | fio->op_flags | f2fs_io_flags(fio, inode),
> GFP_NOIO, &f2fs_bioset);
> bio->bi_iter.bi_sector = sector;
> if (is_read_io(fio->op)) {
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 9333a22b9a01..3e02687c1b58 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -3972,6 +3972,7 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio);
> struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
> block_t blk_addr, sector_t *sector);
> int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr);
> +blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio, struct inode *inode);
> void f2fs_set_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
> void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
> int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 696131e655ed..3eb40d7bf602 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -5015,6 +5015,17 @@ static void f2fs_dio_write_submit_io(const struct iomap_iter *iter,
> enum log_type type = f2fs_rw_hint_to_seg_type(sbi, inode->i_write_hint);
> enum temp_type temp = f2fs_get_segment_temp(sbi, type);
>
> + /* if fadvise set to hot, override the temperature */
> + struct f2fs_io_info fio = {
> + .sbi = sbi,
> + .type = DATA,
> + .op = REQ_OP_WRITE,
> + .temp = file_is_hot(inode) ? HOT : temp,
> + .op_flags = bio->bi_opf,
> + .page = NULL,
> + };
> + bio->bi_opf |= f2fs_io_flags(&fio, inode);
> +
> bio->bi_write_hint = f2fs_io_type_to_rw_hint(sbi, DATA, temp);
> submit_bio(bio);
> }
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files
2025-06-15 14:42 ` [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files Daniel Lee
@ 2025-06-16 12:50 ` Chao Yu
2025-06-30 22:56 ` Daniel Lee
0 siblings, 1 reply; 8+ messages in thread
From: Chao Yu @ 2025-06-16 12:50 UTC (permalink / raw)
To: Daniel Lee, Jaegeuk Kim; +Cc: chao, linux-f2fs-devel, linux-kernel
On 6/15/25 22:42, Daniel Lee wrote:
> Apply the `ioprio_hint` to set `F2FS_IOPRIO_WRITE` priority
> on files identified as "hot" at creation and on files that are
> pinned via ioctl.
>
> Signed-off-by: Daniel Lee <chullee@google.com>
> ---
> fs/f2fs/f2fs.h | 19 +++++++++++++++++++
> fs/f2fs/file.c | 3 +++
> fs/f2fs/namei.c | 11 +++++++----
> 3 files changed, 29 insertions(+), 4 deletions(-)
>
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 3e02687c1b58..0c4f52892ff7 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -3440,6 +3440,25 @@ static inline void set_file(struct inode *inode, int type)
> f2fs_mark_inode_dirty_sync(inode, true);
> }
>
> +static inline int get_ioprio(struct inode *inode)
> +{
> + return F2FS_I(inode)->ioprio_hint;
> +}
> +
> +static inline void set_ioprio(struct inode *inode, int level)
> +{
> + if (get_ioprio(inode) == level)
> + return;
> + F2FS_I(inode)->ioprio_hint = level;
> +}
> +
> +static inline void clear_ioprio(struct inode *inode)
> +{
> + if (get_ioprio(inode) == 0)
> + return;
> + F2FS_I(inode)->ioprio_hint = 0;
> +}
> +
> static inline void clear_file(struct inode *inode, int type)
> {
> if (!is_file(inode, type))
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 3eb40d7bf602..a18fb7f3d019 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -3496,6 +3496,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
>
> if (!pin) {
> clear_inode_flag(inode, FI_PIN_FILE);
> + clear_ioprio(inode);
I guess there are more places clearing FI_PIN_FILE? we need to cover
them all?
> f2fs_i_gc_failures_write(inode, 0);
> goto done;
> } else if (f2fs_is_pinned_file(inode)) {
> @@ -3529,6 +3530,8 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
> }
>
> set_inode_flag(inode, FI_PIN_FILE);
> + file_set_hot(inode);
Unnecessary file_set_hot() invoking? Or am I missing anything?
Thanks,
> + set_ioprio(inode, F2FS_IOPRIO_WRITE);
> ret = F2FS_I(inode)->i_gc_failures;
> done:
> f2fs_update_time(sbi, REQ_TIME);
> diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
> index 07e333ee21b7..0f96a0b86c40 100644
> --- a/fs/f2fs/namei.c
> +++ b/fs/f2fs/namei.c
> @@ -191,9 +191,10 @@ static void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
> }
>
> /*
> - * Set file's temperature for hot/cold data separation
> + * Set file's temperature (for hot/cold data separation) and
> + * I/O priority, based on filename extension
> */
> -static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
> +static void set_file_temp_prio(struct f2fs_sb_info *sbi, struct inode *inode,
> const unsigned char *name)
> {
> __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
> @@ -212,8 +213,10 @@ static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
>
> if (i < cold_count)
> file_set_cold(inode);
> - else
> + else {
> file_set_hot(inode);
> + set_ioprio(inode, F2FS_IOPRIO_WRITE);
> + }
> }
>
> static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
> @@ -317,7 +320,7 @@ static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
> set_inode_flag(inode, FI_INLINE_DATA);
>
> if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
> - set_file_temperature(sbi, inode, name);
> + set_file_temp_prio(sbi, inode, name);
>
> stat_inc_inline_xattr(inode);
> stat_inc_inline_inode(inode);
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files
2025-06-16 12:50 ` Chao Yu
@ 2025-06-30 22:56 ` Daniel Lee
2025-07-01 3:39 ` Chao Yu
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Lee @ 2025-06-30 22:56 UTC (permalink / raw)
To: Chao Yu; +Cc: Jaegeuk Kim, linux-f2fs-devel, linux-kernel
On Mon, Jun 16, 2025 at 5:50 AM Chao Yu <chao@kernel.org> wrote:
>
> On 6/15/25 22:42, Daniel Lee wrote:
> > Apply the `ioprio_hint` to set `F2FS_IOPRIO_WRITE` priority
> > on files identified as "hot" at creation and on files that are
> > pinned via ioctl.
> >
> > Signed-off-by: Daniel Lee <chullee@google.com>
> > ---
> > fs/f2fs/f2fs.h | 19 +++++++++++++++++++
> > fs/f2fs/file.c | 3 +++
> > fs/f2fs/namei.c | 11 +++++++----
> > 3 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index 3e02687c1b58..0c4f52892ff7 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -3440,6 +3440,25 @@ static inline void set_file(struct inode *inode, int type)
> > f2fs_mark_inode_dirty_sync(inode, true);
> > }
> >
> > +static inline int get_ioprio(struct inode *inode)
> > +{
> > + return F2FS_I(inode)->ioprio_hint;
> > +}
> > +
> > +static inline void set_ioprio(struct inode *inode, int level)
> > +{
> > + if (get_ioprio(inode) == level)
> > + return;
> > + F2FS_I(inode)->ioprio_hint = level;
> > +}
> > +
> > +static inline void clear_ioprio(struct inode *inode)
> > +{
> > + if (get_ioprio(inode) == 0)
> > + return;
> > + F2FS_I(inode)->ioprio_hint = 0;
> > +}
> > +
> > static inline void clear_file(struct inode *inode, int type)
> > {
> > if (!is_file(inode, type))
> > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > index 3eb40d7bf602..a18fb7f3d019 100644
> > --- a/fs/f2fs/file.c
> > +++ b/fs/f2fs/file.c
> > @@ -3496,6 +3496,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
> >
> > if (!pin) {
> > clear_inode_flag(inode, FI_PIN_FILE);
> > + clear_ioprio(inode);
>
> I guess there are more places clearing FI_PIN_FILE? we need to cover
> them all?
Yes, you're right. FI_PIN_FILE is toggled in several places. However,
this change is intended to set the HOT and IOPRIO on the files that
users explicitly pin through IOCTL. The other kernel internal
mechanisms (e.g., swap or gc_failures) remain the same. Are there any
potential issues that I should consider?
>
> > f2fs_i_gc_failures_write(inode, 0);
> > goto done;
> > } else if (f2fs_is_pinned_file(inode)) {
> > @@ -3529,6 +3530,8 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
> > }
> >
> > set_inode_flag(inode, FI_PIN_FILE);
> > + file_set_hot(inode);
>
> Unnecessary file_set_hot() invoking? Or am I missing anything?
>
> Thanks,
Setting HOT and IOPRIO by default is also intentional. We set both
flags by default because the main use case for pinned files involves
frequently updated or short-lived data that needs fast write speeds.
>
> > + set_ioprio(inode, F2FS_IOPRIO_WRITE);
> > ret = F2FS_I(inode)->i_gc_failures;
> > done:
> > f2fs_update_time(sbi, REQ_TIME);
> > diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
> > index 07e333ee21b7..0f96a0b86c40 100644
> > --- a/fs/f2fs/namei.c
> > +++ b/fs/f2fs/namei.c
> > @@ -191,9 +191,10 @@ static void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
> > }
> >
> > /*
> > - * Set file's temperature for hot/cold data separation
> > + * Set file's temperature (for hot/cold data separation) and
> > + * I/O priority, based on filename extension
> > */
> > -static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
> > +static void set_file_temp_prio(struct f2fs_sb_info *sbi, struct inode *inode,
> > const unsigned char *name)
> > {
> > __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
> > @@ -212,8 +213,10 @@ static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
> >
> > if (i < cold_count)
> > file_set_cold(inode);
> > - else
> > + else {
> > file_set_hot(inode);
> > + set_ioprio(inode, F2FS_IOPRIO_WRITE);
> > + }
> > }
> >
> > static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
> > @@ -317,7 +320,7 @@ static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
> > set_inode_flag(inode, FI_INLINE_DATA);
> >
> > if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
> > - set_file_temperature(sbi, inode, name);
> > + set_file_temp_prio(sbi, inode, name);
> >
> > stat_inc_inline_xattr(inode);
> > stat_inc_inline_inode(inode);
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] f2fs: Apply bio flags to direct I/O
2025-06-16 12:41 ` Chao Yu
@ 2025-06-30 23:02 ` Daniel Lee
0 siblings, 0 replies; 8+ messages in thread
From: Daniel Lee @ 2025-06-30 23:02 UTC (permalink / raw)
To: Chao Yu; +Cc: Jaegeuk Kim, linux-f2fs-devel, linux-kernel
On Mon, Jun 16, 2025 at 5:41 AM Chao Yu <chao@kernel.org> wrote:
>
> On 6/15/25 22:42, Daniel Lee wrote:
> > Bio flags like REQ_PRIO, REQ_META, and REQ_FUA, determined by
> > f2fs_io_flags(), were not being applied to direct I/O (DIO) writes.
> > This meant that DIO writes would not respect filesystem-level hints
> > (for REQ_META/FUA) or inode-level hints (like F2FS_IOPRIO_WRITE).
> >
> > This patch refactors f2fs_io_flags() to use a direct inode pointer
> > instead of deriving it from a page. The function is then called from
> > the DIO write path, ensuring that bio flags are handled consistently
> > for both buffered and DIO writes.
> >
> > Signed-off-by: Daniel Lee <chullee@google.com>
> > ---
> > fs/f2fs/data.c | 10 +++++-----
> > fs/f2fs/f2fs.h | 1 +
> > fs/f2fs/file.c | 11 +++++++++++
> > 3 files changed, 17 insertions(+), 5 deletions(-)
> >
> > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> > index 31e892842625..71dde494b892 100644
> > --- a/fs/f2fs/data.c
> > +++ b/fs/f2fs/data.c
> > @@ -416,10 +416,9 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
> > return 0;
> > }
> >
> > -static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio)
> > +blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio, struct inode *inode)
> > {
> > unsigned int temp_mask = GENMASK(NR_TEMP_TYPE - 1, 0);
> > - struct folio *fio_folio = page_folio(fio->page);
> > unsigned int fua_flag, meta_flag, io_flag;
> > blk_opf_t op_flags = 0;
> >
> > @@ -446,8 +445,8 @@ static blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio)
> > if (BIT(fio->temp) & fua_flag)
> > op_flags |= REQ_FUA;
> >
> > - if (fio->type == DATA &&
> > - F2FS_I(fio_folio->mapping->host)->ioprio_hint == F2FS_IOPRIO_WRITE)
> > + if (inode && fio->type == DATA &&
> > + F2FS_I(inode)->ioprio_hint == F2FS_IOPRIO_WRITE)
> > op_flags |= REQ_PRIO;
> >
> > return op_flags;
> > @@ -459,10 +458,11 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
> > struct block_device *bdev;
> > sector_t sector;
> > struct bio *bio;
> > + struct inode *inode = fio->page ? fio->page->mapping->host : NULL;
>
> fio->page will always be true now? We can pass fio->page->mapping->host to f2fs_io_flags()
> directly?
>
> Thanks,
Thanks for the insight. Since fio->page is always non-null here, I'll
remove the unnecessary code.
>
> >
> > bdev = f2fs_target_device(sbi, fio->new_blkaddr, §or);
> > bio = bio_alloc_bioset(bdev, npages,
> > - fio->op | fio->op_flags | f2fs_io_flags(fio),
> > + fio->op | fio->op_flags | f2fs_io_flags(fio, inode),
> > GFP_NOIO, &f2fs_bioset);
> > bio->bi_iter.bi_sector = sector;
> > if (is_read_io(fio->op)) {
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index 9333a22b9a01..3e02687c1b58 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -3972,6 +3972,7 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio);
> > struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
> > block_t blk_addr, sector_t *sector);
> > int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr);
> > +blk_opf_t f2fs_io_flags(struct f2fs_io_info *fio, struct inode *inode);
> > void f2fs_set_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
> > void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
> > int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
> > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > index 696131e655ed..3eb40d7bf602 100644
> > --- a/fs/f2fs/file.c
> > +++ b/fs/f2fs/file.c
> > @@ -5015,6 +5015,17 @@ static void f2fs_dio_write_submit_io(const struct iomap_iter *iter,
> > enum log_type type = f2fs_rw_hint_to_seg_type(sbi, inode->i_write_hint);
> > enum temp_type temp = f2fs_get_segment_temp(sbi, type);
> >
> > + /* if fadvise set to hot, override the temperature */
> > + struct f2fs_io_info fio = {
> > + .sbi = sbi,
> > + .type = DATA,
> > + .op = REQ_OP_WRITE,
> > + .temp = file_is_hot(inode) ? HOT : temp,
> > + .op_flags = bio->bi_opf,
> > + .page = NULL,
> > + };
> > + bio->bi_opf |= f2fs_io_flags(&fio, inode);
> > +
> > bio->bi_write_hint = f2fs_io_type_to_rw_hint(sbi, DATA, temp);
> > submit_bio(bio);
> > }
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files
2025-06-30 22:56 ` Daniel Lee
@ 2025-07-01 3:39 ` Chao Yu
0 siblings, 0 replies; 8+ messages in thread
From: Chao Yu @ 2025-07-01 3:39 UTC (permalink / raw)
To: Daniel Lee; +Cc: chao, Jaegeuk Kim, linux-f2fs-devel, linux-kernel
On 7/1/25 06:56, Daniel Lee wrote:
> On Mon, Jun 16, 2025 at 5:50 AM Chao Yu <chao@kernel.org> wrote:
>>
>> On 6/15/25 22:42, Daniel Lee wrote:
>>> Apply the `ioprio_hint` to set `F2FS_IOPRIO_WRITE` priority
>>> on files identified as "hot" at creation and on files that are
>>> pinned via ioctl.
>>>
>>> Signed-off-by: Daniel Lee <chullee@google.com>
>>> ---
>>> fs/f2fs/f2fs.h | 19 +++++++++++++++++++
>>> fs/f2fs/file.c | 3 +++
>>> fs/f2fs/namei.c | 11 +++++++----
>>> 3 files changed, 29 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>>> index 3e02687c1b58..0c4f52892ff7 100644
>>> --- a/fs/f2fs/f2fs.h
>>> +++ b/fs/f2fs/f2fs.h
>>> @@ -3440,6 +3440,25 @@ static inline void set_file(struct inode *inode, int type)
>>> f2fs_mark_inode_dirty_sync(inode, true);
>>> }
>>>
>>> +static inline int get_ioprio(struct inode *inode)
>>> +{
>>> + return F2FS_I(inode)->ioprio_hint;
>>> +}
>>> +
>>> +static inline void set_ioprio(struct inode *inode, int level)
>>> +{
>>> + if (get_ioprio(inode) == level)
>>> + return;
>>> + F2FS_I(inode)->ioprio_hint = level;
>>> +}
>>> +
>>> +static inline void clear_ioprio(struct inode *inode)
>>> +{
>>> + if (get_ioprio(inode) == 0)
>>> + return;
>>> + F2FS_I(inode)->ioprio_hint = 0;
>>> +}
>>> +
>>> static inline void clear_file(struct inode *inode, int type)
>>> {
>>> if (!is_file(inode, type))
>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
>>> index 3eb40d7bf602..a18fb7f3d019 100644
>>> --- a/fs/f2fs/file.c
>>> +++ b/fs/f2fs/file.c
>>> @@ -3496,6 +3496,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
>>>
>>> if (!pin) {
>>> clear_inode_flag(inode, FI_PIN_FILE);
>>> + clear_ioprio(inode);
>>
>> I guess there are more places clearing FI_PIN_FILE? we need to cover
>> them all?
>
> Yes, you're right. FI_PIN_FILE is toggled in several places. However,
> this change is intended to set the HOT and IOPRIO on the files that
> users explicitly pin through IOCTL. The other kernel internal
> mechanisms (e.g., swap or gc_failures) remain the same. Are there any
> potential issues that I should consider?
Daniel,
Not sure, just notice that it seems FI_PIN_FILE and IOPRIO are not
set/unset together always.
>
> >
>>> f2fs_i_gc_failures_write(inode, 0);
>>> goto done;
>>> } else if (f2fs_is_pinned_file(inode)) {
>>> @@ -3529,6 +3530,8 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
>>> }
>>>
>>> set_inode_flag(inode, FI_PIN_FILE);
>>> + file_set_hot(inode);
>>
>> Unnecessary file_set_hot() invoking? Or am I missing anything?
>>
>> Thanks,
>
> Setting HOT and IOPRIO by default is also intentional. We set both
> flags by default because the main use case for pinned files involves
> frequently updated or short-lived data that needs fast write speeds.
Well, if it is intentional, let's describe it in commit message explicitly.
Two more questions:
- when we unpin a file, we need to clear hot flag as well?
- when we set pin on cold file, do we need to clear the cold flag and then
set hot flag?
BTW, there is no document about this pin ioctl, its sematics becomes more
complicated now, not sure whether user can use this ioctl as their needs or
not, how about adding some comments above this ioctl function, later, we
can relocate the comments to f2fs.rst as document.
Thanks,
>
>>
>>> + set_ioprio(inode, F2FS_IOPRIO_WRITE);
>>> ret = F2FS_I(inode)->i_gc_failures;
>>> done:
>>> f2fs_update_time(sbi, REQ_TIME);
>>> diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
>>> index 07e333ee21b7..0f96a0b86c40 100644
>>> --- a/fs/f2fs/namei.c
>>> +++ b/fs/f2fs/namei.c
>>> @@ -191,9 +191,10 @@ static void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
>>> }
>>>
>>> /*
>>> - * Set file's temperature for hot/cold data separation
>>> + * Set file's temperature (for hot/cold data separation) and
>>> + * I/O priority, based on filename extension
>>> */
>>> -static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
>>> +static void set_file_temp_prio(struct f2fs_sb_info *sbi, struct inode *inode,
>>> const unsigned char *name)
>>> {
>>> __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
>>> @@ -212,8 +213,10 @@ static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
>>>
>>> if (i < cold_count)
>>> file_set_cold(inode);
>>> - else
>>> + else {
>>> file_set_hot(inode);
>>> + set_ioprio(inode, F2FS_IOPRIO_WRITE);
>>> + }
>>> }
>>>
>>> static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
>>> @@ -317,7 +320,7 @@ static struct inode *f2fs_new_inode(struct mnt_idmap *idmap,
>>> set_inode_flag(inode, FI_INLINE_DATA);
>>>
>>> if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
>>> - set_file_temperature(sbi, inode, name);
>>> + set_file_temp_prio(sbi, inode, name);
>>>
>>> stat_inc_inline_xattr(inode);
>>> stat_inc_inline_inode(inode);
>>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-07-01 3:39 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-15 14:42 [PATCH v2 0/2] f2fs: Fix DIO flags and add ioprio hint Daniel Lee
2025-06-15 14:42 ` [PATCH v2 1/2] f2fs: Apply bio flags to direct I/O Daniel Lee
2025-06-16 12:41 ` Chao Yu
2025-06-30 23:02 ` Daniel Lee
2025-06-15 14:42 ` [PATCH v2 2/2] f2fs: use ioprio hint for hot and pinned files Daniel Lee
2025-06-16 12:50 ` Chao Yu
2025-06-30 22:56 ` Daniel Lee
2025-07-01 3:39 ` Chao Yu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).