Skip to content

Commit afc5b36

Browse files
jtlaytonchucklever
authored andcommitted
vfs: add ATTR_CTIME_SET flag
When ATTR_ATIME_SET and ATTR_MTIME_SET are set in the ia_valid mask, the notify_change() logic takes that to mean that the request should set those values explicitly, and not override them with "now". With the advent of delegated timestamps, similar functionality is needed for the ctime. Add a ATTR_CTIME_SET flag, and use that to indicate that the ctime should be accepted as-is. Also, clean up the if statements to eliminate the extra negatives. In setattr_copy() and setattr_copy_mgtime() use inode_set_ctime_deleg() when ATTR_CTIME_SET is set, instead of basing the decision on ATTR_DELEG. Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 5affb49 commit afc5b36

2 files changed

Lines changed: 20 additions & 25 deletions

File tree

fs/attr.c

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -286,20 +286,12 @@ static void setattr_copy_mgtime(struct inode *inode, const struct iattr *attr)
286286
unsigned int ia_valid = attr->ia_valid;
287287
struct timespec64 now;
288288

289-
if (ia_valid & ATTR_CTIME) {
290-
/*
291-
* In the case of an update for a write delegation, we must respect
292-
* the value in ia_ctime and not use the current time.
293-
*/
294-
if (ia_valid & ATTR_DELEG)
295-
now = inode_set_ctime_deleg(inode, attr->ia_ctime);
296-
else
297-
now = inode_set_ctime_current(inode);
298-
} else {
299-
/* If ATTR_CTIME isn't set, then ATTR_MTIME shouldn't be either. */
300-
WARN_ON_ONCE(ia_valid & ATTR_MTIME);
289+
if (ia_valid & ATTR_CTIME_SET)
290+
now = inode_set_ctime_deleg(inode, attr->ia_ctime);
291+
else if (ia_valid & ATTR_CTIME)
292+
now = inode_set_ctime_current(inode);
293+
else
301294
now = current_time(inode);
302-
}
303295

304296
if (ia_valid & ATTR_ATIME_SET)
305297
inode_set_atime_to_ts(inode, attr->ia_atime);
@@ -359,12 +351,11 @@ void setattr_copy(struct mnt_idmap *idmap, struct inode *inode,
359351
inode_set_atime_to_ts(inode, attr->ia_atime);
360352
if (ia_valid & ATTR_MTIME)
361353
inode_set_mtime_to_ts(inode, attr->ia_mtime);
362-
if (ia_valid & ATTR_CTIME) {
363-
if (ia_valid & ATTR_DELEG)
364-
inode_set_ctime_deleg(inode, attr->ia_ctime);
365-
else
366-
inode_set_ctime_to_ts(inode, attr->ia_ctime);
367-
}
354+
355+
if (ia_valid & ATTR_CTIME_SET)
356+
inode_set_ctime_deleg(inode, attr->ia_ctime);
357+
else if (ia_valid & ATTR_CTIME)
358+
inode_set_ctime_to_ts(inode, attr->ia_ctime);
368359
}
369360
EXPORT_SYMBOL(setattr_copy);
370361

@@ -463,15 +454,18 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
463454

464455
now = current_time(inode);
465456

466-
attr->ia_ctime = now;
467-
if (!(ia_valid & ATTR_ATIME_SET))
468-
attr->ia_atime = now;
469-
else
457+
if (ia_valid & ATTR_ATIME_SET)
470458
attr->ia_atime = timestamp_truncate(attr->ia_atime, inode);
471-
if (!(ia_valid & ATTR_MTIME_SET))
472-
attr->ia_mtime = now;
473459
else
460+
attr->ia_atime = now;
461+
if (ia_valid & ATTR_CTIME_SET)
462+
attr->ia_ctime = timestamp_truncate(attr->ia_ctime, inode);
463+
else
464+
attr->ia_ctime = now;
465+
if (ia_valid & ATTR_MTIME_SET)
474466
attr->ia_mtime = timestamp_truncate(attr->ia_mtime, inode);
467+
else
468+
attr->ia_mtime = now;
475469

476470
if (ia_valid & ATTR_KILL_PRIV) {
477471
error = security_inode_need_killpriv(dentry);

include/linux/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
238238
#define ATTR_ATIME_SET (1 << 7)
239239
#define ATTR_MTIME_SET (1 << 8)
240240
#define ATTR_FORCE (1 << 9) /* Not a change, but a change it */
241+
#define ATTR_CTIME_SET (1 << 10)
241242
#define ATTR_KILL_SUID (1 << 11)
242243
#define ATTR_KILL_SGID (1 << 12)
243244
#define ATTR_FILE (1 << 13)

0 commit comments

Comments
 (0)