]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
fs/ext4: Introduce DAX inode flag
authorIra Weiny <ira.weiny@intel.com>
Thu, 28 May 2020 15:00:02 +0000 (08:00 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 29 May 2020 02:09:47 +0000 (22:09 -0400)
Add a flag ([EXT4|FS]_DAX_FL) to preserve FS_XFLAG_DAX in the ext4
inode.

Set the flag to be user visible and changeable.  Set the flag to be
inherited.  Allow applications to change the flag at any time except if
it conflicts with the set of mutually exclusive flags (Currently VERITY,
ENCRYPT, JOURNAL_DATA).

Furthermore, restrict setting any of the exclusive flags if DAX is set.

While conceptually possible, we do not allow setting EXT4_DAX_FL while
at the same time clearing exclusion flags (or vice versa) for 2 reasons:

1) The DAX flag does not take effect immediately which
   introduces quite a bit of complexity
2) There is no clear use case for being this flexible

Finally, on regular files, flag the inode to not be cached to facilitate
changing S_DAX on the next creation of the inode.

Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Link: https://lore.kernel.org/r/20200528150003.828793-9-ira.weiny@intel.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/super.c
fs/ext4/verity.c
include/uapi/linux/fs.h

index 65ffb831b2b9b966c075f93995483bac49d2d1bd..598e00a9453fc7d2b0d1a628cae820f3ec48b21a 100644 (file)
@@ -415,13 +415,16 @@ struct flex_groups {
 #define EXT4_VERITY_FL                 0x00100000 /* Verity protected inode */
 #define EXT4_EA_INODE_FL               0x00200000 /* Inode used for large EA */
 /* 0x00400000 was formerly EXT4_EOFBLOCKS_FL */
+
+#define EXT4_DAX_FL                    0x02000000 /* Inode is DAX */
+
 #define EXT4_INLINE_DATA_FL            0x10000000 /* Inode has inline data. */
 #define EXT4_PROJINHERIT_FL            0x20000000 /* Create with parents projid */
 #define EXT4_CASEFOLD_FL               0x40000000 /* Casefolded file */
 #define EXT4_RESERVED_FL               0x80000000 /* reserved for ext4 lib */
 
-#define EXT4_FL_USER_VISIBLE           0x705BDFFF /* User visible flags */
-#define EXT4_FL_USER_MODIFIABLE                0x604BC0FF /* User modifiable flags */
+#define EXT4_FL_USER_VISIBLE           0x725BDFFF /* User visible flags */
+#define EXT4_FL_USER_MODIFIABLE                0x624BC0FF /* User modifiable flags */
 
 /* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */
 #define EXT4_FL_XFLAG_VISIBLE          (EXT4_SYNC_FL | \
@@ -429,14 +432,16 @@ struct flex_groups {
                                         EXT4_APPEND_FL | \
                                         EXT4_NODUMP_FL | \
                                         EXT4_NOATIME_FL | \
-                                        EXT4_PROJINHERIT_FL)
+                                        EXT4_PROJINHERIT_FL | \
+                                        EXT4_DAX_FL)
 
 /* Flags that should be inherited by new inodes from their parent. */
 #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
                           EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
                           EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
                           EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\
-                          EXT4_PROJINHERIT_FL | EXT4_CASEFOLD_FL)
+                          EXT4_PROJINHERIT_FL | EXT4_CASEFOLD_FL |\
+                          EXT4_DAX_FL)
 
 /* Flags that are appropriate for regular files (all but dir-specific ones). */
 #define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL | EXT4_CASEFOLD_FL |\
