mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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


  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®