Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72ec3516 authored by Al Viro's avatar Al Viro
Browse files

switch compat readv/writev variants to COMPAT_SYSCALL_DEFINE



... and take to fs/read_write.c

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent bdaec334
Loading
Loading
Loading
Loading
+0 −16
Original line number Diff line number Diff line
@@ -1387,22 +1387,6 @@ ENTRY(compat_sys_keyctl_wrapper)
	llgfr	%r6,%r6			# u32
	jg	compat_sys_keyctl	# branch to system call

ENTRY(compat_sys_preadv_wrapper)
	llgfr	%r2,%r2			# unsigned long
	llgtr	%r3,%r3			# compat_iovec *
	llgfr	%r4,%r4			# unsigned long
	llgfr	%r5,%r5			# u32
	llgfr	%r6,%r6			# u32
	jg	compat_sys_preadv	# branch to system call

ENTRY(compat_sys_pwritev_wrapper)
	llgfr	%r2,%r2			# unsigned long
	llgtr	%r3,%r3			# compat_iovec *
	llgfr	%r4,%r4			# unsigned long
	llgfr	%r5,%r5			# u32
	llgfr	%r6,%r6			# u32
	jg	compat_sys_pwritev	# branch to system call

ENTRY(sys_perf_event_open_wrapper)
	llgtr	%r2,%r2			# const struct perf_event_attr *
	lgfr	%r3,%r3			# pid_t
+2 −2
Original line number Diff line number Diff line
@@ -336,8 +336,8 @@ SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper)
SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */
SYSCALL(sys_dup3,sys_dup3,sys_dup3_wrapper)
SYSCALL(sys_epoll_create1,sys_epoll_create1,sys_epoll_create1_wrapper)
SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv_wrapper)
SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev_wrapper)
SYSCALL(sys_preadv,sys_preadv,compat_sys_preadv)
SYSCALL(sys_pwritev,sys_pwritev,compat_sys_pwritev)
SYSCALL(sys_rt_tgsigqueueinfo,sys_rt_tgsigqueueinfo,compat_sys_rt_tgsigqueueinfo) /* 330 */
SYSCALL(sys_perf_event_open,sys_perf_event_open,sys_perf_event_open_wrapper)
SYSCALL(sys_fanotify_init,sys_fanotify_init,sys_fanotify_init_wrapper)
+0 −186
Original line number Diff line number Diff line
@@ -1069,192 +1069,6 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
}
#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */

static ssize_t compat_do_readv_writev(int type, struct file *file,
			       const struct compat_iovec __user *uvector,
			       unsigned long nr_segs, loff_t *pos)
{
	compat_ssize_t tot_len;
	struct iovec iovstack[UIO_FASTIOV];
	struct iovec *iov = iovstack;
	ssize_t ret;
	io_fn_t fn;
	iov_fn_t fnv;

	ret = -EINVAL;
	if (!file->f_op)
		goto out;

	ret = compat_rw_copy_check_uvector(type, uvector, nr_segs,
					       UIO_FASTIOV, iovstack, &iov);
	if (ret <= 0)
		goto out;

	tot_len = ret;
	ret = rw_verify_area(type, file, pos, tot_len);
	if (ret < 0)
		goto out;

	fnv = NULL;
	if (type == READ) {
		fn = file->f_op->read;
		fnv = file->f_op->aio_read;
	} else {
		fn = (io_fn_t)file->f_op->write;
		fnv = file->f_op->aio_write;
	}

	if (fnv) {
		file_start_write(file);
		ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
						pos, fnv);
		file_end_write(file);
	} else
		ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);

out:
	if (iov != iovstack)
		kfree(iov);
	if ((ret + (type == READ)) > 0) {
		if (type == READ)
			fsnotify_access(file);
		else
			fsnotify_modify(file);
	}
	return ret;
}

static size_t compat_readv(struct file *file,
			   const struct compat_iovec __user *vec,
			   unsigned long vlen, loff_t *pos)
{
	ssize_t ret = -EBADF;

	if (!(file->f_mode & FMODE_READ))
		goto out;

	ret = -EINVAL;
	if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
		goto out;

	ret = compat_do_readv_writev(READ, file, vec, vlen, pos);

out:
	if (ret > 0)
		add_rchar(current, ret);
	inc_syscr(current);
	return ret;
}

