Skip to content

Commit 7d6c8b6

Browse files
committed
fs: have setattr_copy handle multigrain timestamps appropriately
JIRA: https://issues.redhat.com/browse/RHEL-121527 The setattr codepath is still using coarse-grained timestamps, even on multigrain filesystems. To fix this, fetch the timestamp for ctime updates later, at the point where the assignment occurs in setattr_copy. On a multigrain inode, ignore the ia_ctime in the attrs, and always update the ctime to the current clock value. Update the atime and mtime with the same value (if needed) unless they are being set to other specific values, a'la utimes(). Do not do this universally however, as some filesystems (e.g. most networked fs) want to do an explicit update elsewhere before updating the local inode. Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: Jan Kara <jack@suse.cz> Tested-by: Randy Dunlap <rdunlap@infradead.org> # documentation bits Signed-off-by: Jeff Layton <jlayton@kernel.org> Link: https://lore.kernel.org/r/20241002-mgtime-v10-4-d1c4717f5284@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org> (cherry picked from commit b82f92d) Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com>
1 parent bd5e6ec commit 7d6c8b6

File tree

1 file changed

+46
-6
lines changed

1 file changed

+46
-6
lines changed

fs/attr.c

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,42 @@ int inode_newsize_ok(const struct inode *inode, loff_t offset)
271271
}
272272
EXPORT_SYMBOL(inode_newsize_ok);
273273

274+
/**
275+
* setattr_copy_mgtime - update timestamps for mgtime inodes
276+
* @inode: inode timestamps to be updated
277+
* @attr: attrs for the update
278+
*
279+
* With multigrain timestamps, take more care to prevent races when
280+
* updating the ctime. Always update the ctime to the very latest using
281+
* the standard mechanism, and use that to populate the atime and mtime
282+
* appropriately (unless those are being set to specific values).
283+
*/
284+
static void setattr_copy_mgtime(struct inode *inode, const struct iattr *attr)
285+
{
286+
unsigned int ia_valid = attr->ia_valid;
287+
struct timespec64 now;
288+
289+
/*
290+
* If the ctime isn't being updated then nothing else should be
291+
* either.
292+
*/
293+
if (!(ia_valid & ATTR_CTIME)) {
294+
WARN_ON_ONCE(ia_valid & (ATTR_ATIME|ATTR_MTIME));
295+
return;
296+
}
297+
298+
now = inode_set_ctime_current(inode);
299+
if (ia_valid & ATTR_ATIME_SET)
300+
inode_set_atime_to_ts(inode, attr->ia_atime);
301+
else if (ia_valid & ATTR_ATIME)
302+
inode_set_atime_to_ts(inode, now);
303+
304+
if (ia_valid & ATTR_MTIME_SET)
305+
inode_set_mtime_to_ts(inode, attr->ia_mtime);
306+
else if (ia_valid & ATTR_MTIME)
307+
inode_set_mtime_to_ts(inode, now);
308+
}
309+
274310
/**
275311
* setattr_copy - copy simple metadata updates into the generic inode
276312
* @idmap: idmap of the mount the inode was found from
@@ -303,19 +339,23 @@ void setattr_copy(struct mnt_idmap *idmap, struct inode *inode,
303339

304340
i_uid_update(idmap, attr, inode);
305341
i_gid_update(idmap, attr, inode);
306-
if (ia_valid & ATTR_ATIME)
307-
inode_set_atime_to_ts(inode, attr->ia_atime);
308-
if (ia_valid & ATTR_MTIME)
309-
inode_set_mtime_to_ts(inode, attr->ia_mtime);
310-
if (ia_valid & ATTR_CTIME)
311-
inode_set_ctime_to_ts(inode, attr->ia_ctime);
312342
if (ia_valid & ATTR_MODE) {
313343
umode_t mode = attr->ia_mode;
314344
if (!in_group_or_capable(idmap, inode,
315345
i_gid_into_vfsgid(idmap, inode)))
316346
mode &= ~S_ISGID;
317347
inode->i_mode = mode;
318348
}
349+
350+
if (is_mgtime(inode))
351+
return setattr_copy_mgtime(inode, attr);
352+
353+
if (ia_valid & ATTR_ATIME)
354+
inode_set_atime_to_ts(inode, attr->ia_atime);
355+
if (ia_valid & ATTR_MTIME)
356+
inode_set_mtime_to_ts(inode, attr->ia_mtime);
357+
if (ia_valid & ATTR_CTIME)
358+
inode_set_ctime_to_ts(inode, attr->ia_ctime);
319359
}
320360
EXPORT_SYMBOL(setattr_copy);
321361

0 commit comments

Comments
 (0)