From: Chao Yu <chao@kernel.org>
To: Barry Song <21cnbao@gmail.com>
Cc: chao@kernel.org, jaegeuk@kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] f2fs: fix to prevent clearing immutable for large folio supported inode
Date: Fri, 9 Jan 2026 16:44:53 +0800 [thread overview]
Message-ID: <8c13ca69-a08a-41c7-bbef-0a79a5f44f93@kernel.org> (raw)
In-Reply-To: <CAGsJ_4weE5T1uBA1-JoJdbZY4E91eN_OL3hMdqixLcoKSrmuzw@mail.gmail.com>
On 1/9/2026 11:57 AM, Barry Song wrote:
> On Fri, Jan 9, 2026 at 4:45 PM Chao Yu <chao@kernel.org> wrote:
>>
>> On 1/9/2026 11:05 AM, Barry Song wrote:
>>> On Fri, Jan 9, 2026 at 3:47 PM Chao Yu <chao@kernel.org> wrote:
>>>>
>>>> Below testcase can change large folio supported inode from immutable
>>>> to mutable, it's not as expected, let's add a new check condition in
>>>> f2fs_setflags_common() to detect and reject it.
>>>>
>>>> - dd if=/dev/zero of=/mnt/f2fs/test bs=32k count=4
>>>> - f2fs_io setflags immutable /mnt/f2fs/test
>>>> - echo 3 > /proc/sys/vm/drop_caches
>>>> : to reload inode with large folio
>>>> - f2fs_io read 32 0 1 mmap 0 0 /mnt/f2fs/test
>>>> - f2fs_io clearflags immutable /mnt/f2fs/test
>>>>
>>>> Signed-off-by: Chao Yu <chao@kernel.org>
>>>> ---
>>>> fs/f2fs/file.c | 6 ++++++
>>>> 1 file changed, 6 insertions(+)
>>>>
>>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
>>>> index ce291f152bc3..f7f9da0b215f 100644
>>>> --- a/fs/f2fs/file.c
>>>> +++ b/fs/f2fs/file.c
>>>> @@ -2155,6 +2155,12 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
>>>> }
>>>> }
>>>>
>>>> + if ((iflags ^ masked_flags) & F2FS_IMMUTABLE_FL) {
>>>> + if ((masked_flags & F2FS_IMMUTABLE_FL) &&
>>>> + mapping_large_folio_support(inode->i_mapping))
>>>> + return -EINVAL;
>>>
>>
>> Barry,
>>
>> I noticed that we are allowed to clear immutable if large folio are supported
>> in target inode, since we can prevent to open w/ write permission in ->open after
>> immutable is cleared, see details in f2fs doc below.
>>
>> So, anyway, I guess my patch should be ignored.
>>
>> Per-file Read-Only Large Folio Support
>> --------------------------------------
>>
>> F2FS implements large folio support on the read path to leverage high-order
>> page allocation for significant performance gains. To minimize code complexity,
>> this support is currently excluded from the write path, which requires handling
>> complex optimizations such as compression and block allocation modes.
>>
>> This optional feature is triggered only when a file's immutable bit is set.
>> Consequently, F2FS will return EOPNOTSUPP if a user attempts to open a cached
>> file with write permissions, even immediately after clearing the bit. Write
>> access is only restored once the cached inode is dropped. The usage flow is
>> demonstrated below:
>>
>> .. code-block::
>>
>> # f2fs_io setflags immutable /data/testfile_read_seq
>>
>> /* flush and reload the inode to enable the large folio */
>> # sync && echo 3 > /proc/sys/vm/drop_caches
>>
>> /* mmap(MAP_POPULATE) + mlock() */
>> # f2fs_io read 128 0 1024 mmap 1 0 /data/testfile_read_seq
>>
>> /* mmap() + fadvise(POSIX_FADV_WILLNEED) + mlock() */
>> # f2fs_io read 128 0 1024 fadvise 1 0 /data/testfile_read_seq
>>
>> /* mmap() + mlock2(MLOCK_ONFAULT) + madvise(MADV_POPULATE_READ) */
>> # f2fs_io read 128 0 1024 madvise 1 0 /data/testfile_read_seq
>>
>> # f2fs_io clearflags immutable /data/testfile_read_seq
>>
>> # f2fs_io write 1 0 1 zero buffered /data/testfile_read_seq
>> Failed to open /mnt/test/test: Operation not supported
>>
>> /* flush and reload the inode to disable the large folio */
>> # sync && echo 3 > /proc/sys/vm/drop_caches
>
> Right, I see. The only concern is that this would require dropping
> the page cache for the entire system, rather than for a single inode.
Yes, maybe, one way to avoid "sync && echo 3" is introducing a new ioctl
interface to hold inode's parent lock, and call d_invalidate(inode_dentry)
to evict the inode which is not opened by anyone.
>
>
>>
>> # f2fs_io write 1 0 1 zero buffered /data/testfile_read_seq
>> Written 4096 bytes with pattern = zero, total_time = 29 us, max_latency = 28 us
>>
>> # rm /data/testfile_read_seq
>>
>>> Hi Yu, I find it a bit odd to prevent unsetting immutable solely
>>> because large folios are in use. If unsetting immutable is considered
>>> unexpected behavior, it should be disallowed regardless of whether
>>> large folios are used, and apply equally in both cases.
>>
>> To confirm, you mean if clearing immutable is considered unexpected behavior,
>> we need to prevent clearing immutable for inode which doesn't enable large folio?
>
> Right. It feels unfair to prevent clearing immutable solely because
> the file happens to have large folios.
>
>>
>>>
>>> I'm not sure whether reverting the large folios setting is the
>>> better approach:
>>> truncate_pagecache(inode, inode->i_size);
>>> mapping_set_folio_order_range(inode->i_mapping, 0, 0);
>>
>> If we want to support reverting the large folios setting dynamically as you
>> proposed above, it need to consider more race case and corner case, so, a
>> little bit complicated.
>
> Right. The idea is to truncate the page cache via
> truncate_pagecache(inode, 0) and set the maximum page-cache order
> to 0. That said, we still need to consider whether any related
> locks are held.
>
> From the comment, it seems that we may need to hold i_rwsem and
> invalidate_lock.
w/ above locks, it seems there is still a race condition as below:
f2fs_fileattr_set read
- f2fs_setflags_common
- truncate_pagecache
- f2fs_read_data_large_folio
: read large folios
- mapping_set_folio_order_range
Thanks,
>
> /**
> * truncate_inode_pages - truncate *all* the pages from an offset
> * @mapping: mapping to truncate
> * @lstart: offset from which to truncate
> *
> * Called under (and serialised by) inode->i_rwsem and
> * mapping->invalidate_lock.
> *
> * ...
> */
> void truncate_inode_pages(struct address_space *mapping, loff_t lstart)
> {
> truncate_inode_pages_range(mapping, lstart, (loff_t)-1);
> }
> EXPORT_SYMBOL(truncate_inode_pages);
>
>
> If clearing immutable is indeed rare, we may leave this as is, since
> writes are not supported until the page cache is fully dropped.
> Eventually, we will support large folios on non-immutable files.
>
> Thanks
> Barry
next prev parent reply other threads:[~2026-01-09 8:44 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-09 2:47 Chao Yu
2026-01-09 3:05 ` Barry Song
2026-01-09 3:45 ` Chao Yu
2026-01-09 3:57 ` Barry Song
2026-01-09 8:44 ` Chao Yu [this message]
2026-01-22 2:02 ` [f2fs-dev] " Nanzhe Zhao
2026-01-22 23:10 ` Jaegeuk Kim
2026-01-23 6:30 ` Nanzhe Zhao
2026-02-24 3:55 ` Jaegeuk Kim
2026-01-23 4:04 ` Chao Yu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8c13ca69-a08a-41c7-bbef-0a79a5f44f93@kernel.org \
--to=chao@kernel.org \
--cc=21cnbao@gmail.com \
--cc=jaegeuk@kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®