From f86fab116246a25dcf77f6a22881ccb87e44cc28 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 14 Nov 2016 14:52:28 -0800 Subject: [PATCH] Add an inode data_version field The data_version field is changed every time the contents of the file could have changed. Signed-off-by: Zach Brown Reviewed-by: Mark Fasheh --- kmod/src/filerw.c | 5 +++++ kmod/src/format.h | 5 +++++ kmod/src/inode.c | 31 ++++++++++++++++++++++++++++++- kmod/src/inode.h | 5 +++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/kmod/src/filerw.c b/kmod/src/filerw.c index 841b5a01..daa975df 100644 --- a/kmod/src/filerw.c +++ b/kmod/src/filerw.c @@ -615,6 +615,11 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping, scoutfs_ino(inode), PGA(page), (u64)pos, len, copied); ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); + if (ret > 0) { + scoutfs_inode_inc_data_version(inode); + /* XXX kind of a big hammer, inode life cycle needs work */ + scoutfs_update_inode_item(inode); + } scoutfs_release_trans(sb); return ret; } diff --git a/kmod/src/format.h b/kmod/src/format.h index 2b2b31b0..528b2e5d 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -200,6 +200,10 @@ struct scoutfs_timespec { } __packed; /* + * @data_version: incremented every time the contents of a file could + * have changed. It is exposed via an ioctl and is then provided as an + * argument to data functions to protect racing modification. + * * XXX * - otime? * - compat flags? @@ -211,6 +215,7 @@ struct scoutfs_inode { __le64 size; __le64 blocks; __le64 link_counter; + __le64 data_version; __le32 nlink; __le32 uid; __le32 gid; diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 81a18a85..aabb0910 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -120,9 +120,10 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode) inode->i_mtime.tv_nsec = le32_to_cpu(cinode->mtime.nsec); inode->i_ctime.tv_sec = le64_to_cpu(cinode->ctime.sec); inode->i_ctime.tv_nsec = le32_to_cpu(cinode->ctime.nsec); - + ci->salt = le32_to_cpu(cinode->salt); atomic64_set(&ci->link_counter, le64_to_cpu(cinode->link_counter)); + ci->data_version = le64_to_cpu(cinode->data_version); } static int scoutfs_read_locked_inode(struct inode *inode) @@ -148,6 +149,31 @@ static int scoutfs_read_locked_inode(struct inode *inode) return ret; } +void scoutfs_inode_inc_data_version(struct inode *inode) +{ + struct scoutfs_inode_info *si = SCOUTFS_I(inode); + + preempt_disable(); + write_seqcount_begin(&si->seqcount); + si->data_version++; + write_seqcount_end(&si->seqcount); + preempt_enable(); +} + +u64 scoutfs_inode_get_data_version(struct inode *inode) +{ + struct scoutfs_inode_info *si = SCOUTFS_I(inode); + unsigned int seq; + u64 vers; + + do { + seq = read_seqcount_begin(&si->seqcount); + vers = si->data_version; + } while (read_seqcount_retry(&si->seqcount, seq)); + + return vers; +} + static int scoutfs_iget_test(struct inode *inode, void *arg) { struct scoutfs_inode_info *ci = SCOUTFS_I(inode); @@ -210,6 +236,7 @@ static void store_inode(struct scoutfs_inode *cinode, struct inode *inode) cinode->salt = cpu_to_le32(ci->salt); cinode->link_counter = cpu_to_le64(atomic64_read(&ci->link_counter)); + cinode->data_version = cpu_to_le64(ci->data_version); } /* @@ -366,6 +393,8 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir, ci = SCOUTFS_I(inode); ci->ino = ino; + seqcount_init(&ci->seqcount); + ci->data_version = 0; get_random_bytes(&ci->salt, sizeof(ci->salt)); atomic64_set(&ci->link_counter, 0); diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 52ad52a6..1becde1d 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -5,6 +5,9 @@ struct scoutfs_inode_info { u64 ino; u32 salt; + seqcount_t seqcount; + u64 data_version; + atomic64_t link_counter; struct rw_semaphore xattr_rwsem; @@ -33,6 +36,8 @@ void scoutfs_dirty_inode(struct inode *inode, int flags); void scoutfs_update_inode_item(struct inode *inode); struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, dev_t rdev); +void scoutfs_inode_inc_data_version(struct inode *inode); +u64 scoutfs_inode_get_data_version(struct inode *inode); int scoutfs_scan_orphans(struct super_block *sb);