This patch adds ext4 specific checks for supporting atomic writes using fsawu (filesystem atomic write unit). We can enable this support with either - 1. bigalloc on a 4k pagesize system or 2. bs < ps system with -b <BS> 3. filesystems with LBS (large block size) support (future) Let's use generic_atomic_write_valid() helper for alignment restrictions checking. Co-developed-by: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx> Signed-off-by: Ojaswin Mujoo <ojaswin@xxxxxxxxxxxxx> Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@xxxxxxxxx> --- fs/ext4/file.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 54d6ff22585c..8e309a9a0bd6 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -400,6 +400,21 @@ static const struct iomap_dio_ops ext4_dio_write_ops = { .end_io = ext4_dio_write_end_io, }; +static bool ext4_dio_atomic_write_checks(struct kiocb *iocb, + struct iov_iter *from) +{ + struct super_block *sb = file_inode(iocb->ki_filp)->i_sb; + loff_t pos = iocb->ki_pos; + unsigned int fsawu_min, fsawu_max; + + if (!ext4_can_atomic_write_fsawu(sb)) + return false; + + ext4_atomic_write_fsawu(sb, &fsawu_min, &fsawu_max); + + return generic_atomic_write_valid(pos, from, fsawu_min, fsawu_max); +} + /* * The intention here is to start with shared lock acquired then see if any * condition requires an exclusive inode lock. If yes, then we restart the @@ -427,13 +442,19 @@ static ssize_t ext4_dio_write_checks(struct kiocb *iocb, struct iov_iter *from, loff_t offset; size_t count; ssize_t ret; - bool overwrite, unaligned_io; + bool overwrite, unaligned_io, atomic_write; restart: ret = ext4_generic_write_checks(iocb, from); if (ret <= 0) goto out; + atomic_write = iocb->ki_flags & IOCB_ATOMIC; + if (atomic_write && !ext4_dio_atomic_write_checks(iocb, from)) { + ret = -EINVAL; + goto out; + } + offset = iocb->ki_pos; count = ret; @@ -576,8 +597,15 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) iomap_ops = &ext4_iomap_overwrite_ops; ret = iomap_dio_rw(iocb, from, iomap_ops, &ext4_dio_write_ops, dio_flags, NULL, 0); - if (ret == -ENOTBLK) - ret = 0; + + /* Fallback to buffered-io for non-atomic DIO */ + if (ret == -ENOTBLK) { + if (iocb->ki_flags & IOCB_ATOMIC) + ret = -EIO; + else + ret = 0; + } + if (extend) { /* * We always perform extending DIO write synchronously so by -- 2.43.0