]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
nfsd: don't set the ctime on delegated atime updates
authorJeff Layton <jlayton@kernel.org>
Wed, 16 Jul 2025 13:34:29 +0000 (09:34 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Tue, 5 Aug 2025 14:31:33 +0000 (10:31 -0400)
Clients will typically precede a DELEGRETURN for a delegation with
delegated timestamp with a SETATTR to set the timestamps on the server
to match what the client has.

knfsd implements this by using the nfsd_setattr() infrastructure, which
will set ATTR_CTIME on any update that goes to notify_change(). This is
problematic as it means that the client will get a spurious ctime
update when updating the atime.

POSIX unfortunately doesn't phrase it succinctly, but updating the atime
due to reads should not update the ctime. In this case, the client is
sending a SETATTR to update the atime on the server to match its latest
value. The ctime should not be advanced in this case as that would
incorrectly indicate a change to the inode.

Fix this by not implicitly setting ATTR_CTIME when ATTR_DELEG is set in
__nfsd_setattr(). The decoder for FATTR4_WORD2_TIME_DELEG_MODIFY already
sets ATTR_CTIME, so this is sufficient to make it skip setting the ctime
on atime-only updates.

Fixes: 7e13f4f8d27d ("nfsd: handle delegated timestamps in SETATTR")
Cc: stable@vger.kernel.org
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/vfs.c

index ee78b6fb17098b788b07f5cd90598e678244b57e..eaf04751d07fe9be4d1dd08477bc5a38ac99be3a 100644 (file)
@@ -470,7 +470,15 @@ static int __nfsd_setattr(struct dentry *dentry, struct iattr *iap)
        if (!iap->ia_valid)
                return 0;
 
-       iap->ia_valid |= ATTR_CTIME;
+       /*
+        * If ATTR_DELEG is set, then this is an update from a client that
+        * holds a delegation. If this is an update for only the atime, the
+        * ctime should not be changed. If the update contains the mtime
+        * too, then ATTR_CTIME should already be set.
+        */
+       if (!(iap->ia_valid & ATTR_DELEG))
+               iap->ia_valid |= ATTR_CTIME;
+
        return notify_change(&nop_mnt_idmap, dentry, iap, NULL);
 }