UPSTREAM: f2fs: atomic: fix to forbid dio in atomic_file

atomic write can only be used via buffered IO, let's fail direct IO on
atomic_file and return -EOPNOTSUPP.

Change-Id: I6a0eadcc968ba1001a155784fc074adde6eb37f4
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
(cherry picked from commit b2c160f4f3)
This commit is contained in:
Chao Yu 2024-08-16 09:13:42 +08:00 committed by Matthias Männich
parent ba0bda6226
commit c77db905d4

View File

@ -2169,6 +2169,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
goto out; goto out;
f2fs_down_write(&fi->i_gc_rwsem[WRITE]); 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 * Should wait end_io to count F2FS_WB_CP_DATA correctly by
@ -2178,10 +2179,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", f2fs_warn(sbi, "Unexpected flush for atomic writes: ino=%lu, npages=%u",
inode->i_ino, get_dirty_pages(inode)); inode->i_ino, get_dirty_pages(inode));
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
if (ret) { if (ret)
f2fs_up_write(&fi->i_gc_rwsem[WRITE]); goto out_unlock;
goto out;
}
/* Check if the inode already has a COW inode */ /* Check if the inode already has a COW inode */
if (fi->cow_inode == NULL) { if (fi->cow_inode == NULL) {
@ -2190,10 +2189,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
struct inode *dir = d_inode(dentry->d_parent); struct inode *dir = d_inode(dentry->d_parent);
ret = f2fs_get_tmpfile(idmap, dir, &fi->cow_inode); ret = f2fs_get_tmpfile(idmap, dir, &fi->cow_inode);
if (ret) { if (ret)
f2fs_up_write(&fi->i_gc_rwsem[WRITE]); goto out_unlock;
goto out;
}
set_inode_flag(fi->cow_inode, FI_COW_FILE); set_inode_flag(fi->cow_inode, FI_COW_FILE);
clear_inode_flag(fi->cow_inode, FI_INLINE_DATA); clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
@ -2207,10 +2204,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
invalidate_mapping_pages(fi->cow_inode->i_mapping, 0, -1); invalidate_mapping_pages(fi->cow_inode->i_mapping, 0, -1);
ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true); ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true);
if (ret) { if (ret)
f2fs_up_write(&fi->i_gc_rwsem[WRITE]); goto out_unlock;
goto out;
}
} }
f2fs_write_inode(inode, NULL); f2fs_write_inode(inode, NULL);
@ -2229,7 +2224,11 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
} }
f2fs_i_size_write(fi->cow_inode, isize); 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]); f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
if (ret)
goto out;
f2fs_update_time(sbi, REQ_TIME); f2fs_update_time(sbi, REQ_TIME);
fi->atomic_write_task = current; fi->atomic_write_task = current;
@ -4577,6 +4576,13 @@ static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
f2fs_down_read(&fi->i_gc_rwsem[READ]); 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 * 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 * the higher-level function iomap_dio_rw() in order to ensure that the
@ -4992,6 +4998,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. */ /* Determine whether we will do a direct write or a buffered write. */
dio = f2fs_should_use_dio(inode, iocb, from); 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. */ /* Possibly preallocate the blocks for the write. */
target_size = iocb->ki_pos + iov_iter_count(from); target_size = iocb->ki_pos + iov_iter_count(from);
preallocated = f2fs_preallocate_blocks(iocb, from, dio); preallocated = f2fs_preallocate_blocks(iocb, from, dio);