f2fs: atomic: fix to forbid dio in atomic_file
authorChao Yu <chao@kernel.org>
Fri, 16 Aug 2024 01:13:42 +0000 (09:13 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 21 Aug 2024 01:01:30 +0000 (01:01 +0000)
atomic write can only be used via buffered IO, let's fail direct IO on
atomic_file and return -EOPNOTSUPP.

Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/file.c

index 0bfcc1bf5832dbbfbe492ad4a9041096a267f11e..81d0b86c57188971f7220a56db1ca7b82e931d9f 100644 (file)
@@ -2162,6 +2162,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
                goto out;
 
        f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
+       f2fs_down_write(&fi->i_gc_rwsem[READ]);
 
        /*
         * Should wait end_io to count F2FS_WB_CP_DATA correctly by
@@ -2171,10 +2172,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
                f2fs_warn(sbi, "Unexpected flush for atomic writes: ino=%lu, npages=%u",
                          inode->i_ino, get_dirty_pages(inode));
        ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
-       if (ret) {
-               f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
-               goto out;
-       }
+       if (ret)
+               goto out_unlock;
 
        /* Check if the inode already has a COW inode */
        if (fi->cow_inode == NULL) {
@@ -2183,10 +2182,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
                struct inode *dir = d_inode(dentry->d_parent);
 
                ret = f2fs_get_tmpfile(idmap, dir, &fi->cow_inode);
-               if (ret) {
-                       f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
-                       goto out;
-               }
+               if (ret)
+                       goto out_unlock;
 
                set_inode_flag(fi->cow_inode, FI_COW_FILE);
                clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
@@ -2200,10 +2197,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
                invalidate_mapping_pages(fi->cow_inode->i_mapping, 0, -1);
 
                ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true);
-               if (ret) {
-                       f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
-                       goto out;
-               }
+               if (ret)
+                       goto out_unlock;
        }
 
        f2fs_write_inode(inode, NULL);
@@ -2222,7 +2217,11 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
        }
        f2fs_i_size_write(fi->cow_inode, isize);
 
+out_unlock:
+       f2fs_up_write(&fi->i_gc_rwsem[READ]);
        f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
+       if (ret)
+               goto out;
 
        f2fs_update_time(sbi, REQ_TIME);
        fi->atomic_write_task = current;
@@ -4570,6 +4569,13 @@ static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
                f2fs_down_read(&fi->i_gc_rwsem[READ]);
        }
 
+       /* dio is not compatible w/ atomic file */
+       if (f2fs_is_atomic_file(inode)) {
+               f2fs_up_read(&fi->i_gc_rwsem[READ]);
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
        /*
         * We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
         * the higher-level function iomap_dio_rw() in order to ensure that the
@@ -4985,6 +4991,12 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
        /* Determine whether we will do a direct write or a buffered write. */
        dio = f2fs_should_use_dio(inode, iocb, from);
 
+       /* dio is not compatible w/ atomic write */
+       if (dio && f2fs_is_atomic_file(inode)) {
+               ret = -EOPNOTSUPP;
+               goto out_unlock;
+       }
+
        /* Possibly preallocate the blocks for the write. */
        target_size = iocb->ki_pos + iov_iter_count(from);
        preallocated = f2fs_preallocate_blocks(iocb, from, dio);