[PATCH] squash: Allow phys change on any length file

From: Ira Weiny
Date: Fri Oct 25 2019 - 16:32:07 EST


delay the changing of the effective bit to when the inode is re-read
into the cache.

Currently a work in Progress because xfs seems to cache the inodes as
well and I'm not sure how to get xfs to release it's reference.
---
fs/xfs/xfs_ioctl.c | 18 +++++++-----------
include/linux/fs.h | 5 ++++-
2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 89cf47ef273e..4d730d5781d9 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1233,10 +1233,13 @@ xfs_diflags_to_linux(
inode->i_flags |= S_NOATIME;
else
inode->i_flags &= ~S_NOATIME;
- if (xflags & FS_XFLAG_DAX)
- inode->i_flags |= S_DAX;
- else
- inode->i_flags &= ~S_DAX;
+ /* NOTE: we do not allow the physical DAX flag to immediately change
+ * the effective IS_DAX() flag tell the VFS layer to remove the inode
+ * from the cache on the final iput() to force recreation on the next
+ * 'fresh' open */
+ if (((xflags & FS_XFLAG_DAX) && !IS_DAX(inode)) ||
+ (!(xflags & FS_XFLAG_DAX) && IS_DAX(inode)))
+ inode->i_flags |= S_REVALIDATE;
}

static int
@@ -1320,13 +1323,6 @@ xfs_ioctl_setattr_dax_invalidate(
/* lock, flush and invalidate mapping in preparation for flag change */
xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);

- /* File size must be zero to avoid races with asynchronous page
- * faults */
- if (i_size_read(inode) > 0) {
- error = -EINVAL;
- goto out_unlock;
- }
-
error = filemap_write_and_wait(inode->i_mapping);
if (error)
goto out_unlock;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0b4d8fc79e0f..4e9b7bf53c86 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1998,6 +1998,7 @@ struct super_operations {
#define S_ENCRYPTED 16384 /* Encrypted file (using fs/crypto/) */
#define S_CASEFOLD 32768 /* Casefolded file */
#define S_VERITY 65536 /* Verity file (using fs/verity/) */
+#define S_REVALIDATE 131072 /* Drop inode from cache on final put */

/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -2040,6 +2041,7 @@ static inline bool sb_rdonly(const struct super_block *sb) { return sb->s_flags
#define IS_ENCRYPTED(inode) ((inode)->i_flags & S_ENCRYPTED)
#define IS_CASEFOLDED(inode) ((inode)->i_flags & S_CASEFOLD)
#define IS_VERITY(inode) ((inode)->i_flags & S_VERITY)
+#define IS_REVALIDATE(inode) ((inode)->i_flags & S_REVALIDATE)

#define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \
(inode)->i_rdev == WHITEOUT_DEV)
@@ -3027,7 +3029,8 @@ extern int inode_needs_sync(struct inode *inode);
extern int generic_delete_inode(struct inode *inode);
static inline int generic_drop_inode(struct inode *inode)
{
- return !inode->i_nlink || inode_unhashed(inode);
+ return !inode->i_nlink || inode_unhashed(inode) ||
+ IS_REVALIDATE(inode);
}

extern struct inode *ilookup5_nowait(struct super_block *sb,
--
2.20.1