@@ -448,6 +453,10 @@ struct flex_groups {
 /* The only flags that should be swapped */
 #define EXT4_FL_SHOULD_SWAP (EXT4_HUGE_FILE_FL | EXT4_EXTENTS_FL)
 
+/* Flags which are mutually exclusive to DAX */
+#define EXT4_DAX_MUT_EXCL (EXT4_VERITY_FL | EXT4_ENCRYPT_FL |\
+                          EXT4_JOURNAL_DATA_FL)
+
 /* Mask out flags that are inappropriate for the given type of inode. */
 static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags)
 {
@@ -488,6 +497,7 @@ enum {
        EXT4_INODE_VERITY       = 20,   /* Verity protected inode */
        EXT4_INODE_EA_INODE     = 21,   /* Inode used for large EA */
 /* 22 was formerly EXT4_INODE_EOFBLOCKS */
+       EXT4_INODE_DAX          = 25,   /* Inode is DAX */
        EXT4_INODE_INLINE_DATA  = 28,   /* Data in inode. */
        EXT4_INODE_PROJINHERIT  = 29,   /* Create with parents projid */
        EXT4_INODE_RESERVED     = 31,   /* reserved for ext4 lib */
index 68fac9289109dac25ba99c80c2f9e033cd3e2516..778b0dbe3da64752e3775c670ad7616a2e60e4eb 100644 (file)
@@ -4419,7 +4419,7 @@ static bool ext4_should_enable_dax(struct inode *inode)
        if (test_opt(inode->i_sb, DAX_ALWAYS))
                return true;
 
-       return false;
+       return ext4_test_inode_flag(inode, EXT4_INODE_DAX);
 }
 
 void ext4_set_inode_flags(struct inode *inode, bool init)
index 779631e8e84935973cb8e188f3ed0c3e606d2d7c..1b520d07d37142f188cc3197d7330e89ef29a9ae 100644 (file)
@@ -292,6 +292,38 @@ static int ext4_ioctl_check_immutable(struct inode *inode, __u32 new_projid,
        return 0;
 }
 
+static void ext4_dax_dontcache(struct inode *inode, unsigned int flags)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+
+       if (S_ISDIR(inode->i_mode))
+               return;
+
+       if (test_opt2(inode->i_sb, DAX_NEVER) ||
+           test_opt(inode->i_sb, DAX_ALWAYS))
+               return;
+
+       if ((ei->i_flags ^ flags) & EXT4_DAX_FL)
+               d_mark_dontcache(inode);
+}
+
+static bool dax_compatible(struct inode *inode, unsigned int oldflags,
+                          unsigned int flags)
+{
+       if (flags & EXT4_DAX_FL) {
+               if ((oldflags & EXT4_DAX_MUT_EXCL) ||
+                    ext4_test_inode_state(inode,
+                                         EXT4_STATE_VERITY_IN_PROGRESS)) {
+                       return false;
+               }
+       }
+
+       if ((flags & EXT4_DAX_MUT_EXCL) && (oldflags & EXT4_DAX_FL))
+                       return false;
+
+       return true;
+}
+
 static int ext4_ioctl_setflags(struct inode *inode,
                               unsigned int flags)
 {
@@ -320,6 +352,12 @@ static int ext4_ioctl_setflags(struct inode *inode,
                if (!capable(CAP_SYS_RESOURCE))
                        goto flags_out;
        }
+
+       if (!dax_compatible(inode, oldflags, flags)) {
+               err = -EOPNOTSUPP;
+               goto flags_out;
+       }
+
        if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
                migrate = 1;
 
@@ -365,6 +403,8 @@ static int ext4_ioctl_setflags(struct inode *inode,
        if (err)
                goto flags_err;
 
+       ext4_dax_dontcache(inode, flags);
+
        for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
                if (!(mask & EXT4_FL_USER_MODIFIABLE))
                        continue;
@@ -525,12 +565,15 @@ static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
                xflags |= FS_XFLAG_NOATIME;
        if (iflags & EXT4_PROJINHERIT_FL)
                xflags |= FS_XFLAG_PROJINHERIT;
+       if (iflags & EXT4_DAX_FL)
+               xflags |= FS_XFLAG_DAX;
        return xflags;
 }
 
 #define EXT4_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \
                                  FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
-                                 FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT)
+                                 FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT | \
+                                 FS_XFLAG_DAX)
 
 /* Transfer xflags flags to internal */
 static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
@@ -549,6 +592,8 @@ static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
                iflags |= EXT4_NOATIME_FL;
        if (xflags & FS_XFLAG_PROJINHERIT)
                iflags |= EXT4_PROJINHERIT_FL;
+       if (xflags & FS_XFLAG_DAX)
+               iflags |= EXT4_DAX_FL;
 
        return iflags;
 }
index 5e056aa20ce97a76f3a7b98b23f8d1071285c498..3658e301699999863e976d76f005d156191f1eda 100644 (file)
@@ -1323,6 +1323,9 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
        if (WARN_ON_ONCE(IS_DAX(inode) && i_size_read(inode)))
                return -EINVAL;
 
+       if (ext4_test_inode_flag(inode, EXT4_INODE_DAX))
+               return -EOPNOTSUPP;
+
        res = ext4_convert_inline_data(inode);
        if (res)
                return res;
index 89a155ece3236b4c79dde9e6f8b6aa98a742e7c9..4fecb3e4e33882a8376e828bde72a761e1b480fa 100644 (file)
@@ -113,7 +113,7 @@ static int ext4_begin_enable_verity(struct file *filp)
        handle_t *handle;
        int err;
 
-       if (IS_DAX(inode))
+       if (IS_DAX(inode) || ext4_test_inode_flag(inode, EXT4_INODE_DAX))
                return -EINVAL;
 
        if (ext4_verity_in_progress(inode))
index 379a612f8f1d9f45d1703bc55a67fa677862b8d0..f44eb0a04afdd8cea369af1395c3637a5f69122d 100644 (file)
@@ -262,6 +262,7 @@ struct fsxattr {
 #define FS_EA_INODE_FL                 0x00200000 /* Inode used for large EA */
 #define FS_EOFBLOCKS_FL                        0x00400000 /* Reserved for ext4 */
 #define FS_NOCOW_FL                    0x00800000 /* Do not cow file */
+#define FS_DAX_FL                      0x02000000 /* Inode is DAX */
 #define FS_INLINE_DATA_FL              0x10000000 /* Reserved for ext4 */
 #define FS_PROJINHERIT_FL              0x20000000 /* Create with parents projid */
 #define FS_CASEFOLD_FL                 0x40000000 /* Folder is case insensitive */