diff --git a/kmod/src/dir.c b/kmod/src/dir.c index c6eb331d..ed5e28d8 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -753,6 +753,7 @@ static int scoutfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, struct inode *inode = NULL; struct scoutfs_lock *dir_lock = NULL; struct scoutfs_lock *inode_lock = NULL; + struct scoutfs_inode_info *si; LIST_HEAD(ind_locks); u64 hash; u64 pos; @@ -766,6 +767,7 @@ static int scoutfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, &dir_lock, &inode_lock, NULL, &ind_locks); if (IS_ERR(inode)) return PTR_ERR(inode); + si = SCOUTFS_I(inode); pos = SCOUTFS_I(dir)->next_readdir_pos++; @@ -781,6 +783,7 @@ static int scoutfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, i_size_write(dir, i_size_read(dir) + dentry->d_name.len); dir->i_mtime = dir->i_ctime = CURRENT_TIME; inode->i_mtime = inode->i_atime = inode->i_ctime = dir->i_mtime; + si->crtime = inode->i_mtime; if (S_ISDIR(mode)) { inc_nlink(inode); @@ -1185,6 +1188,7 @@ static int scoutfs_symlink(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; struct scoutfs_lock *dir_lock = NULL; struct scoutfs_lock *inode_lock = NULL; + struct scoutfs_inode_info *si; LIST_HEAD(ind_locks); u64 hash; u64 pos; @@ -1205,6 +1209,7 @@ static int scoutfs_symlink(struct inode *dir, struct dentry *dentry, &dir_lock, &inode_lock, NULL, &ind_locks); if (IS_ERR(inode)) return PTR_ERR(inode); + si = SCOUTFS_I(inode); ret = symlink_item_ops(sb, SYM_CREATE, scoutfs_ino(inode), inode_lock, symname, name_len); @@ -1226,6 +1231,7 @@ static int scoutfs_symlink(struct inode *dir, struct dentry *dentry, dir->i_mtime = dir->i_ctime = CURRENT_TIME; inode->i_ctime = dir->i_mtime; + si->crtime = inode->i_ctime; i_size_write(inode, name_len); scoutfs_update_inode_item(inode, inode_lock, &ind_locks); @@ -1817,6 +1823,7 @@ static int scoutfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mod struct scoutfs_lock *dir_lock = NULL; struct scoutfs_lock *inode_lock = NULL; struct scoutfs_lock *orph_lock = NULL; + struct scoutfs_inode_info *si; LIST_HEAD(ind_locks); int ret; @@ -1827,6 +1834,7 @@ static int scoutfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mod &dir_lock, &inode_lock, &orph_lock, &ind_locks); if (IS_ERR(inode)) return PTR_ERR(inode); + si = SCOUTFS_I(inode); ret = scoutfs_inode_orphan_create(sb, scoutfs_ino(inode), orph_lock); if (ret < 0) { @@ -1835,6 +1843,7 @@ static int scoutfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mod } inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + si->crtime = inode->i_mtime; insert_inode_hash(inode); ihold(inode); /* need to update inode modifications in d_tmpfile */ d_tmpfile(dentry, inode); diff --git a/kmod/src/format.h b/kmod/src/format.h index fb6c1f4f..a546210b 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -821,7 +821,6 @@ struct scoutfs_super_block { * online by staging. * * XXX - * - otime? * - compat flags? * - version? * - generation? @@ -845,6 +844,7 @@ struct scoutfs_inode { struct scoutfs_timespec atime; struct scoutfs_timespec ctime; struct scoutfs_timespec mtime; + struct scoutfs_timespec crtime; }; #define SCOUTFS_INO_FLAG_TRUNCATE 0x1 diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 15e4014f..18f3c6a8 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -262,6 +262,8 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode) si->next_readdir_pos = le64_to_cpu(cinode->next_readdir_pos); si->next_xattr_id = le64_to_cpu(cinode->next_xattr_id); si->flags = le32_to_cpu(cinode->flags); + si->crtime.tv_sec = le64_to_cpu(cinode->crtime.sec); + si->crtime.tv_nsec = le32_to_cpu(cinode->crtime.nsec); /* * i_blocks is initialized from online and offline and is then @@ -764,6 +766,9 @@ static void store_inode(struct scoutfs_inode *cinode, struct inode *inode) cinode->next_readdir_pos = cpu_to_le64(si->next_readdir_pos); cinode->next_xattr_id = cpu_to_le64(si->next_xattr_id); cinode->flags = cpu_to_le32(si->flags); + cinode->crtime.sec = cpu_to_le64(si->crtime.tv_sec); + cinode->crtime.nsec = cpu_to_le32(si->crtime.tv_nsec); + memset(cinode->crtime.__pad, 0, sizeof(cinode->crtime.__pad)); } /* diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 7cb61b57..0207de6d 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -20,6 +20,7 @@ struct scoutfs_inode_info { u64 online_blocks; u64 offline_blocks; u32 flags; + struct timespec crtime; /* * Protects per-inode extent items, most particularly readers diff --git a/kmod/src/ioctl.c b/kmod/src/ioctl.c index cb3f4a4e..3df9da44 100644 --- a/kmod/src/ioctl.c +++ b/kmod/src/ioctl.c @@ -541,6 +541,7 @@ out: static long scoutfs_ioc_stat_more(struct file *file, unsigned long arg) { struct inode *inode = file_inode(file); + struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct scoutfs_ioctl_stat_more stm; if (get_user(stm.valid_bytes, (__u64 __user *)arg)) @@ -552,6 +553,8 @@ static long scoutfs_ioc_stat_more(struct file *file, unsigned long arg) stm.data_seq = scoutfs_inode_data_seq(inode); stm.data_version = scoutfs_inode_data_version(inode); scoutfs_inode_get_onoff(inode, &stm.online_blocks, &stm.offline_blocks); + stm.crtime_sec = si->crtime.tv_sec; + stm.crtime_nsec = si->crtime.tv_nsec; if (copy_to_user((void __user *)arg, &stm, stm.valid_bytes)) return -EFAULT; @@ -617,6 +620,7 @@ static long scoutfs_ioc_data_waiting(struct file *file, unsigned long arg) static long scoutfs_ioc_setattr_more(struct file *file, unsigned long arg) { struct inode *inode = file->f_inode; + struct scoutfs_inode_info *si = SCOUTFS_I(inode); struct super_block *sb = inode->i_sb; struct scoutfs_ioctl_setattr_more __user *usm = (void __user *)arg; struct scoutfs_ioctl_setattr_more sm; @@ -685,6 +689,8 @@ static long scoutfs_ioc_setattr_more(struct file *file, unsigned long arg) i_size_write(inode, sm.i_size); inode->i_ctime.tv_sec = sm.ctime_sec; inode->i_ctime.tv_nsec = sm.ctime_nsec; + si->crtime.tv_sec = sm.crtime_sec; + si->crtime.tv_nsec = sm.crtime_nsec; scoutfs_update_inode_item(inode, lock, &ind_locks); ret = 0; diff --git a/kmod/src/ioctl.h b/kmod/src/ioctl.h index 446611e9..a8c84e65 100644 --- a/kmod/src/ioctl.h +++ b/kmod/src/ioctl.h @@ -232,6 +232,9 @@ struct scoutfs_ioctl_stat_more { __u64 data_version; __u64 online_blocks; __u64 offline_blocks; + __u64 crtime_sec; + __u32 crtime_nsec; + __u8 _pad[4]; }; #define SCOUTFS_IOC_STAT_MORE _IOR(SCOUTFS_IOCTL_MAGIC, 5, \ @@ -275,7 +278,8 @@ struct scoutfs_ioctl_setattr_more { __u64 flags; __u64 ctime_sec; __u32 ctime_nsec; - __u8 _pad[4]; + __u32 crtime_nsec; + __u64 crtime_sec; }; #define SCOUTFS_IOC_SETATTR_MORE_OFFLINE (1 << 0) diff --git a/utils/src/stat.c b/utils/src/stat.c index 812c38ef..a0679a71 100644 --- a/utils/src/stat.c +++ b/utils/src/stat.c @@ -37,6 +37,7 @@ static struct stat_more_field inode_fields[] = { INODE_FIELD(data_version), INODE_FIELD(online_blocks), INODE_FIELD(offline_blocks), + { .name = "crtime", .offset = INODE_FIELD_OFF(crtime_sec) }, { NULL, } }; @@ -60,6 +61,9 @@ static void print_inode_field(void *st, size_t off) case INODE_FIELD_OFF(offline_blocks): printf("%llu", stm->offline_blocks); break; + case INODE_FIELD_OFF(crtime_sec): + printf("%llu.%09u", stm->crtime_sec, stm->crtime_nsec); + break; }; }