asmlinkage ssize_t
compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec,
		 unsigned long vlen)
{
	struct fd f = fdget(fd);
	ssize_t ret;
	loff_t pos;

	if (!f.file)
		return -EBADF;
	pos = f.file->f_pos;
	ret = compat_readv(f.file, vec, vlen, &pos);
	f.file->f_pos = pos;
	fdput(f);
	return ret;
}

asmlinkage ssize_t
compat_sys_preadv64(unsigned long fd, const struct compat_iovec __user *vec,
		    unsigned long vlen, loff_t pos)
{
	struct fd f;
	ssize_t ret;

	if (pos < 0)
		return -EINVAL;
	f = fdget(fd);
	if (!f.file)
		return -EBADF;
	ret = -ESPIPE;
	if (f.file->f_mode & FMODE_PREAD)
		ret = compat_readv(f.file, vec, vlen, &pos);
	fdput(f);
	return ret;
}

asmlinkage ssize_t
compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
		  unsigned long vlen, u32 pos_low, u32 pos_high)
{
	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
	return compat_sys_preadv64(fd, vec, vlen, pos);
}

static size_t compat_writev(struct file *file,
			    const struct compat_iovec __user *vec,
			    unsigned long vlen, loff_t *pos)
{
	ssize_t ret = -EBADF;

	if (!(file->f_mode & FMODE_WRITE))
		goto out;

	ret = -EINVAL;
	if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
		goto out;

	ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos);

out:
	if (ret > 0)
		add_wchar(current, ret);
	inc_syscw(current);
	return ret;
}

asmlinkage ssize_t
compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec,
		  unsigned long vlen)
{
	struct fd f = fdget(fd);
	ssize_t ret;
	loff_t pos;

	if (!f.file)
		return -EBADF;
	pos = f.file->f_pos;
	ret = compat_writev(f.file, vec, vlen, &pos);
	f.file->f_pos = pos;
	fdput(f);
	return ret;
}

asmlinkage ssize_t
compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec,
		     unsigned long vlen, loff_t pos)
{
	struct fd f;
	ssize_t ret;

	if (pos < 0)
		return -EINVAL;
	f = fdget(fd);
	if (!f.file)
		return -EBADF;
	ret = -ESPIPE;
	if (f.file->f_mode & FMODE_PWRITE)
		ret = compat_writev(f.file, vec, vlen, &pos);
	fdput(f);
	return ret;
}

asmlinkage ssize_t
compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
		   unsigned long vlen, u32 pos_low, u32 pos_high)
{
	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
	return compat_sys_pwritev64(fd, vec, vlen, pos);
}

asmlinkage long
compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32,
		    unsigned int nr_segs, unsigned int flags)
+195 −2
Original line number Diff line number Diff line
@@ -591,7 +591,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
}
EXPORT_SYMBOL(iov_shorten);

ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
static ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
		unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
{
	struct kiocb kiocb;
@@ -616,7 +616,7 @@ ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
}

/* Do it by hand, with file-ops */
ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
static ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
		unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
{
	struct iovec *vector = iov;
@@ -898,6 +898,199 @@ SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec,
	return ret;
}

#ifdef CONFIG_COMPAT

static ssize_t compat_do_readv_writev(int type, struct file *file,
			       const struct compat_iovec __user *uvector,
			       unsigned long nr_segs, loff_t *pos)
{
	compat_ssize_t tot_len;
	struct iovec iovstack[UIO_FASTIOV];
	struct iovec *iov = iovstack;
	ssize_t ret;
	io_fn_t fn;
	iov_fn_t fnv;

	ret = -EINVAL;
	if (!file->f_op)
		goto out;

	ret = -EFAULT;
	if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
		goto out;

	ret = compat_rw_copy_check_uvector(type, uvector, nr_segs,
					       UIO_FASTIOV, iovstack, &iov);
	if (ret <= 0)
		goto out;

	tot_len = ret;
	ret = rw_verify_area(type, file, pos, tot_len);
	if (ret < 0)
		goto out;

	fnv = NULL;
	if (type == READ) {
		fn = file->f_op->read;
		fnv = file->f_op->aio_read;
	} else {
		fn = (io_fn_t)file->f_op->write;
		fnv = file->f_op->aio_write;
	}

	if (fnv) {
		file_start_write(file);
		ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
						pos, fnv);
		file_end_write(file);
	} else
		ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);

