mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-13 13:03:15 -05:00
fs: refactor ->update_time handling
Pass the type of update (atime vs c/mtime plus version) as an enum instead of a set of flags that caused all kinds of confusion. Because inode_update_timestamps now can't return a modified version of those flags, return the I_DIRTY_* flags needed to persist the update, which is what the main caller in generic_update_time wants anyway, and which is suitable for the other callers that only want to know if an update happened. The whole update_time path keeps the flags argument, which will be used to support non-blocking updates soon even if it is unused, and (the slightly renamed) inode_update_time also gains the possibility to return a negative errno to support this. Signed-off-by: Christoph Hellwig <hch@lst.de> Link: https://patch.msgid.link/20260108141934.2052404-6-hch@lst.de Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
committed by
Christian Brauner
parent
1cbc822816
commit
761475268f
@@ -80,7 +80,8 @@ prototypes::
|
||||
int (*getattr) (struct mnt_idmap *, const struct path *, struct kstat *, u32, unsigned int);
|
||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
|
||||
void (*update_time)(struct inode *, struct timespec *, int);
|
||||
void (*update_time)(struct inode *inode, enum fs_update_time type,
|
||||
int flags);
|
||||
int (*atomic_open)(struct inode *, struct dentry *,
|
||||
struct file *, unsigned open_flag,
|
||||
umode_t create_mode);
|
||||
|
||||
@@ -485,7 +485,8 @@ As of kernel 2.6.22, the following members are defined:
|
||||
int (*setattr) (struct mnt_idmap *, struct dentry *, struct iattr *);
|
||||
int (*getattr) (struct mnt_idmap *, const struct path *, struct kstat *, u32, unsigned int);
|
||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||
void (*update_time)(struct inode *, struct timespec *, int);
|
||||
void (*update_time)(struct inode *inode, enum fs_update_time type,
|
||||
int flags);
|
||||
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
|
||||
unsigned open_flag, umode_t create_mode);
|
||||
int (*tmpfile) (struct mnt_idmap *, struct inode *, struct file *, umode_t);
|
||||
|
||||
@@ -133,7 +133,8 @@ static int bad_inode_fiemap(struct inode *inode,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_inode_update_time(struct inode *inode, int flags)
|
||||
static int bad_inode_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -6345,16 +6345,19 @@ static int btrfs_dirty_inode(struct btrfs_inode *inode)
|
||||
* We need our own ->update_time so that we can return error on ENOSPC for
|
||||
* updating the inode in the case of file write and mmap writes.
|
||||
*/
|
||||
static int btrfs_update_time(struct inode *inode, int flags)
|
||||
static int btrfs_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
bool dirty;
|
||||
int dirty;
|
||||
|
||||
if (btrfs_root_readonly(root))
|
||||
return -EROFS;
|
||||
|
||||
dirty = inode_update_timestamps(inode, flags);
|
||||
return dirty ? btrfs_dirty_inode(BTRFS_I(inode)) : 0;
|
||||
dirty = inode_update_time(inode, type, flags);
|
||||
if (dirty <= 0)
|
||||
return dirty;
|
||||
return btrfs_dirty_inode(BTRFS_I(inode));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -472,7 +472,8 @@ extern struct timespec64 fat_truncate_atime(const struct msdos_sb_info *sbi,
|
||||
#define FAT_UPDATE_CMTIME (1u << 1)
|
||||
void fat_truncate_time(struct inode *inode, struct timespec64 *now,
|
||||
unsigned int flags);
|
||||
extern int fat_update_time(struct inode *inode, int flags);
|
||||
int fat_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags);
|
||||
extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
|
||||
|
||||
int fat_cache_init(void);
|
||||
|
||||
@@ -332,28 +332,14 @@ void fat_truncate_time(struct inode *inode, struct timespec64 *now,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fat_truncate_time);
|
||||
|
||||
int fat_update_time(struct inode *inode, int flags)
|
||||
int fat_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
unsigned int fat_flags = 0;
|
||||
int dirty_flags = 0;
|
||||
|
||||
if (inode->i_ino == MSDOS_ROOT_INO)
|
||||
return 0;
|
||||
|
||||
if (flags & S_ATIME)
|
||||
fat_flags |= FAT_UPDATE_ATIME;
|
||||
if (flags & (S_CTIME | S_MTIME))
|
||||
fat_flags |= FAT_UPDATE_CMTIME;
|
||||
|
||||
if (fat_flags) {
|
||||
fat_truncate_time(inode, NULL, flags);
|
||||
if (inode->i_sb->s_flags & SB_LAZYTIME)
|
||||
dirty_flags |= I_DIRTY_TIME;
|
||||
else
|
||||
dirty_flags |= I_DIRTY_SYNC;
|
||||
if (inode->i_ino != MSDOS_ROOT_INO) {
|
||||
fat_truncate_time(inode, NULL, type == FS_UPD_ATIME ?
|
||||
FAT_UPDATE_ATIME : FAT_UPDATE_CMTIME);
|
||||
__mark_inode_dirty(inode, inode_time_dirty_flag(inode));
|
||||
}
|
||||
|
||||
__mark_inode_dirty(inode, dirty_flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fat_update_time);
|
||||
|
||||
@@ -2242,7 +2242,8 @@ loff_t gfs2_seek_hole(struct file *file, loff_t offset)
|
||||
return vfs_setpos(file, ret, inode->i_sb->s_maxbytes);
|
||||
}
|
||||
|
||||
static int gfs2_update_time(struct inode *inode, int flags)
|
||||
static int gfs2_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_glock *gl = ip->i_gl;
|
||||
@@ -2257,7 +2258,7 @@ static int gfs2_update_time(struct inode *inode, int flags)
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
return generic_update_time(inode, flags);
|
||||
return generic_update_time(inode, type, flags);
|
||||
}
|
||||
|
||||
static const struct inode_operations gfs2_file_iops = {
|
||||
|
||||
142
fs/inode.c
142
fs/inode.c
@@ -2081,78 +2081,84 @@ static bool relatime_need_update(struct vfsmount *mnt, struct inode *inode,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_update_timestamps - update the timestamps on the inode
|
||||
* @inode: inode to be updated
|
||||
* @flags: S_* flags that needed to be updated
|
||||
*
|
||||
* The update_time function is called when an inode's timestamps need to be
|
||||
* updated for a read or write operation. This function handles updating the
|
||||
* actual timestamps. It's up to the caller to ensure that the inode is marked
|
||||
* dirty appropriately.
|
||||
*
|
||||
* In the case where any of S_MTIME, S_CTIME, or S_VERSION need to be updated,
|
||||
* attempt to update all three of them. S_ATIME updates can be handled
|
||||
* independently of the rest.
|
||||
*
|
||||
* Returns a set of S_* flags indicating which values changed.
|
||||
*/
|
||||
int inode_update_timestamps(struct inode *inode, int flags)
|
||||
static int inode_update_atime(struct inode *inode)
|
||||
{
|
||||
int updated = 0;
|
||||
struct timespec64 now;
|
||||
struct timespec64 atime = inode_get_atime(inode);
|
||||
struct timespec64 now = current_time(inode);
|
||||
|
||||
if (flags & (S_MTIME|S_CTIME|S_VERSION)) {
|
||||
struct timespec64 ctime = inode_get_ctime(inode);
|
||||
struct timespec64 mtime = inode_get_mtime(inode);
|
||||
if (timespec64_equal(&now, &atime))
|
||||
return 0;
|
||||
|
||||
now = inode_set_ctime_current(inode);
|
||||
if (!timespec64_equal(&now, &ctime))
|
||||
updated |= S_CTIME;
|
||||
if (!timespec64_equal(&now, &mtime)) {
|
||||
inode_set_mtime_to_ts(inode, now);
|
||||
updated |= S_MTIME;
|
||||
}
|
||||
if (IS_I_VERSION(inode) && inode_maybe_inc_iversion(inode, updated))
|
||||
updated |= S_VERSION;
|
||||
} else {
|
||||
now = current_time(inode);
|
||||
}
|
||||
|
||||
if (flags & S_ATIME) {
|
||||
struct timespec64 atime = inode_get_atime(inode);
|
||||
|
||||
if (!timespec64_equal(&now, &atime)) {
|
||||
inode_set_atime_to_ts(inode, now);
|
||||
updated |= S_ATIME;
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
inode_set_atime_to_ts(inode, now);
|
||||
return inode_time_dirty_flag(inode);
|
||||
}
|
||||
EXPORT_SYMBOL(inode_update_timestamps);
|
||||
|
||||
static int inode_update_cmtime(struct inode *inode)
|
||||
{
|
||||
struct timespec64 ctime = inode_get_ctime(inode);
|
||||
struct timespec64 mtime = inode_get_mtime(inode);
|
||||
struct timespec64 now = inode_set_ctime_current(inode);
|
||||
unsigned int dirty = 0;
|
||||
bool mtime_changed;
|
||||
|
||||
mtime_changed = !timespec64_equal(&now, &mtime);
|
||||
if (mtime_changed || !timespec64_equal(&now, &ctime))
|
||||
dirty = inode_time_dirty_flag(inode);
|
||||
if (mtime_changed)
|
||||
inode_set_mtime_to_ts(inode, now);
|
||||
|
||||
if (IS_I_VERSION(inode) && inode_maybe_inc_iversion(inode, !!dirty))
|
||||
dirty |= I_DIRTY_SYNC;
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_update_time - update either atime or c/mtime and i_version on the inode
|
||||
* @inode: inode to be updated
|
||||
* @type: timestamp to be updated
|
||||
* @flags: flags for the update
|
||||
*
|
||||
* Update either atime or c/mtime and version in a inode if needed for a file
|
||||
* access or modification. It is up to the caller to mark the inode dirty
|
||||
* appropriately.
|
||||
*
|
||||
* Returns the positive I_DIRTY_* flags for __mark_inode_dirty() if the inode
|
||||
* needs to be marked dirty, 0 if it did not, or a negative errno if an error
|
||||
* happened.
|
||||
*/
|
||||
int inode_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
switch (type) {
|
||||
case FS_UPD_ATIME:
|
||||
return inode_update_atime(inode);
|
||||
case FS_UPD_CMTIME:
|
||||
return inode_update_cmtime(inode);
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(inode_update_time);
|
||||
|
||||
/**
|
||||
* generic_update_time - update the timestamps on the inode
|
||||
* @inode: inode to be updated
|
||||
* @flags: S_* flags that needed to be updated
|
||||
*
|
||||
* The update_time function is called when an inode's timestamps need to be
|
||||
* updated for a read or write operation. In the case where any of S_MTIME, S_CTIME,
|
||||
* or S_VERSION need to be updated we attempt to update all three of them. S_ATIME
|
||||
* updates can be handled done independently of the rest.
|
||||
* @type: timestamp to be updated
|
||||
* @flags: flags for the update
|
||||
*
|
||||
* Returns a negative error value on error, else 0.
|
||||
*/
|
||||
int generic_update_time(struct inode *inode, int flags)
|
||||
int generic_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
int updated = inode_update_timestamps(inode, flags);
|
||||
int dirty_flags = 0;
|
||||
int dirty;
|
||||
|
||||
if (updated & (S_ATIME|S_MTIME|S_CTIME))
|
||||
dirty_flags = inode->i_sb->s_flags & SB_LAZYTIME ? I_DIRTY_TIME : I_DIRTY_SYNC;
|
||||
if (updated & S_VERSION)
|
||||
dirty_flags |= I_DIRTY_SYNC;
|
||||
__mark_inode_dirty(inode, dirty_flags);
|
||||
dirty = inode_update_time(inode, type, flags);
|
||||
if (dirty <= 0)
|
||||
return dirty;
|
||||
__mark_inode_dirty(inode, dirty);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_update_time);
|
||||
@@ -2225,9 +2231,9 @@ void touch_atime(const struct path *path)
|
||||
* of the fs read only, e.g. subvolumes in Btrfs.
|
||||
*/
|
||||
if (inode->i_op->update_time)
|
||||
inode->i_op->update_time(inode, S_ATIME);
|
||||
inode->i_op->update_time(inode, FS_UPD_ATIME, 0);
|
||||
else
|
||||
generic_update_time(inode, S_ATIME);
|
||||
generic_update_time(inode, FS_UPD_ATIME, 0);
|
||||
mnt_put_write_access(mnt);
|
||||
skip_update:
|
||||
sb_end_write(inode->i_sb);
|
||||
@@ -2354,7 +2360,7 @@ static int file_update_time_flags(struct file *file, unsigned int flags)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct timespec64 now, ts;
|
||||
int sync_mode = 0;
|
||||
bool need_update = false;
|
||||
int ret = 0;
|
||||
|
||||
/* First try to exhaust all avenues to not sync */
|
||||
@@ -2367,14 +2373,14 @@ static int file_update_time_flags(struct file *file, unsigned int flags)
|
||||
|
||||
ts = inode_get_mtime(inode);
|
||||
if (!timespec64_equal(&ts, &now))
|
||||
sync_mode |= S_MTIME;
|
||||
need_update = true;
|
||||
ts = inode_get_ctime(inode);
|
||||
if (!timespec64_equal(&ts, &now))
|
||||
sync_mode |= S_CTIME;
|
||||
need_update = true;
|
||||
if (IS_I_VERSION(inode) && inode_iversion_need_inc(inode))
|
||||
sync_mode |= S_VERSION;
|
||||
need_update = true;
|
||||
|
||||
if (!sync_mode)
|
||||
if (!need_update)
|
||||
return 0;
|
||||
|
||||
if (flags & IOCB_NOWAIT)
|
||||
@@ -2383,9 +2389,9 @@ static int file_update_time_flags(struct file *file, unsigned int flags)
|
||||
if (mnt_get_write_access_file(file))
|
||||
return 0;
|
||||
if (inode->i_op->update_time)
|
||||
ret = inode->i_op->update_time(inode, sync_mode);
|
||||
ret = inode->i_op->update_time(inode, FS_UPD_CMTIME, 0);
|
||||
else
|
||||
ret = generic_update_time(inode, sync_mode);
|
||||
ret = generic_update_time(inode, FS_UPD_CMTIME, 0);
|
||||
mnt_put_write_access_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -649,15 +649,15 @@ static void nfs_set_timestamps_to_ts(struct inode *inode, struct iattr *attr)
|
||||
struct timespec64 ctime = inode_get_ctime(inode);
|
||||
struct timespec64 mtime = inode_get_mtime(inode);
|
||||
struct timespec64 now;
|
||||
int updated = 0;
|
||||
bool updated = false;
|
||||
|
||||
now = inode_set_ctime_current(inode);
|
||||
if (!timespec64_equal(&now, &ctime))
|
||||
updated |= S_CTIME;
|
||||
updated = true;
|
||||
|
||||
inode_set_mtime_to_ts(inode, attr->ia_mtime);
|
||||
if (!timespec64_equal(&now, &mtime))
|
||||
updated |= S_MTIME;
|
||||
updated = true;
|
||||
|
||||
inode_maybe_inc_iversion(inode, updated);
|
||||
cache_flags |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;
|
||||
@@ -671,13 +671,13 @@ static void nfs_set_timestamps_to_ts(struct inode *inode, struct iattr *attr)
|
||||
|
||||
static void nfs_update_atime(struct inode *inode)
|
||||
{
|
||||
inode_update_timestamps(inode, S_ATIME);
|
||||
inode_update_time(inode, FS_UPD_ATIME, 0);
|
||||
NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ATIME;
|
||||
}
|
||||
|
||||
static void nfs_update_mtime(struct inode *inode)
|
||||
{
|
||||
inode_update_timestamps(inode, S_MTIME | S_CTIME);
|
||||
inode_update_time(inode, FS_UPD_CMTIME, 0);
|
||||
NFS_I(inode)->cache_validity &=
|
||||
~(NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME);
|
||||
}
|
||||
|
||||
@@ -872,22 +872,24 @@ int orangefs_permission(struct mnt_idmap *idmap,
|
||||
return generic_permission(&nop_mnt_idmap, inode, mask);
|
||||
}
|
||||
|
||||
int orangefs_update_time(struct inode *inode, int flags)
|
||||
int orangefs_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct iattr iattr;
|
||||
struct iattr iattr = { };
|
||||
int dirty;
|
||||
|
||||
gossip_debug(GOSSIP_INODE_DEBUG, "orangefs_update_time: %pU\n",
|
||||
get_khandle_from_ino(inode));
|
||||
switch (type) {
|
||||
case FS_UPD_ATIME:
|
||||
iattr.ia_valid = ATTR_ATIME;
|
||||
break;
|
||||
case FS_UPD_CMTIME:
|
||||
iattr.ia_valid = ATTR_CTIME | ATTR_MTIME;
|
||||
break;
|
||||
}
|
||||
|
||||
flags = inode_update_timestamps(inode, flags);
|
||||
|
||||
memset(&iattr, 0, sizeof iattr);
|
||||
if (flags & S_ATIME)
|
||||
iattr.ia_valid |= ATTR_ATIME;
|
||||
if (flags & S_CTIME)
|
||||
iattr.ia_valid |= ATTR_CTIME;
|
||||
if (flags & S_MTIME)
|
||||
iattr.ia_valid |= ATTR_MTIME;
|
||||
dirty = inode_update_time(inode, type, flags);
|
||||
if (dirty <= 0)
|
||||
return dirty;
|
||||
return __orangefs_setattr(inode, &iattr);
|
||||
}
|
||||
|
||||
|
||||
@@ -360,7 +360,8 @@ int orangefs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
int orangefs_permission(struct mnt_idmap *idmap,
|
||||
struct inode *inode, int mask);
|
||||
|
||||
int orangefs_update_time(struct inode *, int);
|
||||
int orangefs_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags);
|
||||
|
||||
/*
|
||||
* defined in xattr.c
|
||||
|
||||
@@ -555,9 +555,10 @@ int ovl_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
}
|
||||
#endif
|
||||
|
||||
int ovl_update_time(struct inode *inode, int flags)
|
||||
int ovl_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (flags & S_ATIME) {
|
||||
if (type == FS_UPD_ATIME) {
|
||||
struct ovl_fs *ofs = OVL_FS(inode->i_sb);
|
||||
struct path upperpath = {
|
||||
.mnt = ovl_upper_mnt(ofs),
|
||||
|
||||
@@ -820,7 +820,8 @@ static inline struct posix_acl *ovl_get_acl_path(const struct path *path,
|
||||
}
|
||||
#endif
|
||||
|
||||
int ovl_update_time(struct inode *inode, int flags);
|
||||
int ovl_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags);
|
||||
bool ovl_is_private_xattr(struct super_block *sb, const char *name);
|
||||
|
||||
struct ovl_inode_params {
|
||||
|
||||
@@ -1361,17 +1361,8 @@ static inline int mctime_update_needed(const struct inode *inode,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_update_time - update time of inode.
|
||||
* @inode: inode to update
|
||||
* @flags: time updating control flag determines updating
|
||||
* which time fields of @inode
|
||||
*
|
||||
* This function updates time of the inode.
|
||||
*
|
||||
* Returns: %0 for success or a negative error code otherwise.
|
||||
*/
|
||||
int ubifs_update_time(struct inode *inode, int flags)
|
||||
int ubifs_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
@@ -1379,15 +1370,19 @@ int ubifs_update_time(struct inode *inode, int flags)
|
||||
.dirtied_ino_d = ALIGN(ui->data_len, 8) };
|
||||
int err, release;
|
||||
|
||||
/* ubifs sets S_NOCMTIME on all inodes, this should not happen. */
|
||||
if (WARN_ON_ONCE(type != FS_UPD_ATIME))
|
||||
return -EIO;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT))
|
||||
return generic_update_time(inode, flags);
|
||||
return generic_update_time(inode, type, flags);
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&ui->ui_mutex);
|
||||
inode_update_timestamps(inode, flags);
|
||||
inode_update_time(inode, type, flags);
|
||||
release = ui->dirty;
|
||||
__mark_inode_dirty(inode, I_DIRTY_SYNC);
|
||||
mutex_unlock(&ui->ui_mutex);
|
||||
|
||||
@@ -2018,7 +2018,8 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
|
||||
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
|
||||
int ubifs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
int ubifs_update_time(struct inode *inode, int flags);
|
||||
int ubifs_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags);
|
||||
|
||||
/* dir.c */
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
||||
|
||||
@@ -1184,21 +1184,21 @@ xfs_vn_setattr(
|
||||
STATIC int
|
||||
xfs_vn_update_time(
|
||||
struct inode *inode,
|
||||
int flags)
|
||||
enum fs_update_time type,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct xfs_inode *ip = XFS_I(inode);
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
int log_flags = XFS_ILOG_TIMESTAMP;
|
||||
struct xfs_trans *tp;
|
||||
int error;
|
||||
struct timespec64 now;
|
||||
|
||||
trace_xfs_update_time(ip);
|
||||
|
||||
if (inode->i_sb->s_flags & SB_LAZYTIME) {
|
||||
if (!((flags & S_VERSION) &&
|
||||
inode_maybe_inc_iversion(inode, false)))
|
||||
return generic_update_time(inode, flags);
|
||||
if (type == FS_UPD_ATIME ||
|
||||
!inode_maybe_inc_iversion(inode, false))
|
||||
return generic_update_time(inode, type, flags);
|
||||
|
||||
/* Capture the iversion update that just occurred */
|
||||
log_flags |= XFS_ILOG_CORE;
|
||||
@@ -1209,16 +1209,10 @@ xfs_vn_update_time(
|
||||
return error;
|
||||
|
||||
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
||||
if (flags & (S_CTIME|S_MTIME))
|
||||
now = inode_set_ctime_current(inode);
|
||||
if (type == FS_UPD_ATIME)
|
||||
inode_set_atime_to_ts(inode, current_time(inode));
|
||||
else
|
||||
now = current_time(inode);
|
||||
|
||||
if (flags & S_MTIME)
|
||||
inode_set_mtime_to_ts(inode, now);
|
||||
if (flags & S_ATIME)
|
||||
inode_set_atime_to_ts(inode, now);
|
||||
|
||||
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
|
||||
xfs_trans_log_inode(tp, ip, log_flags);
|
||||
return xfs_trans_commit(tp);
|
||||
|
||||
@@ -1717,6 +1717,13 @@ static inline struct timespec64 inode_set_ctime(struct inode *inode,
|
||||
|
||||
struct timespec64 simple_inode_init_ts(struct inode *inode);
|
||||
|
||||
static inline int inode_time_dirty_flag(struct inode *inode)
|
||||
{
|
||||
if (inode->i_sb->s_flags & SB_LAZYTIME)
|
||||
return I_DIRTY_TIME;
|
||||
return I_DIRTY_SYNC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Snapshotting support.
|
||||
*/
|
||||
@@ -1983,6 +1990,11 @@ int wrap_directory_iterator(struct file *, struct dir_context *,
|
||||
static int shared_##x(struct file *file , struct dir_context *ctx) \
|
||||
{ return wrap_directory_iterator(file, ctx, x); }
|
||||
|
||||
enum fs_update_time {
|
||||
FS_UPD_ATIME,
|
||||
FS_UPD_CMTIME,
|
||||
};
|
||||
|
||||
struct inode_operations {
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
|
||||
const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
|
||||
@@ -2010,7 +2022,8 @@ struct inode_operations {
|
||||
ssize_t (*listxattr) (struct dentry *, char *, size_t);
|
||||
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
|
||||
u64 len);
|
||||
int (*update_time)(struct inode *, int);
|
||||
int (*update_time)(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags);
|
||||
int (*atomic_open)(struct inode *, struct dentry *,
|
||||
struct file *, unsigned open_flag,
|
||||
umode_t create_mode);
|
||||
@@ -2237,13 +2250,6 @@ static inline void inode_dec_link_count(struct inode *inode)
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
|
||||
enum file_time_flags {
|
||||
S_ATIME = 1,
|
||||
S_MTIME = 2,
|
||||
S_CTIME = 4,
|
||||
S_VERSION = 8,
|
||||
};
|
||||
|
||||
extern bool atime_needs_update(const struct path *, struct inode *);
|
||||
extern void touch_atime(const struct path *);
|
||||
|
||||
@@ -2398,8 +2404,10 @@ static inline void super_set_sysfs_name_generic(struct super_block *sb, const ch
|
||||
extern void ihold(struct inode * inode);
|
||||
extern void iput(struct inode *);
|
||||
void iput_not_last(struct inode *);
|
||||
int inode_update_timestamps(struct inode *inode, int flags);
|
||||
int generic_update_time(struct inode *inode, int flags);
|
||||
int inode_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags);
|
||||
int generic_update_time(struct inode *inode, enum fs_update_time type,
|
||||
unsigned int flags);
|
||||
|
||||
/* /sys/fs */
|
||||
extern struct kobject *fs_kobj;
|
||||
|
||||
Reference in New Issue
Block a user