From: sashiko-bot@kernel.org
To: "Jan Kara" <jack@suse.cz>, "Christian Brauner" <brauner@kernel.org>
Cc: "Andreas Gruenbacher" <agruenba@redhat.com>,
"Mike Marshall" <hubcap@omnibond.com>,
"Martin Brandenburg" <martin@omnibond.com>,
devel@lists.orangefs.org, "Dave Kleikamp" <shaggy@kernel.org>,
"Carlos Maiolino" <cem@kernel.org>,
"David Howells" <dhowells@redhat.com>,
"Marc Dionne" <marc.dionne@auristor.com>,
"Miklos Szeredi" <miklos@szeredi.hu>,
"Chuck Lever" <cel@kernel.org>,
"Jeff Layton" <jlayton@kernel.org>,
"Eric Biggers" <ebiggers@kernel.org>,
"Jaegeuk Kim" <jaegeuk@kernel.org>,
linux-fscrypt@vger.kernel.org, "Anna Schumaker" <anna@kernel.org>
Subject: Re: [PATCH 03/13] orangefs: Check PAGECACHE_TAG_DIRTY instead of I_DIRTY_PAGES inode state
Date: Fri, 13 Nov 2026 09:00:01 +0000 [thread overview]
Message-ID: <sashiko-outbox-212490@kernel.org> (raw)
In-Reply-To: <20261113084700.739002-16-jack@suse.cz>
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] orangefs: stale i_size overwrite during writeback in
orangefs_inode_getattr()
--
commit 627feba60e819dc443191dbfcd63f583f8da0f24
Author: Jan Kara <jack@suse.cz>
orangefs: Check PAGECACHE_TAG_DIRTY instead of I_DIRTY_PAGES inode state
This commit replaces checks of the I_DIRTY_PAGES inode state flag in
orangefs_inode_getattr() with mapping_tagged(..., PAGECACHE_TAG_DIRTY).
> diff --git a/fs/orangefs/orangefs-utils.c b/fs/orangefs/orangefs-utils.c
> index 9ab1119ebd28a..4c4036f470cdd 100644
> --- a/fs/orangefs/orangefs-utils.c
> +++ b/fs/orangefs/orangefs-utils.c
> @@ -247,7 +247,8 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
> spin_lock(&inode->i_lock);
> /* Must have all the attributes in the mask and be within cache time. */
> if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
> - orangefs_inode->attr_valid || inode_state_read(inode) & I_DIRTY_PAGES) {
> + orangefs_inode->attr_valid ||
> + mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
> if (orangefs_inode->attr_valid) {
> spin_unlock(&inode->i_lock);
> write_inode_now(inode, 1);
> @@ -281,13 +282,14 @@ int orangefs_inode_getattr(struct inode *inode, int flags)
> spin_lock(&inode->i_lock);
> /* Must have all the attributes in the mask and be within cache time. */
> if ((!flags && time_before(jiffies, orangefs_inode->getattr_time)) ||
> - orangefs_inode->attr_valid || inode_state_read(inode) & I_DIRTY_PAGES) {
> + orangefs_inode->attr_valid ||
> + mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
> if (orangefs_inode->attr_valid) {
> spin_unlock(&inode->i_lock);
> write_inode_now(inode, 1);
> goto again2;
> }
> - if (inode_state_read(inode) & I_DIRTY_PAGES) {
> + if (mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
> ret = 0;
> goto out_unlock;
> }
[Severity: High]
Can orangefs_inode_getattr() overwrite inode->i_size with a stale size from
the server while pagecache writeback is in flight?
When a buffered write extends a file in orangefs_write_end(), inode->i_size
is updated in memory and the folio is marked dirty, while the server only
learns the new size once the writeback RPC in wait_for_direct_io()
completes. Previously, I_DIRTY_PAGES stayed set in
__writeback_single_inode() across the entire do_writepages() call.
However, folio_start_writeback() clears PAGECACHE_TAG_DIRTY and sets
PAGECACHE_TAG_WRITEBACK before wait_for_direct_io() sends the write to the
server:
CPU0 CPU1
orangefs_writepage_locked()
folio_start_writeback(folio)
/* clears PAGECACHE_TAG_DIRTY,
sets PAGECACHE_TAG_WRITEBACK */
orangefs_getattr()
orangefs_inode_getattr(...,
ORANGEFS_GETATTR_SIZE)
/* PAGECACHE_TAG_DIRTY is false */
service_operation(GETATTR)
inode->i_size = ...; <-- stale size
len = i_size_read(inode);
wait_for_direct_io(ORANGEFS_IO_WRITE, ...)
As a result, any concurrent getattr with non-zero flags (such as
orangefs_getattr() or orangefs_file_llseek()) fetches the pre-write size
from the server and clobbers inode->i_size, which also causes
orangefs_writepage_locked() (or a subsequent batch in
orangefs_writepages_work()) to clamp the write length to the stale size and
truncate the buffered write.
Should these checks also test mapping_tagged(inode->i_mapping,
PAGECACHE_TAG_WRITEBACK) (or mapping_writably_mapped() / a helper covering
both PAGECACHE_TAG_DIRTY and PAGECACHE_TAG_WRITEBACK)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113083336.15152-1-jack@suse.cz?part=3
next prev parent reply other threads:[~2026-11-13 9:00 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 8:47 [PATCH 0/13] fs: Various I_DIRTY_* state handling fixes Jan Kara
2026-11-13 8:47 ` [PATCH 01/13] bdev: Drop pointless loop from blkdev_flush_mapping() Jan Kara
2026-11-13 8:47 ` [PATCH 02/13] xfs: Drop pointless I_DIRTY_PAGES check in xfs_can_free_cowblocks() Jan Kara
2026-11-13 8:47 ` [PATCH 03/13] orangefs: Check PAGECACHE_TAG_DIRTY instead of I_DIRTY_PAGES inode state Jan Kara
2026-11-13 9:00 ` sashiko-bot [this message]
2026-11-13 10:34 ` Jan Kara
2026-11-13 8:47 ` [PATCH 04/13] fs: Provide inode_is_dirty() helper Jan Kara
2026-11-13 8:47 ` [PATCH 05/13] jfs: Use inode_is_dirty() in jfs_fsync() Jan Kara
2026-11-13 8:47 ` [PATCH 06/13] gfs2: Avoid racy dirtiness check in gfs2_fsync() Jan Kara
2026-11-13 9:08 ` sashiko-bot
2026-11-13 10:14 ` Jan Kara
2026-11-13 8:47 ` [PATCH 07/13] fuse: Use inode_is_dirty() check in fuse_evict_inode() Jan Kara
2026-11-13 8:47 ` [PATCH 08/13] fs: Provide inode_or_folios_dirty() helper Jan Kara
2026-11-13 8:47 ` [PATCH 09/13] gfs2: Fix dirtiness checks in gfs2_write_inode() and evict_linked_inode() Jan Kara
2026-11-13 8:56 ` sashiko-bot
2026-11-13 10:02 ` Jan Kara
2026-11-13 8:47 ` [PATCH 10/13] afs: Use inode_or_folios_dirty() in afs_evict_inode() Jan Kara
2026-11-13 8:47 ` [PATCH 11/13] nfsd: Use inode_or_folios_dirty() for dirtiness check in wait_for_concurrent_writes() Jan Kara
2026-11-13 8:59 ` sashiko-bot
2026-11-13 8:47 ` [PATCH 12/13] fscrypt: Use inode_or_folios_dirty() instead of explicit state check Jan Kara
2026-11-13 8:47 ` [PATCH 13/13] fs: Use inode_or_folios_dirty() in __inode_lru_list_add() Jan Kara
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=sashiko-outbox-212490@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=agruenba@redhat.com \
--cc=anna@kernel.org \
--cc=brauner@kernel.org \
--cc=cel@kernel.org \
--cc=cem@kernel.org \
--cc=devel@lists.orangefs.org \
--cc=dhowells@redhat.com \
--cc=ebiggers@kernel.org \
--cc=hubcap@omnibond.com \
--cc=jack@suse.cz \
--cc=jaegeuk@kernel.org \
--cc=jlayton@kernel.org \
--cc=linux-fscrypt@vger.kernel.org \
--cc=marc.dionne@auristor.com \
--cc=martin@omnibond.com \
--cc=miklos@szeredi.hu \
--cc=sashiko-reviews@lists.linux.dev \
--cc=shaggy@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.