EXT4 supports bigalloc feature which allows the FS to work in size of
clusters (group of blocks) rather than individual blocks. This patch
adds atomic write support for bigalloc so that systems with bs = ps can
create FS using -
mkfs.ext4 -F -O bigalloc -b 4096 -C 16384 <dev>
EXT4 can then adjust it's atomic write unit max value to cluster size.
This can then support atomic write of size anywhere between
[blocksize, clustersize].
Note: bigalloc can support writes of the pattern [0 16k] followed by [0 8k].
However, if there is a write pattern detected of type [0 8k] followed by
[0 16k], then we return an error (-EINVAL). It is ok to return an error here
to avoid splitting of atomic write request. This is ok because anyways
atomic write requests has many constraints to follow for e.g. writes of
form which does not follow natural alignment [4k, 12k] ([start, end]) can
also return -EINVAL (check generic_atomic_write_valid()).
Hence the current patch adds the base support needed to support
atomic writes with bigalloc. This is helpful for systems with 4k
pagesize to support atomic writes.
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
fs/ext4/inode.c | 13 +++++++++++++
fs/ext4/super.c | 9 +++++++--
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 897c028d5bc9..2dee8514d2f8 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3423,6 +3423,19 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
*/
map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len);
+ /*
+ * [0 16k] followed by [0 8k] can work with bigalloc. However,
+ * For now we don't support atomic writes of the pattern
+ * [0 8k] followed by [0 16k] in case of bigalloc. This is because it
+ * can cause the atomic writes to split in the iomap layer.
+ * Atomic writes anyways has many constraints, so as a base support to
+ * enable atomic writes using bigalloc, it is ok to return an error for
+ * an unsupported write request.
+ */
+ if (flags & IOMAP_ATOMIC) {
+ if (map.m_len < (length >> blkbits))
+ return -EINVAL;
+ }
ext4_set_iomap(inode, iomap, &map, offset, length, flags);
return 0;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index f5c075aff060..eba16989ce36 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4428,12 +4428,14 @@ static int ext4_handle_clustersize(struct super_block *sb)
/*
* ext4_atomic_write_init: Initializes filesystem min & max atomic write units.
* @sb: super block
- * TODO: Later add support for bigalloc
*/
static void ext4_atomic_write_init(struct super_block *sb)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct block_device *bdev = sb->s_bdev;
+ unsigned int blkbits = sb->s_blocksize_bits;
+ unsigned int clustersize = sb->s_blocksize;
+
if (!bdev_can_atomic_write(bdev))
return;
@@ -4441,9 +4443,12 @@ static void ext4_atomic_write_init(struct super_block *sb)
if (!ext4_has_feature_extents(sb))
return;
+ if (ext4_has_feature_bigalloc(sb))
+ clustersize = 1U << (sbi->s_cluster_bits + blkbits);
+
sbi->fs_awu_min = max(sb->s_blocksize,
bdev_atomic_write_unit_min_bytes(bdev));
- sbi->fs_awu_max = min(sb->s_blocksize,
+ sbi->fs_awu_max = min(clustersize,
bdev_atomic_write_unit_max_bytes(bdev));
if (sbi->fs_awu_min && sbi->fs_awu_max &&
sbi->fs_awu_min <= sbi->fs_awu_max) {
--
2.46.0