@@ -2193,7 +2193,8 @@ EXPORT_SYMBOL(current_time);
/*
* Generic function to check FS_IOC_SETFLAGS values and reject any invalid
- * configurations.
+ * configurations. Once we're done, prepare the inode for whatever changes
+ * are coming down the pipeline.
*
* Note: the caller should be holding i_mutex, or else be sure that they have
* exclusive access to the inode structure.
@@ -2201,6 +2202,8 @@ EXPORT_SYMBOL(current_time);
int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
unsigned int flags)
{
+ int ret;
+
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
* the relevant capability.
@@ -2211,7 +2214,21 @@ int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
- return 0;
+ /*
+ * Now that we're done checking the new flags, flush all pending IO and
+ * dirty mappings before setting S_IMMUTABLE on an inode via
+ * FS_IOC_SETFLAGS. If the flush fails we'll clear the flag before
+ * returning error.
+ */
+ if (!S_ISREG(inode->i_mode) || IS_IMMUTABLE(inode) ||
+ !(flags & FS_IMMUTABLE_FL))
+ return 0;
+
+ inode_set_flags(inode, S_IMMUTABLE, S_IMMUTABLE);
+ ret = inode_drain_writes(inode);
+ if (ret)
+ inode_set_flags(inode, 0, S_IMMUTABLE);
+ return ret;
}
EXPORT_SYMBOL(vfs_ioc_setflags_prepare);
@@ -3561,4 +3561,15 @@ int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags,
int vfs_ioc_fssetxattr_check(struct inode *inode, const struct fsxattr *old_fa,
struct fsxattr *fa);
+/*
+ * Flush file data before changing attributes. Caller must hold any locks
+ * required to prevent further writes to this file until we're done setting
+ * flags.
+ */
+static inline int inode_drain_writes(struct inode *inode)
+{
+ inode_dio_wait(inode);
+ return filemap_write_and_wait(inode->i_mapping);
+}
+
#endif /* _LINUX_FS_H */