diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig index 9de04c37e11a..4b10d78ed99b 100644 --- a/fs/btrfs/Kconfig +++ b/fs/btrfs/Kconfig @@ -106,7 +106,8 @@ config BTRFS_EXPERIMENTAL - extent tree v2 - complex rework of extent tracking - - block size > page size support + - block size > page size support - needs transparent huge page and + non-HIGHMEM system - huge folios for data - folios can be as large as 2MiB now diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 22c321719e4f..50228c2e66c0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3468,7 +3468,15 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device fs_info->sectorsize = sectorsize; fs_info->sectorsize_bits = ilog2(sectorsize); fs_info->block_min_order = ilog2(round_up(sectorsize, PAGE_SIZE) >> PAGE_SHIFT); - fs_info->block_max_order = calc_block_max_order(fs_info->sectorsize_bits); + /* + * For HIGHMEM, a large folio cannot be mapped in one go, breaking a lot + * of basic assumptions for btrfs IOs. + * Disable large folios for such 32-bit systems. + */ + if (IS_ENABLED(CONFIG_HIGHMEM)) + fs_info->block_max_order = fs_info->block_min_order; + else + fs_info->block_max_order = calc_block_max_order(fs_info->sectorsize_bits); fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size; fs_info->stripesize = stripesize; fs_info->fs_devices->fs_info = fs_info; diff --git a/fs/btrfs/fs.c b/fs/btrfs/fs.c index 14d83565cdee..dcf12979af33 100644 --- a/fs/btrfs/fs.c +++ b/fs/btrfs/fs.c @@ -166,9 +166,17 @@ bool __attribute_const__ btrfs_supported_blocksize(u32 blocksize) * * Considering HIGHMEM is such a pain to deal with and it's going * to be deprecated eventually, just reject HIGHMEM && bs > ps cases. + * + * Finally, for bs > ps cases, we need to set the minimal folio order, + * which requires transparent hugepage. */ - if (IS_ENABLED(CONFIG_HIGHMEM) && blocksize > PAGE_SIZE) - return false; + if (blocksize > PAGE_SIZE) { + if (IS_ENABLED(CONFIG_HIGHMEM)) + return false; + + if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) + return false; + } return true; #endif return false; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b446c3014b24..d7b5a05fae00 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3938,10 +3938,11 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path btrfs_inode_split_flags(btrfs_inode_flags(leaf, inode_item), &inode->flags, &inode->ro_flags); + +cache_index: btrfs_update_inode_mapping_flags(inode); btrfs_set_inode_mapping_order(inode); -cache_index: /* * If we were modified in the current generation and evicted from memory * and then re-read we need to do a full sync since we don't have any @@ -9954,6 +9955,7 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from, if (cb) cleanup_compressed_bio(cb); out: + extent_changeset_free(data_reserved); if (ret >= 0) iocb->ki_pos += encoded->len; return ret; diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c index 1531adb117d1..2f0996692da0 100644 --- a/fs/btrfs/lzo.c +++ b/fs/btrfs/lzo.c @@ -552,9 +552,10 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in, size_t max_segment_len = workspace_buf_length(fs_info); int ret; - if (unlikely(srclen < LZO_LEN || srclen > max_segment_len + LZO_LEN * 2)) { + if (unlikely(srclen <= LZO_LEN * 2 || + srclen > max_segment_len + LZO_LEN * 2)) { btrfs_err(fs_info, "invalid lzo header length, has %zu expect (%u, %zu)", - srclen, LZO_LEN, max_segment_len + LZO_LEN * 2); + srclen, LZO_LEN * 2, max_segment_len + LZO_LEN * 2); return -EUCLEAN; }