]> Gentwo Git Trees - linux/.git/commitdiff
ext4: add checks for large folio incompatibilities when BS > PS
authorBaokun Li <libaokun1@huawei.com>
Fri, 21 Nov 2025 09:06:53 +0000 (17:06 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 29 Nov 2025 03:35:28 +0000 (22:35 -0500)
Supporting a block size greater than the page size (BS > PS) requires
support for large folios. However, several features (e.g., encrypt)
do not yet support large folios.

To prevent conflicts, this patch adds checks at mount time to prohibit
these features from being used when BS > PS. Since these features cannot
be changed on remount, there is no need to check on remount.

This patch adds s_max_folio_order, initialized during mount according to
filesystem features and mount options. If s_max_folio_order is 0, large
folios are disabled.

With this in place, ext4_set_inode_mapping_order() can be simplified by
checking s_max_folio_order, avoiding redundant checks.

Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Message-ID: <20251121090654.631996-24-libaokun@huaweicloud.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/super.c

index 5ade4e22dcfff35ac77e8fc76be2d48c213c5cd2..56112f201cace7dc3f0709f25fb8fb8980983e0f 100644 (file)
@@ -1705,7 +1705,9 @@ struct ext4_sb_info {
        unsigned long s_last_trim_minblks;
 
        /* minimum folio order of a page cache allocation */
-       unsigned int s_min_folio_order;
+       u16 s_min_folio_order;
+       /* supported maximum folio order, 0 means not supported */
+       u16 s_max_folio_order;
 
        /* Precomputed FS UUID checksum for seeding other checksums */
        __u32 s_csum_seed;
index a566469ae07a5af8721c7dfe97a9963e1cd06e49..7510fce3d0f0d029c8cb76ec55b3b709319b79d9 100644 (file)
@@ -5148,41 +5148,23 @@ static int check_igot_inode(struct inode *inode, ext4_iget_flags flags,
        return -EFSCORRUPTED;
 }
 
-static bool ext4_should_enable_large_folio(struct inode *inode)
+void ext4_set_inode_mapping_order(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
+       u16 min_order, max_order;
 
-       if (!S_ISREG(inode->i_mode))
-               return false;
-       if (ext4_has_feature_encrypt(sb))
-               return false;
-
-       return true;
-}
-
-/*
- * Limit the maximum folio order to 2048 blocks to prevent overestimation
- * of reserve handle credits during the folio writeback in environments
- * where the PAGE_SIZE exceeds 4KB.
- */
-#define EXT4_MAX_PAGECACHE_ORDER(i)            \
-               umin(MAX_PAGECACHE_ORDER, (11 + (i)->i_blkbits - PAGE_SHIFT))
-void ext4_set_inode_mapping_order(struct inode *inode)
-{
-       u32 max_order;
+       max_order = EXT4_SB(sb)->s_max_folio_order;
+       if (!max_order)
+               return;
 
-       if (!ext4_should_enable_large_folio(inode))
+       min_order = EXT4_SB(sb)->s_min_folio_order;
+       if (!min_order && !S_ISREG(inode->i_mode))
                return;
 
-       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
-           ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
-               max_order = EXT4_SB(inode->i_sb)->s_min_folio_order;
-       else
-               max_order = EXT4_MAX_PAGECACHE_ORDER(inode);
+       if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA))
+               max_order = min_order;
 
-       mapping_set_folio_order_range(inode->i_mapping,
-                                     EXT4_SB(inode->i_sb)->s_min_folio_order,
-                                     max_order);
+       mapping_set_folio_order_range(inode->i_mapping, min_order, max_order);
 }
 
 struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
index 998ddce49093138aaaf87a34f4eb62c1eb3ebec5..3d03a6eb0ea0c50cf5f6e0a7342b4d5350004811 100644 (file)
@@ -5042,6 +5042,41 @@ static const char *ext4_has_journal_option(struct super_block *sb)
        return NULL;
 }
 
+/*
+ * Limit the maximum folio order to 2048 blocks to prevent overestimation
+ * of reserve handle credits during the folio writeback in environments
+ * where the PAGE_SIZE exceeds 4KB.
+ */
+#define EXT4_MAX_PAGECACHE_ORDER(sb)           \
+               umin(MAX_PAGECACHE_ORDER, (11 + (sb)->s_blocksize_bits - PAGE_SHIFT))
+static void ext4_set_max_mapping_order(struct super_block *sb)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+               sbi->s_max_folio_order = sbi->s_min_folio_order;
+       else
+               sbi->s_max_folio_order = EXT4_MAX_PAGECACHE_ORDER(sb);
+}
+
+static int ext4_check_large_folio(struct super_block *sb)
+{
+       const char *err_str = NULL;
+
+       if (ext4_has_feature_encrypt(sb))
+               err_str = "encrypt";
+
+       if (!err_str) {
+               ext4_set_max_mapping_order(sb);
+       } else if (sb->s_blocksize > PAGE_SIZE) {
+               ext4_msg(sb, KERN_ERR, "bs(%lu) > ps(%lu) unsupported for %s",
+                        sb->s_blocksize, PAGE_SIZE, err_str);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int ext4_load_super(struct super_block *sb, ext4_fsblk_t *lsb,
                           int silent)
 {
@@ -5318,6 +5353,10 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
 
        ext4_apply_options(fc, sb);
 
+       err = ext4_check_large_folio(sb);
+       if (err < 0)
+               goto failed_mount;
+
        err = ext4_encoding_init(sb, es);
        if (err)
                goto failed_mount;