[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