[Devel] [PATCH RHEL7 COMMIT] kill generic_segment_checks()
Konstantin Khorenko
khorenko at virtuozzo.com
Mon May 25 17:52:06 MSK 2020
The commit is pushed to "branch-rh7-3.10.0-1127.8.2.vz7.161.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.8.2.vz7.161.1
------>
commit 03c3d1b894985bd7bec46537107127210e4377a5
Author: Al Viro <viro at zeniv.linux.org.uk>
Date: Mon May 25 17:52:05 2020 +0300
kill generic_segment_checks()
ms commit cb66a7a1f149
all callers of ->aio_read() and ->aio_write() have iov/nr_segs already
checked - generic_segment_checks() done after that is just an odd way
to spell iov_length().
Signed-off-by: Al Viro <viro at zeniv.linux.org.uk>
1)generic_segment_checks() is called from ->aio_read() and ->aio_write()
callbacks;
2)in all callers of ->aio_read() and ->aio_write() we check
for user iovec via access_ok() and overflows.
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
=====================
Patchset description:
[00/30] fs,direct_IO: Switch to iov_iter and allow bio_vec for ext4
This patchset transforms direct_IO callbacks, blockdev_direct_IO
and its underlining functions to iov_iter, and introduces complete
support of iov_iter for ext4.
Supported iov_iter subtypes for ext4 is iovec and bio_vec. The first
is for traditional user-submitted aio, while bio_vec is the type,
which is important for us, since we use it in ploop.
bio_vec operates with pages instead of user addresses (like iovec
does), so it requires specific callbacks in do_blockdev_direct_IO()
and in the functions it calls.
The patchset reworks do_blockdev_direct_IO() in the same manner
as in mainstrean. The most of rest patches are prepared manually,
since we have significant differences to ms (RHEL7 patches, our
direct IO patches for FUSE; all they have changed many functions).
At the end, kaio engine (resulting in direct_IO) became possible
to be enabled for ext4.
https://jira.sw.ru/browse/PSBM-99793
---
fs/btrfs/file.c | 7 +------
fs/ceph/file.c | 13 +++---------
fs/ext4/file.c | 12 ++---------
fs/fuse/file.c | 7 +------
fs/gfs2/file.c | 5 +----
fs/ntfs/file.c | 5 +----
fs/ocfs2/file.c | 7 +------
fs/xfs/xfs_file.c | 20 ++++--------------
include/linux/fs.h | 2 --
mm/filemap.c | 59 +++---------------------------------------------------
mm/shmem.c | 7 +------
11 files changed, 18 insertions(+), 126 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 44daeffd851e4..e14f2e5920289 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1821,12 +1821,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
mutex_lock(&inode->i_mutex);
- err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
- if (err) {
- mutex_unlock(&inode->i_mutex);
- goto out;
- }
- count = ocount;
+ count = ocount = iov_length(iov, nr_segs);
current->backing_dev_info = inode->i_mapping->backing_dev_info;
err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 829f3261ef00b..4302940a8a6cb 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -1296,12 +1296,8 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len,
ceph_cap_string(got));
- if (!read) {
- ret = generic_segment_checks(iov, &nr_segs,
- &len, VERIFY_WRITE);
- if (ret)
- goto out;
- }
+ if (!read)
+ len = iov_length(iov, nr_segs);
iov_iter_init(&i, iov, nr_segs, len, read);
@@ -1336,7 +1332,6 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
ceph_del_rw_context(fi, &rw_ctx);
}
-out:
dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
if (pinned_page) {
@@ -1426,9 +1421,7 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
retry_snap:
mutex_lock(&inode->i_mutex);
- err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
- if (err)
- goto out;
+ count = iov_length(iov, nr_segs);
/* We can write back this queue in page reclaim */
current->backing_dev_info = file->f_mapping->backing_dev_info;
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 970cfe6794e89..fefcbb809bf37 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -221,12 +221,9 @@ ext4_file_dax_write(
{
struct inode *inode = file_inode(iocb->ki_filp);
ssize_t ret;
- size_t size = 0;
+ size_t size = iov_length(iovp, nr_segs);
inode_lock(inode);
- ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
- if (ret < 0)
- return ret;
ret = ext4_write_checks(iocb, iovp, nr_segs, &pos);
if (ret < 0)
goto out;
@@ -514,14 +511,9 @@ ext4_file_dax_read(
unsigned long nr_segs,
loff_t pos)
{
- size_t size = 0;
+ size_t size = iov_length(iovp, nr_segs);
ssize_t ret = 0;
struct inode *inode = file_inode(iocb->ki_filp);
-
- ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
- if (ret < 0)
- return ret;
-
if (!size)
return 0; /* skip atime */
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 973f1513868a5..258bd78a559c6 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1571,12 +1571,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
WARN_ON(iocb->ki_pos != pos);
- ocount = 0;
- err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
- if (err)
- return err;
-
- count = ocount;
+ count = ocount = iov_length(iov, nr_segs);
mutex_lock(&inode->i_mutex);
/* We can write back this queue in page reclaim */
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 53a11f484fb48..553ef0bddc029 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -734,10 +734,7 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
if (io_is_direct(file))
return generic_file_aio_write(iocb, iov, nr_segs, pos);
- ocount = 0;
- ret = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
- if (ret)
- return ret;
+ ocount = iov_length(iov, nr_segs);
count = ocount;
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 81adff3fd8651..fb72ec6e1a645 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2091,10 +2091,7 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb,
size_t count; /* after file limit checks */
ssize_t written, err;
- count = 0;
- err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
- if (err)
- return err;
+ count = iov_length(iov, nr_segs);
pos = *ppos;
/* We can write back this queue in page reclaim. */
current->backing_dev_info = mapping->backing_dev_info;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 60ea07def7e2f..dfa86a02e160f 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -2344,12 +2344,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
/* communicate with ocfs2_dio_end_io */
ocfs2_iocb_set_rw_locked(iocb, rw_level);
- ret = generic_segment_checks(iov, &nr_segs, &ocount,
- VERIFY_READ);
- if (ret)
- goto out_dio;
-
- count = ocount;
+ count = ocount = iov_length(iov, nr_segs);
ret = generic_write_checks(file, ppos, &count,
S_ISBLK(inode->i_mode));
if (ret)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 0fe09671c6b8b..5fb17574f0ce0 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -255,10 +255,7 @@ xfs_file_dio_aio_read(
ssize_t ret = 0;
loff_t end;
-
- ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
- if (ret < 0)
- return ret;
+ size = iov_length(iovp, nr_segs);
end = iocb->ki_pos + size - 1;
trace_xfs_file_direct_read(ip, size, iocb->ki_pos);
@@ -318,9 +315,7 @@ xfs_file_dax_read(
size_t size = 0;
ssize_t ret = 0;
- ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
- if (ret < 0)
- return ret;
+ size = iov_length(iovp, nr_segs);
trace_xfs_file_dax_read(ip, size, iocb->ki_pos);
@@ -344,13 +339,9 @@ xfs_file_buffered_aio_read(
loff_t pos)
{
struct xfs_inode *ip = XFS_I(file_inode(iocb->ki_filp));
- size_t size = 0;
+ size_t size = iov_length(iovp, nr_segs);
ssize_t ret;
- ret = generic_segment_checks(iovp, &nr_segs, &size, VERIFY_WRITE);
- if (ret < 0)
- return ret;
-
trace_xfs_file_buffered_read(ip, size, iocb->ki_pos);
xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
ret = generic_file_aio_read(iocb, iovp, nr_segs, pos);
@@ -885,10 +876,7 @@ xfs_file_aio_write(
BUG_ON(iocb->ki_pos != pos);
- ret = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ);
- if (ret)
- return ret;
-
+ ocount = iov_length(iovp, nr_segs);
if (ocount == 0)
return 0;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4cd0cc93d32a3..20b5b53ec04e8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3226,8 +3226,6 @@ extern ssize_t generic_file_buffered_write_iter(struct kiocb *, struct iov_iter
loff_t, loff_t *, ssize_t);
extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
-extern int generic_segment_checks(const struct iovec *iov,
- unsigned long *nr_segs, size_t *count, int access_flags);
/* fs/block_dev.c */
extern ssize_t blkdev_aio_read(struct kiocb *, const struct iovec *,
diff --git a/mm/filemap.c b/mm/filemap.c
index d13bc7fef066b..cd72517769f4c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1987,45 +1987,6 @@ int file_read_actor(read_descriptor_t *desc, struct page *page,
return size;
}
-/*
- * Performs necessary checks before doing a write
- * @iov: io vector request
- * @nr_segs: number of segments in the iovec
- * @count: number of bytes to write
- * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE
- *
- * Adjust number of segments and amount of bytes to write (nr_segs should be
- * properly initialized first). Returns appropriate error code that caller
- * should return or zero in case that write should be allowed.
- */
-int generic_segment_checks(const struct iovec *iov,
- unsigned long *nr_segs, size_t *count, int access_flags)
-{
- unsigned long seg;
- size_t cnt = 0;
- for (seg = 0; seg < *nr_segs; seg++) {
- const struct iovec *iv = &iov[seg];
-
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- cnt += iv->iov_len;
- if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(access_flags, iv->iov_base, iv->iov_len))
- continue;
- if (seg == 0)
- return -EFAULT;
- *nr_segs = seg;
- cnt -= iv->iov_len; /* This segment is no good */
- break;
- }
- *count = cnt;
- return 0;
-}
-EXPORT_SYMBOL(generic_segment_checks);
-
static ssize_t mapping_direct_IO(struct address_space *mapping, int rw,
struct kiocb *iocb, struct iov_iter *iter,
loff_t pos)
@@ -2155,13 +2116,7 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct iov_iter iter;
- int ret;
- size_t count;
-
- count = 0;
- ret = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
- if (ret)
- return ret;
+ size_t count = iov_length(iov, nr_segs);
iov_iter_init(&iter, iov, nr_segs, count, 0);
@@ -3191,19 +3146,11 @@ __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t *ppos)
{
struct iov_iter iter;
- size_t count;
- int ret;
-
- count = 0;
- ret = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
- if (ret)
- goto out;
+ size_t count = iov_length(iov, nr_segs);
iov_iter_init(&iter, iov, nr_segs, count, 0);
- ret = __generic_file_write_iter(iocb, &iter, ppos);
-out:
- return ret;
+ return __generic_file_write_iter(iocb, &iter, ppos);
}
EXPORT_SYMBOL(__generic_file_aio_write);
diff --git a/mm/shmem.c b/mm/shmem.c
index 12cab4a18bc37..a9e0877c4bb36 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1953,15 +1953,10 @@ static ssize_t shmem_file_aio_read(struct kiocb *iocb,
const struct iovec *iov, unsigned long nr_segs, loff_t pos)
{
struct file *filp = iocb->ki_filp;
- ssize_t retval;
+ ssize_t retval = 0;
unsigned long seg;
- size_t count;
loff_t *ppos = &iocb->ki_pos;
- retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
- if (retval)
- return retval;
-
for (seg = 0; seg < nr_segs; seg++) {
read_descriptor_t desc;
More information about the Devel
mailing list