Push clamping timestamps down the call stack into notify_change(), so in-kernel callers like nfsd and overlayfs will get similar timestamp set behavior as utimes.
Suggested-by: Miklos Szeredi mszeredi@redhat.com Fixes: 42e729b9ddbb ("utimes: Clamp the timestamps before update") Cc: stable@vger.kernel.org # v5.4 Cc: Deepa Dinamani deepa.kernel@gmail.com Cc: Jeff Layton jlayton@kernel.org Signed-off-by: Amir Goldstein amir73il@gmail.com ---
Arnd,
This fixes xfstest generic/402 when run with -overlay setup. Note that running the test requires latest xfstests with: acb2ba78 - overlay: support timestamp range check
I had previously posted a fix specific for overlayfs [1], but Miklos suggested this more generic fix, which should also serve nfsd and other in-kernel users.
I tested this change with test generic/402 on ext4/xfs/btrfs and overlayfs, but not with nfsd.
Jeff, could you ack this change is good for nfsd as well?
Thanks, Amir.
[1] https://lore.kernel.org/linux-fsdevel/20191111073000.2957-1-amir73il@gmail.c...
fs/attr.c | 5 +++++ fs/utimes.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c index df28035aa23e..e8de5e636e66 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -268,8 +268,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; + else + attr->ia_atime = timestamp_truncate(attr->ia_atime, inode); if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; + else + attr->ia_mtime = timestamp_truncate(attr->ia_mtime, inode); + if (ia_valid & ATTR_KILL_PRIV) { error = security_inode_need_killpriv(dentry); if (error < 0) diff --git a/fs/utimes.c b/fs/utimes.c index 1ba3f7883870..090739322463 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -36,14 +36,14 @@ static int utimes_common(const struct path *path, struct timespec64 *times) if (times[0].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_ATIME; else if (times[0].tv_nsec != UTIME_NOW) { - newattrs.ia_atime = timestamp_truncate(times[0], inode); + newattrs.ia_atime = times[0]; newattrs.ia_valid |= ATTR_ATIME_SET; }
if (times[1].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_MTIME; else if (times[1].tv_nsec != UTIME_NOW) { - newattrs.ia_mtime = timestamp_truncate(times[1], inode); + newattrs.ia_mtime = times[1]; newattrs.ia_valid |= ATTR_MTIME_SET; } /*