out:
	if (iov != iovstack)
		kfree(iov);
	if ((ret + (type == READ)) > 0) {
		if (type == READ)
			fsnotify_access(file);
		else
			fsnotify_modify(file);
	}
	return ret;
}

static size_t compat_readv(struct file *file,
			   const struct compat_iovec __user *vec,
			   unsigned long vlen, loff_t *pos)
{
	ssize_t ret = -EBADF;

	if (!(file->f_mode & FMODE_READ))
		goto out;

	ret = -EINVAL;
	if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
		goto out;

	ret = compat_do_readv_writev(READ, file, vec, vlen, pos);

out:
	if (ret > 0)
		add_rchar(current, ret);
	inc_syscr(current);
	return ret;
}

COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd,
		const struct compat_iovec __user *,vec,
		unsigned long, vlen)
{
	struct fd f = fdget(fd);
	ssize_t ret;
	loff_t pos;

	if (!f.file)
		return -EBADF;
	pos = f.file->f_pos;
	ret = compat_readv(f.file, vec, vlen, &pos);
	f.file->f_pos = pos;
	fdput(f);
	return ret;
}

COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
		const struct compat_iovec __user *,vec,
		unsigned long, vlen, loff_t, pos)
{
	struct fd f;
	ssize_t ret;

	if (pos < 0)
		return -EINVAL;
	f = fdget(fd);
	if (!f.file)
		return -EBADF;
	ret = -ESPIPE;
	if (f.file->f_mode & FMODE_PREAD)
		ret = compat_readv(f.file, vec, vlen, &pos);
	fdput(f);
	return ret;
}

COMPAT_SYSCALL_DEFINE5(preadv, unsigned long, fd,
		const struct compat_iovec __user *,vec,
		unsigned long, vlen, u32, pos_low, u32, pos_high)
{
	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
	return compat_sys_preadv64(fd, vec, vlen, pos);
}

static size_t compat_writev(struct file *file,
			    const struct compat_iovec __user *vec,
			    unsigned long vlen, loff_t *pos)
{
	ssize_t ret = -EBADF;

	if (!(file->f_mode & FMODE_WRITE))
		goto out;

	ret = -EINVAL;
	if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
		goto out;

	ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos);

out:
	if (ret > 0)
		add_wchar(current, ret);
	inc_syscw(current);
	return ret;
}

COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd,
		const struct compat_iovec __user *, vec,
		unsigned long, vlen)
{
	struct fd f = fdget(fd);
	ssize_t ret;
	loff_t pos;

	if (!f.file)
		return -EBADF;
	pos = f.file->f_pos;
	ret = compat_writev(f.file, vec, vlen, &pos);
	f.file->f_pos = pos;
	fdput(f);
	return ret;
}

COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
		const struct compat_iovec __user *,vec,
		unsigned long, vlen, loff_t, pos)
{
	struct fd f;
	ssize_t ret;

	if (pos < 0)
		return -EINVAL;
	f = fdget(fd);
	if (!f.file)
		return -EBADF;
	ret = -ESPIPE;
	if (f.file->f_mode & FMODE_PWRITE)
		ret = compat_writev(f.file, vec, vlen, &pos);
	fdput(f);
	return ret;
}

COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd,
		const struct compat_iovec __user *,vec,
		unsigned long, vlen, u32, pos_low, u32, pos_high)
{
	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
	return compat_sys_pwritev64(fd, vec, vlen, pos);
}
#endif

ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
		    loff_t max)
{
+0 −4
Original line number Diff line number Diff line
@@ -8,9 +8,5 @@ typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
		unsigned long, loff_t);

ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
		unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn);
ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
		unsigned long nr_segs, loff_t *ppos, io_fn_t fn);
ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
		    loff_t max);