From: Omar Sandoval <osandov@xxxxxx> Encoded I/O in Btrfs needs to check a write with a given logical size without an iov_iter that matches that size (because the iov_iter we have is for the compressed data). So, factor out the parts of generic_write_check() that expect an iov_iter into a new __generic_write_checks() function and export that. Signed-off-by: Omar Sandoval <osandov@xxxxxx> --- fs/read_write.c | 40 ++++++++++++++++++++++------------------ include/linux/fs.h | 1 + 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index 0029ff2b0ca8..3bddd5ee7f64 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1633,6 +1633,26 @@ int generic_write_check_limits(struct file *file, loff_t pos, loff_t *count) return 0; } +/* Like generic_write_checks(), but takes size of write instead of iter. */ +int __generic_write_checks(struct kiocb *iocb, loff_t *count) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + + if (IS_SWAPFILE(inode)) + return -ETXTBSY; + + /* FIXME: this is for backwards compatibility with 2.4 */ + if (iocb->ki_flags & IOCB_APPEND) + iocb->ki_pos = i_size_read(inode); + + if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) + return -EINVAL; + + return generic_write_check_limits(iocb->ki_filp, iocb->ki_pos, count); +} +EXPORT_SYMBOL(__generic_write_checks); + /* * Performs necessary checks before doing a write * @@ -1642,26 +1662,10 @@ int generic_write_check_limits(struct file *file, loff_t pos, loff_t *count) */ ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) { - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - loff_t count; + loff_t count = iov_iter_count(from); int ret; - if (IS_SWAPFILE(inode)) - return -ETXTBSY; - - if (!iov_iter_count(from)) - return 0; - - /* FIXME: this is for backwards compatibility with 2.4 */ - if (iocb->ki_flags & IOCB_APPEND) - iocb->ki_pos = i_size_read(inode); - - if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) - return -EINVAL; - - count = iov_iter_count(from); - ret = generic_write_check_limits(file, iocb->ki_pos, &count); + ret = __generic_write_checks(iocb, &count); if (ret) return ret; diff --git a/include/linux/fs.h b/include/linux/fs.h index 0de4d75339b9..b206814da181 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3227,6 +3227,7 @@ extern int sb_min_blocksize(struct super_block *, int); extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *); extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *); +extern int __generic_write_checks(struct kiocb *iocb, loff_t *count); extern int generic_write_check_limits(struct file *file, loff_t pos, loff_t *count); extern int generic_file_rw_checks(struct file *file_in, struct file *file_out); -- 2.32.0