[rh7,04/30] kill generic_segment_checks()

Submitted by Kirill Tkhai on May 20, 2020, 4:03 p.m.

Details

Message ID 158999060016.2234365.12206220662047539831.stgit@localhost.localdomain
State New
Series "fs, direct_IO: Switch to iov_iter and allow bio_vec for ext4"
Headers show

Commit Message

Kirill Tkhai May 20, 2020, 4:03 p.m.
From: Al Viro <viro@zeniv.linux.org.uk>

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@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@virtuozzo.com>
---
 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(-)

Patch hide | download patch | download mbox

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 44daeffd851e..e14f2e592028 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 829f3261ef00..4302940a8a6c 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 970cfe6794e8..fefcbb809bf3 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 973f1513868a..258bd78a559c 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 53a11f484fb4..553ef0bddc02 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 81adff3fd865..fb72ec6e1a64 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 60ea07def7e2..dfa86a02e160 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 0fe09671c6b8..5fb17574f0ce 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 f778fcc3bcc5..4992b89b3cba 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 d13bc7fef066..cd72517769f4 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 12cab4a18bc3..a9e0877c4bb3 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;