162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/read_write.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/stat.h>
1062306a36Sopenharmony_ci#include <linux/sched/xacct.h>
1162306a36Sopenharmony_ci#include <linux/fcntl.h>
1262306a36Sopenharmony_ci#include <linux/file.h>
1362306a36Sopenharmony_ci#include <linux/uio.h>
1462306a36Sopenharmony_ci#include <linux/fsnotify.h>
1562306a36Sopenharmony_ci#include <linux/security.h>
1662306a36Sopenharmony_ci#include <linux/export.h>
1762306a36Sopenharmony_ci#include <linux/syscalls.h>
1862306a36Sopenharmony_ci#include <linux/pagemap.h>
1962306a36Sopenharmony_ci#include <linux/splice.h>
2062306a36Sopenharmony_ci#include <linux/compat.h>
2162306a36Sopenharmony_ci#include <linux/mount.h>
2262306a36Sopenharmony_ci#include <linux/fs.h>
2362306a36Sopenharmony_ci#include "internal.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/uaccess.h>
2662306a36Sopenharmony_ci#include <asm/unistd.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciconst struct file_operations generic_ro_fops = {
2962306a36Sopenharmony_ci	.llseek		= generic_file_llseek,
3062306a36Sopenharmony_ci	.read_iter	= generic_file_read_iter,
3162306a36Sopenharmony_ci	.mmap		= generic_file_readonly_mmap,
3262306a36Sopenharmony_ci	.splice_read	= filemap_splice_read,
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciEXPORT_SYMBOL(generic_ro_fops);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic inline bool unsigned_offsets(struct file *file)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	return file->f_mode & FMODE_UNSIGNED_OFFSET;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/**
4362306a36Sopenharmony_ci * vfs_setpos - update the file offset for lseek
4462306a36Sopenharmony_ci * @file:	file structure in question
4562306a36Sopenharmony_ci * @offset:	file offset to seek to
4662306a36Sopenharmony_ci * @maxsize:	maximum file size
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * This is a low-level filesystem helper for updating the file offset to
4962306a36Sopenharmony_ci * the value specified by @offset if the given offset is valid and it is
5062306a36Sopenharmony_ci * not equal to the current file offset.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * Return the specified offset on success and -EINVAL on invalid offset.
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_ciloff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	if (offset < 0 && !unsigned_offsets(file))
5762306a36Sopenharmony_ci		return -EINVAL;
5862306a36Sopenharmony_ci	if (offset > maxsize)
5962306a36Sopenharmony_ci		return -EINVAL;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (offset != file->f_pos) {
6262306a36Sopenharmony_ci		file->f_pos = offset;
6362306a36Sopenharmony_ci		file->f_version = 0;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	return offset;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_setpos);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/**
7062306a36Sopenharmony_ci * generic_file_llseek_size - generic llseek implementation for regular files
7162306a36Sopenharmony_ci * @file:	file structure to seek on
7262306a36Sopenharmony_ci * @offset:	file offset to seek to
7362306a36Sopenharmony_ci * @whence:	type of seek
7462306a36Sopenharmony_ci * @maxsize:	max size of this file in file system
7562306a36Sopenharmony_ci * @eof:	offset used for SEEK_END position
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * This is a variant of generic_file_llseek that allows passing in a custom
7862306a36Sopenharmony_ci * maximum file size and a custom EOF position, for e.g. hashed directories
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * Synchronization:
8162306a36Sopenharmony_ci * SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms)
8262306a36Sopenharmony_ci * SEEK_CUR is synchronized against other SEEK_CURs, but not read/writes.
8362306a36Sopenharmony_ci * read/writes behave like SEEK_SET against seeks.
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_ciloff_t
8662306a36Sopenharmony_cigeneric_file_llseek_size(struct file *file, loff_t offset, int whence,
8762306a36Sopenharmony_ci		loff_t maxsize, loff_t eof)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	switch (whence) {
9062306a36Sopenharmony_ci	case SEEK_END:
9162306a36Sopenharmony_ci		offset += eof;
9262306a36Sopenharmony_ci		break;
9362306a36Sopenharmony_ci	case SEEK_CUR:
9462306a36Sopenharmony_ci		/*
9562306a36Sopenharmony_ci		 * Here we special-case the lseek(fd, 0, SEEK_CUR)
9662306a36Sopenharmony_ci		 * position-querying operation.  Avoid rewriting the "same"
9762306a36Sopenharmony_ci		 * f_pos value back to the file because a concurrent read(),
9862306a36Sopenharmony_ci		 * write() or lseek() might have altered it
9962306a36Sopenharmony_ci		 */
10062306a36Sopenharmony_ci		if (offset == 0)
10162306a36Sopenharmony_ci			return file->f_pos;
10262306a36Sopenharmony_ci		/*
10362306a36Sopenharmony_ci		 * f_lock protects against read/modify/write race with other
10462306a36Sopenharmony_ci		 * SEEK_CURs. Note that parallel writes and reads behave
10562306a36Sopenharmony_ci		 * like SEEK_SET.
10662306a36Sopenharmony_ci		 */
10762306a36Sopenharmony_ci		spin_lock(&file->f_lock);
10862306a36Sopenharmony_ci		offset = vfs_setpos(file, file->f_pos + offset, maxsize);
10962306a36Sopenharmony_ci		spin_unlock(&file->f_lock);
11062306a36Sopenharmony_ci		return offset;
11162306a36Sopenharmony_ci	case SEEK_DATA:
11262306a36Sopenharmony_ci		/*
11362306a36Sopenharmony_ci		 * In the generic case the entire file is data, so as long as
11462306a36Sopenharmony_ci		 * offset isn't at the end of the file then the offset is data.
11562306a36Sopenharmony_ci		 */
11662306a36Sopenharmony_ci		if ((unsigned long long)offset >= eof)
11762306a36Sopenharmony_ci			return -ENXIO;
11862306a36Sopenharmony_ci		break;
11962306a36Sopenharmony_ci	case SEEK_HOLE:
12062306a36Sopenharmony_ci		/*
12162306a36Sopenharmony_ci		 * There is a virtual hole at the end of the file, so as long as
12262306a36Sopenharmony_ci		 * offset isn't i_size or larger, return i_size.
12362306a36Sopenharmony_ci		 */
12462306a36Sopenharmony_ci		if ((unsigned long long)offset >= eof)
12562306a36Sopenharmony_ci			return -ENXIO;
12662306a36Sopenharmony_ci		offset = eof;
12762306a36Sopenharmony_ci		break;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return vfs_setpos(file, offset, maxsize);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ciEXPORT_SYMBOL(generic_file_llseek_size);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/**
13562306a36Sopenharmony_ci * generic_file_llseek - generic llseek implementation for regular files
13662306a36Sopenharmony_ci * @file:	file structure to seek on
13762306a36Sopenharmony_ci * @offset:	file offset to seek to
13862306a36Sopenharmony_ci * @whence:	type of seek
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci * This is a generic implemenation of ->llseek useable for all normal local
14162306a36Sopenharmony_ci * filesystems.  It just updates the file offset to the value specified by
14262306a36Sopenharmony_ci * @offset and @whence.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_ciloff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return generic_file_llseek_size(file, offset, whence,
14962306a36Sopenharmony_ci					inode->i_sb->s_maxbytes,
15062306a36Sopenharmony_ci					i_size_read(inode));
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ciEXPORT_SYMBOL(generic_file_llseek);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * fixed_size_llseek - llseek implementation for fixed-sized devices
15662306a36Sopenharmony_ci * @file:	file structure to seek on
15762306a36Sopenharmony_ci * @offset:	file offset to seek to
15862306a36Sopenharmony_ci * @whence:	type of seek
15962306a36Sopenharmony_ci * @size:	size of the file
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_ciloff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	switch (whence) {
16562306a36Sopenharmony_ci	case SEEK_SET: case SEEK_CUR: case SEEK_END:
16662306a36Sopenharmony_ci		return generic_file_llseek_size(file, offset, whence,
16762306a36Sopenharmony_ci						size, size);
16862306a36Sopenharmony_ci	default:
16962306a36Sopenharmony_ci		return -EINVAL;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ciEXPORT_SYMBOL(fixed_size_llseek);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/**
17562306a36Sopenharmony_ci * no_seek_end_llseek - llseek implementation for fixed-sized devices
17662306a36Sopenharmony_ci * @file:	file structure to seek on
17762306a36Sopenharmony_ci * @offset:	file offset to seek to
17862306a36Sopenharmony_ci * @whence:	type of seek
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_ciloff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	switch (whence) {
18462306a36Sopenharmony_ci	case SEEK_SET: case SEEK_CUR:
18562306a36Sopenharmony_ci		return generic_file_llseek_size(file, offset, whence,
18662306a36Sopenharmony_ci						OFFSET_MAX, 0);
18762306a36Sopenharmony_ci	default:
18862306a36Sopenharmony_ci		return -EINVAL;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ciEXPORT_SYMBOL(no_seek_end_llseek);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/**
19462306a36Sopenharmony_ci * no_seek_end_llseek_size - llseek implementation for fixed-sized devices
19562306a36Sopenharmony_ci * @file:	file structure to seek on
19662306a36Sopenharmony_ci * @offset:	file offset to seek to
19762306a36Sopenharmony_ci * @whence:	type of seek
19862306a36Sopenharmony_ci * @size:	maximal offset allowed
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_ciloff_t no_seek_end_llseek_size(struct file *file, loff_t offset, int whence, loff_t size)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	switch (whence) {
20462306a36Sopenharmony_ci	case SEEK_SET: case SEEK_CUR:
20562306a36Sopenharmony_ci		return generic_file_llseek_size(file, offset, whence,
20662306a36Sopenharmony_ci						size, 0);
20762306a36Sopenharmony_ci	default:
20862306a36Sopenharmony_ci		return -EINVAL;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ciEXPORT_SYMBOL(no_seek_end_llseek_size);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/**
21462306a36Sopenharmony_ci * noop_llseek - No Operation Performed llseek implementation
21562306a36Sopenharmony_ci * @file:	file structure to seek on
21662306a36Sopenharmony_ci * @offset:	file offset to seek to
21762306a36Sopenharmony_ci * @whence:	type of seek
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci * This is an implementation of ->llseek useable for the rare special case when
22062306a36Sopenharmony_ci * userspace expects the seek to succeed but the (device) file is actually not
22162306a36Sopenharmony_ci * able to perform the seek. In this case you use noop_llseek() instead of
22262306a36Sopenharmony_ci * falling back to the default implementation of ->llseek.
22362306a36Sopenharmony_ci */
22462306a36Sopenharmony_ciloff_t noop_llseek(struct file *file, loff_t offset, int whence)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	return file->f_pos;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ciEXPORT_SYMBOL(noop_llseek);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ciloff_t default_llseek(struct file *file, loff_t offset, int whence)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
23362306a36Sopenharmony_ci	loff_t retval;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	inode_lock(inode);
23662306a36Sopenharmony_ci	switch (whence) {
23762306a36Sopenharmony_ci		case SEEK_END:
23862306a36Sopenharmony_ci			offset += i_size_read(inode);
23962306a36Sopenharmony_ci			break;
24062306a36Sopenharmony_ci		case SEEK_CUR:
24162306a36Sopenharmony_ci			if (offset == 0) {
24262306a36Sopenharmony_ci				retval = file->f_pos;
24362306a36Sopenharmony_ci				goto out;
24462306a36Sopenharmony_ci			}
24562306a36Sopenharmony_ci			offset += file->f_pos;
24662306a36Sopenharmony_ci			break;
24762306a36Sopenharmony_ci		case SEEK_DATA:
24862306a36Sopenharmony_ci			/*
24962306a36Sopenharmony_ci			 * In the generic case the entire file is data, so as
25062306a36Sopenharmony_ci			 * long as offset isn't at the end of the file then the
25162306a36Sopenharmony_ci			 * offset is data.
25262306a36Sopenharmony_ci			 */
25362306a36Sopenharmony_ci			if (offset >= inode->i_size) {
25462306a36Sopenharmony_ci				retval = -ENXIO;
25562306a36Sopenharmony_ci				goto out;
25662306a36Sopenharmony_ci			}
25762306a36Sopenharmony_ci			break;
25862306a36Sopenharmony_ci		case SEEK_HOLE:
25962306a36Sopenharmony_ci			/*
26062306a36Sopenharmony_ci			 * There is a virtual hole at the end of the file, so
26162306a36Sopenharmony_ci			 * as long as offset isn't i_size or larger, return
26262306a36Sopenharmony_ci			 * i_size.
26362306a36Sopenharmony_ci			 */
26462306a36Sopenharmony_ci			if (offset >= inode->i_size) {
26562306a36Sopenharmony_ci				retval = -ENXIO;
26662306a36Sopenharmony_ci				goto out;
26762306a36Sopenharmony_ci			}
26862306a36Sopenharmony_ci			offset = inode->i_size;
26962306a36Sopenharmony_ci			break;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci	retval = -EINVAL;
27262306a36Sopenharmony_ci	if (offset >= 0 || unsigned_offsets(file)) {
27362306a36Sopenharmony_ci		if (offset != file->f_pos) {
27462306a36Sopenharmony_ci			file->f_pos = offset;
27562306a36Sopenharmony_ci			file->f_version = 0;
27662306a36Sopenharmony_ci		}
27762306a36Sopenharmony_ci		retval = offset;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ciout:
28062306a36Sopenharmony_ci	inode_unlock(inode);
28162306a36Sopenharmony_ci	return retval;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ciEXPORT_SYMBOL(default_llseek);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ciloff_t vfs_llseek(struct file *file, loff_t offset, int whence)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_LSEEK))
28862306a36Sopenharmony_ci		return -ESPIPE;
28962306a36Sopenharmony_ci	return file->f_op->llseek(file, offset, whence);
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_llseek);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic off_t ksys_lseek(unsigned int fd, off_t offset, unsigned int whence)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	off_t retval;
29662306a36Sopenharmony_ci	struct fd f = fdget_pos(fd);
29762306a36Sopenharmony_ci	if (!f.file)
29862306a36Sopenharmony_ci		return -EBADF;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	retval = -EINVAL;
30162306a36Sopenharmony_ci	if (whence <= SEEK_MAX) {
30262306a36Sopenharmony_ci		loff_t res = vfs_llseek(f.file, offset, whence);
30362306a36Sopenharmony_ci		retval = res;
30462306a36Sopenharmony_ci		if (res != (loff_t)retval)
30562306a36Sopenharmony_ci			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci	fdput_pos(f);
30862306a36Sopenharmony_ci	return retval;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ciSYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	return ksys_lseek(fd, offset, whence);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
31762306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE3(lseek, unsigned int, fd, compat_off_t, offset, unsigned int, whence)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	return ksys_lseek(fd, offset, whence);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci#endif
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci#if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT) || \
32462306a36Sopenharmony_ci	defined(__ARCH_WANT_SYS_LLSEEK)
32562306a36Sopenharmony_ciSYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
32662306a36Sopenharmony_ci		unsigned long, offset_low, loff_t __user *, result,
32762306a36Sopenharmony_ci		unsigned int, whence)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	int retval;
33062306a36Sopenharmony_ci	struct fd f = fdget_pos(fd);
33162306a36Sopenharmony_ci	loff_t offset;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (!f.file)
33462306a36Sopenharmony_ci		return -EBADF;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	retval = -EINVAL;
33762306a36Sopenharmony_ci	if (whence > SEEK_MAX)
33862306a36Sopenharmony_ci		goto out_putf;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	offset = vfs_llseek(f.file, ((loff_t) offset_high << 32) | offset_low,
34162306a36Sopenharmony_ci			whence);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	retval = (int)offset;
34462306a36Sopenharmony_ci	if (offset >= 0) {
34562306a36Sopenharmony_ci		retval = -EFAULT;
34662306a36Sopenharmony_ci		if (!copy_to_user(result, &offset, sizeof(offset)))
34762306a36Sopenharmony_ci			retval = 0;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ciout_putf:
35062306a36Sopenharmony_ci	fdput_pos(f);
35162306a36Sopenharmony_ci	return retval;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci#endif
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ciint rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	if (unlikely((ssize_t) count < 0))
35862306a36Sopenharmony_ci		return -EINVAL;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (ppos) {
36162306a36Sopenharmony_ci		loff_t pos = *ppos;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		if (unlikely(pos < 0)) {
36462306a36Sopenharmony_ci			if (!unsigned_offsets(file))
36562306a36Sopenharmony_ci				return -EINVAL;
36662306a36Sopenharmony_ci			if (count >= -pos) /* both values are in 0..LLONG_MAX */
36762306a36Sopenharmony_ci				return -EOVERFLOW;
36862306a36Sopenharmony_ci		} else if (unlikely((loff_t) (pos + count) < 0)) {
36962306a36Sopenharmony_ci			if (!unsigned_offsets(file))
37062306a36Sopenharmony_ci				return -EINVAL;
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	return security_file_permission(file,
37562306a36Sopenharmony_ci				read_write == READ ? MAY_READ : MAY_WRITE);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ciEXPORT_SYMBOL(rw_verify_area);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct kiocb kiocb;
38262306a36Sopenharmony_ci	struct iov_iter iter;
38362306a36Sopenharmony_ci	ssize_t ret;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	init_sync_kiocb(&kiocb, filp);
38662306a36Sopenharmony_ci	kiocb.ki_pos = (ppos ? *ppos : 0);
38762306a36Sopenharmony_ci	iov_iter_ubuf(&iter, ITER_DEST, buf, len);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	ret = call_read_iter(filp, &kiocb, &iter);
39062306a36Sopenharmony_ci	BUG_ON(ret == -EIOCBQUEUED);
39162306a36Sopenharmony_ci	if (ppos)
39262306a36Sopenharmony_ci		*ppos = kiocb.ki_pos;
39362306a36Sopenharmony_ci	return ret;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int warn_unsupported(struct file *file, const char *op)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	pr_warn_ratelimited(
39962306a36Sopenharmony_ci		"kernel %s not supported for file %pD4 (pid: %d comm: %.20s)\n",
40062306a36Sopenharmony_ci		op, file, current->pid, current->comm);
40162306a36Sopenharmony_ci	return -EINVAL;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cissize_t __kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct kvec iov = {
40762306a36Sopenharmony_ci		.iov_base	= buf,
40862306a36Sopenharmony_ci		.iov_len	= min_t(size_t, count, MAX_RW_COUNT),
40962306a36Sopenharmony_ci	};
41062306a36Sopenharmony_ci	struct kiocb kiocb;
41162306a36Sopenharmony_ci	struct iov_iter iter;
41262306a36Sopenharmony_ci	ssize_t ret;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (WARN_ON_ONCE(!(file->f_mode & FMODE_READ)))
41562306a36Sopenharmony_ci		return -EINVAL;
41662306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_READ))
41762306a36Sopenharmony_ci		return -EINVAL;
41862306a36Sopenharmony_ci	/*
41962306a36Sopenharmony_ci	 * Also fail if ->read_iter and ->read are both wired up as that
42062306a36Sopenharmony_ci	 * implies very convoluted semantics.
42162306a36Sopenharmony_ci	 */
42262306a36Sopenharmony_ci	if (unlikely(!file->f_op->read_iter || file->f_op->read))
42362306a36Sopenharmony_ci		return warn_unsupported(file, "read");
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	init_sync_kiocb(&kiocb, file);
42662306a36Sopenharmony_ci	kiocb.ki_pos = pos ? *pos : 0;
42762306a36Sopenharmony_ci	iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len);
42862306a36Sopenharmony_ci	ret = file->f_op->read_iter(&kiocb, &iter);
42962306a36Sopenharmony_ci	if (ret > 0) {
43062306a36Sopenharmony_ci		if (pos)
43162306a36Sopenharmony_ci			*pos = kiocb.ki_pos;
43262306a36Sopenharmony_ci		fsnotify_access(file);
43362306a36Sopenharmony_ci		add_rchar(current, ret);
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci	inc_syscr(current);
43662306a36Sopenharmony_ci	return ret;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cissize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	ssize_t ret;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	ret = rw_verify_area(READ, file, pos, count);
44462306a36Sopenharmony_ci	if (ret)
44562306a36Sopenharmony_ci		return ret;
44662306a36Sopenharmony_ci	return __kernel_read(file, buf, count, pos);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ciEXPORT_SYMBOL(kernel_read);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cissize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	ssize_t ret;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_READ))
45562306a36Sopenharmony_ci		return -EBADF;
45662306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_READ))
45762306a36Sopenharmony_ci		return -EINVAL;
45862306a36Sopenharmony_ci	if (unlikely(!access_ok(buf, count)))
45962306a36Sopenharmony_ci		return -EFAULT;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	ret = rw_verify_area(READ, file, pos, count);
46262306a36Sopenharmony_ci	if (ret)
46362306a36Sopenharmony_ci		return ret;
46462306a36Sopenharmony_ci	if (count > MAX_RW_COUNT)
46562306a36Sopenharmony_ci		count =  MAX_RW_COUNT;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (file->f_op->read)
46862306a36Sopenharmony_ci		ret = file->f_op->read(file, buf, count, pos);
46962306a36Sopenharmony_ci	else if (file->f_op->read_iter)
47062306a36Sopenharmony_ci		ret = new_sync_read(file, buf, count, pos);
47162306a36Sopenharmony_ci	else
47262306a36Sopenharmony_ci		ret = -EINVAL;
47362306a36Sopenharmony_ci	if (ret > 0) {
47462306a36Sopenharmony_ci		fsnotify_access(file);
47562306a36Sopenharmony_ci		add_rchar(current, ret);
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	inc_syscr(current);
47862306a36Sopenharmony_ci	return ret;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct kiocb kiocb;
48462306a36Sopenharmony_ci	struct iov_iter iter;
48562306a36Sopenharmony_ci	ssize_t ret;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	init_sync_kiocb(&kiocb, filp);
48862306a36Sopenharmony_ci	kiocb.ki_pos = (ppos ? *ppos : 0);
48962306a36Sopenharmony_ci	iov_iter_ubuf(&iter, ITER_SOURCE, (void __user *)buf, len);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	ret = call_write_iter(filp, &kiocb, &iter);
49262306a36Sopenharmony_ci	BUG_ON(ret == -EIOCBQUEUED);
49362306a36Sopenharmony_ci	if (ret > 0 && ppos)
49462306a36Sopenharmony_ci		*ppos = kiocb.ki_pos;
49562306a36Sopenharmony_ci	return ret;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci/* caller is responsible for file_start_write/file_end_write */
49962306a36Sopenharmony_cissize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *pos)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct kiocb kiocb;
50262306a36Sopenharmony_ci	ssize_t ret;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (WARN_ON_ONCE(!(file->f_mode & FMODE_WRITE)))
50562306a36Sopenharmony_ci		return -EBADF;
50662306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_WRITE))
50762306a36Sopenharmony_ci		return -EINVAL;
50862306a36Sopenharmony_ci	/*
50962306a36Sopenharmony_ci	 * Also fail if ->write_iter and ->write are both wired up as that
51062306a36Sopenharmony_ci	 * implies very convoluted semantics.
51162306a36Sopenharmony_ci	 */
51262306a36Sopenharmony_ci	if (unlikely(!file->f_op->write_iter || file->f_op->write))
51362306a36Sopenharmony_ci		return warn_unsupported(file, "write");
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	init_sync_kiocb(&kiocb, file);
51662306a36Sopenharmony_ci	kiocb.ki_pos = pos ? *pos : 0;
51762306a36Sopenharmony_ci	ret = file->f_op->write_iter(&kiocb, from);
51862306a36Sopenharmony_ci	if (ret > 0) {
51962306a36Sopenharmony_ci		if (pos)
52062306a36Sopenharmony_ci			*pos = kiocb.ki_pos;
52162306a36Sopenharmony_ci		fsnotify_modify(file);
52262306a36Sopenharmony_ci		add_wchar(current, ret);
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci	inc_syscw(current);
52562306a36Sopenharmony_ci	return ret;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/* caller is responsible for file_start_write/file_end_write */
52962306a36Sopenharmony_cissize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	struct kvec iov = {
53262306a36Sopenharmony_ci		.iov_base	= (void *)buf,
53362306a36Sopenharmony_ci		.iov_len	= min_t(size_t, count, MAX_RW_COUNT),
53462306a36Sopenharmony_ci	};
53562306a36Sopenharmony_ci	struct iov_iter iter;
53662306a36Sopenharmony_ci	iov_iter_kvec(&iter, ITER_SOURCE, &iov, 1, iov.iov_len);
53762306a36Sopenharmony_ci	return __kernel_write_iter(file, &iter, pos);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci/*
54062306a36Sopenharmony_ci * This "EXPORT_SYMBOL_GPL()" is more of a "EXPORT_SYMBOL_DONTUSE()",
54162306a36Sopenharmony_ci * but autofs is one of the few internal kernel users that actually
54262306a36Sopenharmony_ci * wants this _and_ can be built as a module. So we need to export
54362306a36Sopenharmony_ci * this symbol for autofs, even though it really isn't appropriate
54462306a36Sopenharmony_ci * for any other kernel modules.
54562306a36Sopenharmony_ci */
54662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__kernel_write);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cissize_t kernel_write(struct file *file, const void *buf, size_t count,
54962306a36Sopenharmony_ci			    loff_t *pos)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	ssize_t ret;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	ret = rw_verify_area(WRITE, file, pos, count);
55462306a36Sopenharmony_ci	if (ret)
55562306a36Sopenharmony_ci		return ret;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	file_start_write(file);
55862306a36Sopenharmony_ci	ret =  __kernel_write(file, buf, count, pos);
55962306a36Sopenharmony_ci	file_end_write(file);
56062306a36Sopenharmony_ci	return ret;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ciEXPORT_SYMBOL(kernel_write);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cissize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	ssize_t ret;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_WRITE))
56962306a36Sopenharmony_ci		return -EBADF;
57062306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_WRITE))
57162306a36Sopenharmony_ci		return -EINVAL;
57262306a36Sopenharmony_ci	if (unlikely(!access_ok(buf, count)))
57362306a36Sopenharmony_ci		return -EFAULT;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	ret = rw_verify_area(WRITE, file, pos, count);
57662306a36Sopenharmony_ci	if (ret)
57762306a36Sopenharmony_ci		return ret;
57862306a36Sopenharmony_ci	if (count > MAX_RW_COUNT)
57962306a36Sopenharmony_ci		count =  MAX_RW_COUNT;
58062306a36Sopenharmony_ci	file_start_write(file);
58162306a36Sopenharmony_ci	if (file->f_op->write)
58262306a36Sopenharmony_ci		ret = file->f_op->write(file, buf, count, pos);
58362306a36Sopenharmony_ci	else if (file->f_op->write_iter)
58462306a36Sopenharmony_ci		ret = new_sync_write(file, buf, count, pos);
58562306a36Sopenharmony_ci	else
58662306a36Sopenharmony_ci		ret = -EINVAL;
58762306a36Sopenharmony_ci	if (ret > 0) {
58862306a36Sopenharmony_ci		fsnotify_modify(file);
58962306a36Sopenharmony_ci		add_wchar(current, ret);
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci	inc_syscw(current);
59262306a36Sopenharmony_ci	file_end_write(file);
59362306a36Sopenharmony_ci	return ret;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci/* file_ppos returns &file->f_pos or NULL if file is stream */
59762306a36Sopenharmony_cistatic inline loff_t *file_ppos(struct file *file)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	return file->f_mode & FMODE_STREAM ? NULL : &file->f_pos;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cissize_t ksys_read(unsigned int fd, char __user *buf, size_t count)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct fd f = fdget_pos(fd);
60562306a36Sopenharmony_ci	ssize_t ret = -EBADF;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (f.file) {
60862306a36Sopenharmony_ci		loff_t pos, *ppos = file_ppos(f.file);
60962306a36Sopenharmony_ci		if (ppos) {
61062306a36Sopenharmony_ci			pos = *ppos;
61162306a36Sopenharmony_ci			ppos = &pos;
61262306a36Sopenharmony_ci		}
61362306a36Sopenharmony_ci		ret = vfs_read(f.file, buf, count, ppos);
61462306a36Sopenharmony_ci		if (ret >= 0 && ppos)
61562306a36Sopenharmony_ci			f.file->f_pos = pos;
61662306a36Sopenharmony_ci		fdput_pos(f);
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	return ret;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ciSYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	return ksys_read(fd, buf, count);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cissize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct fd f = fdget_pos(fd);
62962306a36Sopenharmony_ci	ssize_t ret = -EBADF;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (f.file) {
63262306a36Sopenharmony_ci		loff_t pos, *ppos = file_ppos(f.file);
63362306a36Sopenharmony_ci		if (ppos) {
63462306a36Sopenharmony_ci			pos = *ppos;
63562306a36Sopenharmony_ci			ppos = &pos;
63662306a36Sopenharmony_ci		}
63762306a36Sopenharmony_ci		ret = vfs_write(f.file, buf, count, ppos);
63862306a36Sopenharmony_ci		if (ret >= 0 && ppos)
63962306a36Sopenharmony_ci			f.file->f_pos = pos;
64062306a36Sopenharmony_ci		fdput_pos(f);
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	return ret;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ciSYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
64762306a36Sopenharmony_ci		size_t, count)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	return ksys_write(fd, buf, count);
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cissize_t ksys_pread64(unsigned int fd, char __user *buf, size_t count,
65362306a36Sopenharmony_ci		     loff_t pos)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct fd f;
65662306a36Sopenharmony_ci	ssize_t ret = -EBADF;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (pos < 0)
65962306a36Sopenharmony_ci		return -EINVAL;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	f = fdget(fd);
66262306a36Sopenharmony_ci	if (f.file) {
66362306a36Sopenharmony_ci		ret = -ESPIPE;
66462306a36Sopenharmony_ci		if (f.file->f_mode & FMODE_PREAD)
66562306a36Sopenharmony_ci			ret = vfs_read(f.file, buf, count, &pos);
66662306a36Sopenharmony_ci		fdput(f);
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	return ret;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ciSYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf,
67362306a36Sopenharmony_ci			size_t, count, loff_t, pos)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	return ksys_pread64(fd, buf, count, pos);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_PREAD64)
67962306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(pread64, unsigned int, fd, char __user *, buf,
68062306a36Sopenharmony_ci		       size_t, count, compat_arg_u64_dual(pos))
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	return ksys_pread64(fd, buf, count, compat_arg_u64_glue(pos));
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci#endif
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cissize_t ksys_pwrite64(unsigned int fd, const char __user *buf,
68762306a36Sopenharmony_ci		      size_t count, loff_t pos)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct fd f;
69062306a36Sopenharmony_ci	ssize_t ret = -EBADF;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (pos < 0)
69362306a36Sopenharmony_ci		return -EINVAL;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	f = fdget(fd);
69662306a36Sopenharmony_ci	if (f.file) {
69762306a36Sopenharmony_ci		ret = -ESPIPE;
69862306a36Sopenharmony_ci		if (f.file->f_mode & FMODE_PWRITE)
69962306a36Sopenharmony_ci			ret = vfs_write(f.file, buf, count, &pos);
70062306a36Sopenharmony_ci		fdput(f);
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	return ret;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ciSYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf,
70762306a36Sopenharmony_ci			 size_t, count, loff_t, pos)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	return ksys_pwrite64(fd, buf, count, pos);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci#if defined(CONFIG_COMPAT) && defined(__ARCH_WANT_COMPAT_PWRITE64)
71362306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(pwrite64, unsigned int, fd, const char __user *, buf,
71462306a36Sopenharmony_ci		       size_t, count, compat_arg_u64_dual(pos))
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	return ksys_pwrite64(fd, buf, count, compat_arg_u64_glue(pos));
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci#endif
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter,
72162306a36Sopenharmony_ci		loff_t *ppos, int type, rwf_t flags)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct kiocb kiocb;
72462306a36Sopenharmony_ci	ssize_t ret;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	init_sync_kiocb(&kiocb, filp);
72762306a36Sopenharmony_ci	ret = kiocb_set_rw_flags(&kiocb, flags);
72862306a36Sopenharmony_ci	if (ret)
72962306a36Sopenharmony_ci		return ret;
73062306a36Sopenharmony_ci	kiocb.ki_pos = (ppos ? *ppos : 0);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (type == READ)
73362306a36Sopenharmony_ci		ret = call_read_iter(filp, &kiocb, iter);
73462306a36Sopenharmony_ci	else
73562306a36Sopenharmony_ci		ret = call_write_iter(filp, &kiocb, iter);
73662306a36Sopenharmony_ci	BUG_ON(ret == -EIOCBQUEUED);
73762306a36Sopenharmony_ci	if (ppos)
73862306a36Sopenharmony_ci		*ppos = kiocb.ki_pos;
73962306a36Sopenharmony_ci	return ret;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci/* Do it by hand, with file-ops */
74362306a36Sopenharmony_cistatic ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter,
74462306a36Sopenharmony_ci		loff_t *ppos, int type, rwf_t flags)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	ssize_t ret = 0;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (flags & ~RWF_HIPRI)
74962306a36Sopenharmony_ci		return -EOPNOTSUPP;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	while (iov_iter_count(iter)) {
75262306a36Sopenharmony_ci		ssize_t nr;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		if (type == READ) {
75562306a36Sopenharmony_ci			nr = filp->f_op->read(filp, iter_iov_addr(iter),
75662306a36Sopenharmony_ci						iter_iov_len(iter), ppos);
75762306a36Sopenharmony_ci		} else {
75862306a36Sopenharmony_ci			nr = filp->f_op->write(filp, iter_iov_addr(iter),
75962306a36Sopenharmony_ci						iter_iov_len(iter), ppos);
76062306a36Sopenharmony_ci		}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		if (nr < 0) {
76362306a36Sopenharmony_ci			if (!ret)
76462306a36Sopenharmony_ci				ret = nr;
76562306a36Sopenharmony_ci			break;
76662306a36Sopenharmony_ci		}
76762306a36Sopenharmony_ci		ret += nr;
76862306a36Sopenharmony_ci		if (nr != iter_iov_len(iter))
76962306a36Sopenharmony_ci			break;
77062306a36Sopenharmony_ci		iov_iter_advance(iter, nr);
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return ret;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic ssize_t do_iter_read(struct file *file, struct iov_iter *iter,
77762306a36Sopenharmony_ci		loff_t *pos, rwf_t flags)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	size_t tot_len;
78062306a36Sopenharmony_ci	ssize_t ret = 0;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_READ))
78362306a36Sopenharmony_ci		return -EBADF;
78462306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_READ))
78562306a36Sopenharmony_ci		return -EINVAL;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	tot_len = iov_iter_count(iter);
78862306a36Sopenharmony_ci	if (!tot_len)
78962306a36Sopenharmony_ci		goto out;
79062306a36Sopenharmony_ci	ret = rw_verify_area(READ, file, pos, tot_len);
79162306a36Sopenharmony_ci	if (ret < 0)
79262306a36Sopenharmony_ci		return ret;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if (file->f_op->read_iter)
79562306a36Sopenharmony_ci		ret = do_iter_readv_writev(file, iter, pos, READ, flags);
79662306a36Sopenharmony_ci	else
79762306a36Sopenharmony_ci		ret = do_loop_readv_writev(file, iter, pos, READ, flags);
79862306a36Sopenharmony_ciout:
79962306a36Sopenharmony_ci	if (ret >= 0)
80062306a36Sopenharmony_ci		fsnotify_access(file);
80162306a36Sopenharmony_ci	return ret;
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_cissize_t vfs_iocb_iter_read(struct file *file, struct kiocb *iocb,
80562306a36Sopenharmony_ci			   struct iov_iter *iter)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	size_t tot_len;
80862306a36Sopenharmony_ci	ssize_t ret = 0;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	if (!file->f_op->read_iter)
81162306a36Sopenharmony_ci		return -EINVAL;
81262306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_READ))
81362306a36Sopenharmony_ci		return -EBADF;
81462306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_READ))
81562306a36Sopenharmony_ci		return -EINVAL;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	tot_len = iov_iter_count(iter);
81862306a36Sopenharmony_ci	if (!tot_len)
81962306a36Sopenharmony_ci		goto out;
82062306a36Sopenharmony_ci	ret = rw_verify_area(READ, file, &iocb->ki_pos, tot_len);
82162306a36Sopenharmony_ci	if (ret < 0)
82262306a36Sopenharmony_ci		return ret;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	ret = call_read_iter(file, iocb, iter);
82562306a36Sopenharmony_ciout:
82662306a36Sopenharmony_ci	if (ret >= 0)
82762306a36Sopenharmony_ci		fsnotify_access(file);
82862306a36Sopenharmony_ci	return ret;
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_iocb_iter_read);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cissize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos,
83362306a36Sopenharmony_ci		rwf_t flags)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	if (!file->f_op->read_iter)
83662306a36Sopenharmony_ci		return -EINVAL;
83762306a36Sopenharmony_ci	return do_iter_read(file, iter, ppos, flags);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_iter_read);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic ssize_t do_iter_write(struct file *file, struct iov_iter *iter,
84262306a36Sopenharmony_ci		loff_t *pos, rwf_t flags)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	size_t tot_len;
84562306a36Sopenharmony_ci	ssize_t ret = 0;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_WRITE))
84862306a36Sopenharmony_ci		return -EBADF;
84962306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_WRITE))
85062306a36Sopenharmony_ci		return -EINVAL;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	tot_len = iov_iter_count(iter);
85362306a36Sopenharmony_ci	if (!tot_len)
85462306a36Sopenharmony_ci		return 0;
85562306a36Sopenharmony_ci	ret = rw_verify_area(WRITE, file, pos, tot_len);
85662306a36Sopenharmony_ci	if (ret < 0)
85762306a36Sopenharmony_ci		return ret;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (file->f_op->write_iter)
86062306a36Sopenharmony_ci		ret = do_iter_readv_writev(file, iter, pos, WRITE, flags);
86162306a36Sopenharmony_ci	else
86262306a36Sopenharmony_ci		ret = do_loop_readv_writev(file, iter, pos, WRITE, flags);
86362306a36Sopenharmony_ci	if (ret > 0)
86462306a36Sopenharmony_ci		fsnotify_modify(file);
86562306a36Sopenharmony_ci	return ret;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cissize_t vfs_iocb_iter_write(struct file *file, struct kiocb *iocb,
86962306a36Sopenharmony_ci			    struct iov_iter *iter)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	size_t tot_len;
87262306a36Sopenharmony_ci	ssize_t ret = 0;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	if (!file->f_op->write_iter)
87562306a36Sopenharmony_ci		return -EINVAL;
87662306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_WRITE))
87762306a36Sopenharmony_ci		return -EBADF;
87862306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_CAN_WRITE))
87962306a36Sopenharmony_ci		return -EINVAL;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	tot_len = iov_iter_count(iter);
88262306a36Sopenharmony_ci	if (!tot_len)
88362306a36Sopenharmony_ci		return 0;
88462306a36Sopenharmony_ci	ret = rw_verify_area(WRITE, file, &iocb->ki_pos, tot_len);
88562306a36Sopenharmony_ci	if (ret < 0)
88662306a36Sopenharmony_ci		return ret;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	ret = call_write_iter(file, iocb, iter);
88962306a36Sopenharmony_ci	if (ret > 0)
89062306a36Sopenharmony_ci		fsnotify_modify(file);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	return ret;
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_iocb_iter_write);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cissize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos,
89762306a36Sopenharmony_ci		rwf_t flags)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	if (!file->f_op->write_iter)
90062306a36Sopenharmony_ci		return -EINVAL;
90162306a36Sopenharmony_ci	return do_iter_write(file, iter, ppos, flags);
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_iter_write);
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
90662306a36Sopenharmony_ci		  unsigned long vlen, loff_t *pos, rwf_t flags)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct iovec iovstack[UIO_FASTIOV];
90962306a36Sopenharmony_ci	struct iovec *iov = iovstack;
91062306a36Sopenharmony_ci	struct iov_iter iter;
91162306a36Sopenharmony_ci	ssize_t ret;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	ret = import_iovec(ITER_DEST, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
91462306a36Sopenharmony_ci	if (ret >= 0) {
91562306a36Sopenharmony_ci		ret = do_iter_read(file, &iter, pos, flags);
91662306a36Sopenharmony_ci		kfree(iov);
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	return ret;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
92362306a36Sopenharmony_ci		   unsigned long vlen, loff_t *pos, rwf_t flags)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	struct iovec iovstack[UIO_FASTIOV];
92662306a36Sopenharmony_ci	struct iovec *iov = iovstack;
92762306a36Sopenharmony_ci	struct iov_iter iter;
92862306a36Sopenharmony_ci	ssize_t ret;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	ret = import_iovec(ITER_SOURCE, vec, vlen, ARRAY_SIZE(iovstack), &iov, &iter);
93162306a36Sopenharmony_ci	if (ret >= 0) {
93262306a36Sopenharmony_ci		file_start_write(file);
93362306a36Sopenharmony_ci		ret = do_iter_write(file, &iter, pos, flags);
93462306a36Sopenharmony_ci		file_end_write(file);
93562306a36Sopenharmony_ci		kfree(iov);
93662306a36Sopenharmony_ci	}
93762306a36Sopenharmony_ci	return ret;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic ssize_t do_readv(unsigned long fd, const struct iovec __user *vec,
94162306a36Sopenharmony_ci			unsigned long vlen, rwf_t flags)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	struct fd f = fdget_pos(fd);
94462306a36Sopenharmony_ci	ssize_t ret = -EBADF;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (f.file) {
94762306a36Sopenharmony_ci		loff_t pos, *ppos = file_ppos(f.file);
94862306a36Sopenharmony_ci		if (ppos) {
94962306a36Sopenharmony_ci			pos = *ppos;
95062306a36Sopenharmony_ci			ppos = &pos;
95162306a36Sopenharmony_ci		}
95262306a36Sopenharmony_ci		ret = vfs_readv(f.file, vec, vlen, ppos, flags);
95362306a36Sopenharmony_ci		if (ret >= 0 && ppos)
95462306a36Sopenharmony_ci			f.file->f_pos = pos;
95562306a36Sopenharmony_ci		fdput_pos(f);
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (ret > 0)
95962306a36Sopenharmony_ci		add_rchar(current, ret);
96062306a36Sopenharmony_ci	inc_syscr(current);
96162306a36Sopenharmony_ci	return ret;
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic ssize_t do_writev(unsigned long fd, const struct iovec __user *vec,
96562306a36Sopenharmony_ci			 unsigned long vlen, rwf_t flags)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	struct fd f = fdget_pos(fd);
96862306a36Sopenharmony_ci	ssize_t ret = -EBADF;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	if (f.file) {
97162306a36Sopenharmony_ci		loff_t pos, *ppos = file_ppos(f.file);
97262306a36Sopenharmony_ci		if (ppos) {
97362306a36Sopenharmony_ci			pos = *ppos;
97462306a36Sopenharmony_ci			ppos = &pos;
97562306a36Sopenharmony_ci		}
97662306a36Sopenharmony_ci		ret = vfs_writev(f.file, vec, vlen, ppos, flags);
97762306a36Sopenharmony_ci		if (ret >= 0 && ppos)
97862306a36Sopenharmony_ci			f.file->f_pos = pos;
97962306a36Sopenharmony_ci		fdput_pos(f);
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (ret > 0)
98362306a36Sopenharmony_ci		add_wchar(current, ret);
98462306a36Sopenharmony_ci	inc_syscw(current);
98562306a36Sopenharmony_ci	return ret;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistatic inline loff_t pos_from_hilo(unsigned long high, unsigned long low)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci#define HALF_LONG_BITS (BITS_PER_LONG / 2)
99162306a36Sopenharmony_ci	return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_cistatic ssize_t do_preadv(unsigned long fd, const struct iovec __user *vec,
99562306a36Sopenharmony_ci			 unsigned long vlen, loff_t pos, rwf_t flags)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct fd f;
99862306a36Sopenharmony_ci	ssize_t ret = -EBADF;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	if (pos < 0)
100162306a36Sopenharmony_ci		return -EINVAL;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	f = fdget(fd);
100462306a36Sopenharmony_ci	if (f.file) {
100562306a36Sopenharmony_ci		ret = -ESPIPE;
100662306a36Sopenharmony_ci		if (f.file->f_mode & FMODE_PREAD)
100762306a36Sopenharmony_ci			ret = vfs_readv(f.file, vec, vlen, &pos, flags);
100862306a36Sopenharmony_ci		fdput(f);
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (ret > 0)
101262306a36Sopenharmony_ci		add_rchar(current, ret);
101362306a36Sopenharmony_ci	inc_syscr(current);
101462306a36Sopenharmony_ci	return ret;
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic ssize_t do_pwritev(unsigned long fd, const struct iovec __user *vec,
101862306a36Sopenharmony_ci			  unsigned long vlen, loff_t pos, rwf_t flags)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	struct fd f;
102162306a36Sopenharmony_ci	ssize_t ret = -EBADF;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (pos < 0)
102462306a36Sopenharmony_ci		return -EINVAL;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	f = fdget(fd);
102762306a36Sopenharmony_ci	if (f.file) {
102862306a36Sopenharmony_ci		ret = -ESPIPE;
102962306a36Sopenharmony_ci		if (f.file->f_mode & FMODE_PWRITE)
103062306a36Sopenharmony_ci			ret = vfs_writev(f.file, vec, vlen, &pos, flags);
103162306a36Sopenharmony_ci		fdput(f);
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (ret > 0)
103562306a36Sopenharmony_ci		add_wchar(current, ret);
103662306a36Sopenharmony_ci	inc_syscw(current);
103762306a36Sopenharmony_ci	return ret;
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ciSYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
104162306a36Sopenharmony_ci		unsigned long, vlen)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	return do_readv(fd, vec, vlen, 0);
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ciSYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
104762306a36Sopenharmony_ci		unsigned long, vlen)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	return do_writev(fd, vec, vlen, 0);
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ciSYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec,
105362306a36Sopenharmony_ci		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	loff_t pos = pos_from_hilo(pos_h, pos_l);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	return do_preadv(fd, vec, vlen, pos, 0);
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ciSYSCALL_DEFINE6(preadv2, unsigned long, fd, const struct iovec __user *, vec,
106162306a36Sopenharmony_ci		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h,
106262306a36Sopenharmony_ci		rwf_t, flags)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	loff_t pos = pos_from_hilo(pos_h, pos_l);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if (pos == -1)
106762306a36Sopenharmony_ci		return do_readv(fd, vec, vlen, flags);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	return do_preadv(fd, vec, vlen, pos, flags);
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ciSYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec,
107362306a36Sopenharmony_ci		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	loff_t pos = pos_from_hilo(pos_h, pos_l);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	return do_pwritev(fd, vec, vlen, pos, 0);
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ciSYSCALL_DEFINE6(pwritev2, unsigned long, fd, const struct iovec __user *, vec,
108162306a36Sopenharmony_ci		unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h,
108262306a36Sopenharmony_ci		rwf_t, flags)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	loff_t pos = pos_from_hilo(pos_h, pos_l);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (pos == -1)
108762306a36Sopenharmony_ci		return do_writev(fd, vec, vlen, flags);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	return do_pwritev(fd, vec, vlen, pos, flags);
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci/*
109362306a36Sopenharmony_ci * Various compat syscalls.  Note that they all pretend to take a native
109462306a36Sopenharmony_ci * iovec - import_iovec will properly treat those as compat_iovecs based on
109562306a36Sopenharmony_ci * in_compat_syscall().
109662306a36Sopenharmony_ci */
109762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
109862306a36Sopenharmony_ci#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64
109962306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
110062306a36Sopenharmony_ci		const struct iovec __user *, vec,
110162306a36Sopenharmony_ci		unsigned long, vlen, loff_t, pos)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	return do_preadv(fd, vec, vlen, pos, 0);
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci#endif
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd,
110862306a36Sopenharmony_ci		const struct iovec __user *, vec,
110962306a36Sopenharmony_ci		compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	return do_preadv(fd, vec, vlen, pos, 0);
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64V2
111762306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(preadv64v2, unsigned long, fd,
111862306a36Sopenharmony_ci		const struct iovec __user *, vec,
111962306a36Sopenharmony_ci		unsigned long, vlen, loff_t, pos, rwf_t, flags)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	if (pos == -1)
112262306a36Sopenharmony_ci		return do_readv(fd, vec, vlen, flags);
112362306a36Sopenharmony_ci	return do_preadv(fd, vec, vlen, pos, flags);
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci#endif
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(preadv2, compat_ulong_t, fd,
112862306a36Sopenharmony_ci		const struct iovec __user *, vec,
112962306a36Sopenharmony_ci		compat_ulong_t, vlen, u32, pos_low, u32, pos_high,
113062306a36Sopenharmony_ci		rwf_t, flags)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (pos == -1)
113562306a36Sopenharmony_ci		return do_readv(fd, vec, vlen, flags);
113662306a36Sopenharmony_ci	return do_preadv(fd, vec, vlen, pos, flags);
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64
114062306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
114162306a36Sopenharmony_ci		const struct iovec __user *, vec,
114262306a36Sopenharmony_ci		unsigned long, vlen, loff_t, pos)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	return do_pwritev(fd, vec, vlen, pos, 0);
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci#endif
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd,
114962306a36Sopenharmony_ci		const struct iovec __user *,vec,
115062306a36Sopenharmony_ci		compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	return do_pwritev(fd, vec, vlen, pos, 0);
115562306a36Sopenharmony_ci}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64V2
115862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(pwritev64v2, unsigned long, fd,
115962306a36Sopenharmony_ci		const struct iovec __user *, vec,
116062306a36Sopenharmony_ci		unsigned long, vlen, loff_t, pos, rwf_t, flags)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	if (pos == -1)
116362306a36Sopenharmony_ci		return do_writev(fd, vec, vlen, flags);
116462306a36Sopenharmony_ci	return do_pwritev(fd, vec, vlen, pos, flags);
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci#endif
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(pwritev2, compat_ulong_t, fd,
116962306a36Sopenharmony_ci		const struct iovec __user *,vec,
117062306a36Sopenharmony_ci		compat_ulong_t, vlen, u32, pos_low, u32, pos_high, rwf_t, flags)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	loff_t pos = ((loff_t)pos_high << 32) | pos_low;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	if (pos == -1)
117562306a36Sopenharmony_ci		return do_writev(fd, vec, vlen, flags);
117662306a36Sopenharmony_ci	return do_pwritev(fd, vec, vlen, pos, flags);
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci#endif /* CONFIG_COMPAT */
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
118162306a36Sopenharmony_ci		  	   size_t count, loff_t max)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	struct fd in, out;
118462306a36Sopenharmony_ci	struct inode *in_inode, *out_inode;
118562306a36Sopenharmony_ci	struct pipe_inode_info *opipe;
118662306a36Sopenharmony_ci	loff_t pos;
118762306a36Sopenharmony_ci	loff_t out_pos;
118862306a36Sopenharmony_ci	ssize_t retval;
118962306a36Sopenharmony_ci	int fl;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	/*
119262306a36Sopenharmony_ci	 * Get input file, and verify that it is ok..
119362306a36Sopenharmony_ci	 */
119462306a36Sopenharmony_ci	retval = -EBADF;
119562306a36Sopenharmony_ci	in = fdget(in_fd);
119662306a36Sopenharmony_ci	if (!in.file)
119762306a36Sopenharmony_ci		goto out;
119862306a36Sopenharmony_ci	if (!(in.file->f_mode & FMODE_READ))
119962306a36Sopenharmony_ci		goto fput_in;
120062306a36Sopenharmony_ci	retval = -ESPIPE;
120162306a36Sopenharmony_ci	if (!ppos) {
120262306a36Sopenharmony_ci		pos = in.file->f_pos;
120362306a36Sopenharmony_ci	} else {
120462306a36Sopenharmony_ci		pos = *ppos;
120562306a36Sopenharmony_ci		if (!(in.file->f_mode & FMODE_PREAD))
120662306a36Sopenharmony_ci			goto fput_in;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci	retval = rw_verify_area(READ, in.file, &pos, count);
120962306a36Sopenharmony_ci	if (retval < 0)
121062306a36Sopenharmony_ci		goto fput_in;
121162306a36Sopenharmony_ci	if (count > MAX_RW_COUNT)
121262306a36Sopenharmony_ci		count =  MAX_RW_COUNT;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/*
121562306a36Sopenharmony_ci	 * Get output file, and verify that it is ok..
121662306a36Sopenharmony_ci	 */
121762306a36Sopenharmony_ci	retval = -EBADF;
121862306a36Sopenharmony_ci	out = fdget(out_fd);
121962306a36Sopenharmony_ci	if (!out.file)
122062306a36Sopenharmony_ci		goto fput_in;
122162306a36Sopenharmony_ci	if (!(out.file->f_mode & FMODE_WRITE))
122262306a36Sopenharmony_ci		goto fput_out;
122362306a36Sopenharmony_ci	in_inode = file_inode(in.file);
122462306a36Sopenharmony_ci	out_inode = file_inode(out.file);
122562306a36Sopenharmony_ci	out_pos = out.file->f_pos;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	if (!max)
122862306a36Sopenharmony_ci		max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	if (unlikely(pos + count > max)) {
123162306a36Sopenharmony_ci		retval = -EOVERFLOW;
123262306a36Sopenharmony_ci		if (pos >= max)
123362306a36Sopenharmony_ci			goto fput_out;
123462306a36Sopenharmony_ci		count = max - pos;
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	fl = 0;
123862306a36Sopenharmony_ci#if 0
123962306a36Sopenharmony_ci	/*
124062306a36Sopenharmony_ci	 * We need to debate whether we can enable this or not. The
124162306a36Sopenharmony_ci	 * man page documents EAGAIN return for the output at least,
124262306a36Sopenharmony_ci	 * and the application is arguably buggy if it doesn't expect
124362306a36Sopenharmony_ci	 * EAGAIN on a non-blocking file descriptor.
124462306a36Sopenharmony_ci	 */
124562306a36Sopenharmony_ci	if (in.file->f_flags & O_NONBLOCK)
124662306a36Sopenharmony_ci		fl = SPLICE_F_NONBLOCK;
124762306a36Sopenharmony_ci#endif
124862306a36Sopenharmony_ci	opipe = get_pipe_info(out.file, true);
124962306a36Sopenharmony_ci	if (!opipe) {
125062306a36Sopenharmony_ci		retval = rw_verify_area(WRITE, out.file, &out_pos, count);
125162306a36Sopenharmony_ci		if (retval < 0)
125262306a36Sopenharmony_ci			goto fput_out;
125362306a36Sopenharmony_ci		file_start_write(out.file);
125462306a36Sopenharmony_ci		retval = do_splice_direct(in.file, &pos, out.file, &out_pos,
125562306a36Sopenharmony_ci					  count, fl);
125662306a36Sopenharmony_ci		file_end_write(out.file);
125762306a36Sopenharmony_ci	} else {
125862306a36Sopenharmony_ci		if (out.file->f_flags & O_NONBLOCK)
125962306a36Sopenharmony_ci			fl |= SPLICE_F_NONBLOCK;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci		retval = splice_file_to_pipe(in.file, opipe, &pos, count, fl);
126262306a36Sopenharmony_ci	}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	if (retval > 0) {
126562306a36Sopenharmony_ci		add_rchar(current, retval);
126662306a36Sopenharmony_ci		add_wchar(current, retval);
126762306a36Sopenharmony_ci		fsnotify_access(in.file);
126862306a36Sopenharmony_ci		fsnotify_modify(out.file);
126962306a36Sopenharmony_ci		out.file->f_pos = out_pos;
127062306a36Sopenharmony_ci		if (ppos)
127162306a36Sopenharmony_ci			*ppos = pos;
127262306a36Sopenharmony_ci		else
127362306a36Sopenharmony_ci			in.file->f_pos = pos;
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	inc_syscr(current);
127762306a36Sopenharmony_ci	inc_syscw(current);
127862306a36Sopenharmony_ci	if (pos > max)
127962306a36Sopenharmony_ci		retval = -EOVERFLOW;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cifput_out:
128262306a36Sopenharmony_ci	fdput(out);
128362306a36Sopenharmony_cifput_in:
128462306a36Sopenharmony_ci	fdput(in);
128562306a36Sopenharmony_ciout:
128662306a36Sopenharmony_ci	return retval;
128762306a36Sopenharmony_ci}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ciSYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	loff_t pos;
129262306a36Sopenharmony_ci	off_t off;
129362306a36Sopenharmony_ci	ssize_t ret;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	if (offset) {
129662306a36Sopenharmony_ci		if (unlikely(get_user(off, offset)))
129762306a36Sopenharmony_ci			return -EFAULT;
129862306a36Sopenharmony_ci		pos = off;
129962306a36Sopenharmony_ci		ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
130062306a36Sopenharmony_ci		if (unlikely(put_user(pos, offset)))
130162306a36Sopenharmony_ci			return -EFAULT;
130262306a36Sopenharmony_ci		return ret;
130362306a36Sopenharmony_ci	}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return do_sendfile(out_fd, in_fd, NULL, count, 0);
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ciSYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	loff_t pos;
131162306a36Sopenharmony_ci	ssize_t ret;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (offset) {
131462306a36Sopenharmony_ci		if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
131562306a36Sopenharmony_ci			return -EFAULT;
131662306a36Sopenharmony_ci		ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
131762306a36Sopenharmony_ci		if (unlikely(put_user(pos, offset)))
131862306a36Sopenharmony_ci			return -EFAULT;
131962306a36Sopenharmony_ci		return ret;
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	return do_sendfile(out_fd, in_fd, NULL, count, 0);
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
132662306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd,
132762306a36Sopenharmony_ci		compat_off_t __user *, offset, compat_size_t, count)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	loff_t pos;
133062306a36Sopenharmony_ci	off_t off;
133162306a36Sopenharmony_ci	ssize_t ret;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (offset) {
133462306a36Sopenharmony_ci		if (unlikely(get_user(off, offset)))
133562306a36Sopenharmony_ci			return -EFAULT;
133662306a36Sopenharmony_ci		pos = off;
133762306a36Sopenharmony_ci		ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
133862306a36Sopenharmony_ci		if (unlikely(put_user(pos, offset)))
133962306a36Sopenharmony_ci			return -EFAULT;
134062306a36Sopenharmony_ci		return ret;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	return do_sendfile(out_fd, in_fd, NULL, count, 0);
134462306a36Sopenharmony_ci}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ciCOMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd,
134762306a36Sopenharmony_ci		compat_loff_t __user *, offset, compat_size_t, count)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	loff_t pos;
135062306a36Sopenharmony_ci	ssize_t ret;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (offset) {
135362306a36Sopenharmony_ci		if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
135462306a36Sopenharmony_ci			return -EFAULT;
135562306a36Sopenharmony_ci		ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
135662306a36Sopenharmony_ci		if (unlikely(put_user(pos, offset)))
135762306a36Sopenharmony_ci			return -EFAULT;
135862306a36Sopenharmony_ci		return ret;
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	return do_sendfile(out_fd, in_fd, NULL, count, 0);
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci#endif
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci/**
136662306a36Sopenharmony_ci * generic_copy_file_range - copy data between two files
136762306a36Sopenharmony_ci * @file_in:	file structure to read from
136862306a36Sopenharmony_ci * @pos_in:	file offset to read from
136962306a36Sopenharmony_ci * @file_out:	file structure to write data to
137062306a36Sopenharmony_ci * @pos_out:	file offset to write data to
137162306a36Sopenharmony_ci * @len:	amount of data to copy
137262306a36Sopenharmony_ci * @flags:	copy flags
137362306a36Sopenharmony_ci *
137462306a36Sopenharmony_ci * This is a generic filesystem helper to copy data from one file to another.
137562306a36Sopenharmony_ci * It has no constraints on the source or destination file owners - the files
137662306a36Sopenharmony_ci * can belong to different superblocks and different filesystem types. Short
137762306a36Sopenharmony_ci * copies are allowed.
137862306a36Sopenharmony_ci *
137962306a36Sopenharmony_ci * This should be called from the @file_out filesystem, as per the
138062306a36Sopenharmony_ci * ->copy_file_range() method.
138162306a36Sopenharmony_ci *
138262306a36Sopenharmony_ci * Returns the number of bytes copied or a negative error indicating the
138362306a36Sopenharmony_ci * failure.
138462306a36Sopenharmony_ci */
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_cissize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
138762306a36Sopenharmony_ci				struct file *file_out, loff_t pos_out,
138862306a36Sopenharmony_ci				size_t len, unsigned int flags)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	lockdep_assert(sb_write_started(file_inode(file_out)->i_sb));
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	return do_splice_direct(file_in, &pos_in, file_out, &pos_out,
139362306a36Sopenharmony_ci				len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ciEXPORT_SYMBOL(generic_copy_file_range);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci/*
139862306a36Sopenharmony_ci * Performs necessary checks before doing a file copy
139962306a36Sopenharmony_ci *
140062306a36Sopenharmony_ci * Can adjust amount of bytes to copy via @req_count argument.
140162306a36Sopenharmony_ci * Returns appropriate error code that caller should return or
140262306a36Sopenharmony_ci * zero in case the copy should be allowed.
140362306a36Sopenharmony_ci */
140462306a36Sopenharmony_cistatic int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
140562306a36Sopenharmony_ci				    struct file *file_out, loff_t pos_out,
140662306a36Sopenharmony_ci				    size_t *req_count, unsigned int flags)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	struct inode *inode_in = file_inode(file_in);
140962306a36Sopenharmony_ci	struct inode *inode_out = file_inode(file_out);
141062306a36Sopenharmony_ci	uint64_t count = *req_count;
141162306a36Sopenharmony_ci	loff_t size_in;
141262306a36Sopenharmony_ci	int ret;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	ret = generic_file_rw_checks(file_in, file_out);
141562306a36Sopenharmony_ci	if (ret)
141662306a36Sopenharmony_ci		return ret;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	/*
141962306a36Sopenharmony_ci	 * We allow some filesystems to handle cross sb copy, but passing
142062306a36Sopenharmony_ci	 * a file of the wrong filesystem type to filesystem driver can result
142162306a36Sopenharmony_ci	 * in an attempt to dereference the wrong type of ->private_data, so
142262306a36Sopenharmony_ci	 * avoid doing that until we really have a good reason.
142362306a36Sopenharmony_ci	 *
142462306a36Sopenharmony_ci	 * nfs and cifs define several different file_system_type structures
142562306a36Sopenharmony_ci	 * and several different sets of file_operations, but they all end up
142662306a36Sopenharmony_ci	 * using the same ->copy_file_range() function pointer.
142762306a36Sopenharmony_ci	 */
142862306a36Sopenharmony_ci	if (flags & COPY_FILE_SPLICE) {
142962306a36Sopenharmony_ci		/* cross sb splice is allowed */
143062306a36Sopenharmony_ci	} else if (file_out->f_op->copy_file_range) {
143162306a36Sopenharmony_ci		if (file_in->f_op->copy_file_range !=
143262306a36Sopenharmony_ci		    file_out->f_op->copy_file_range)
143362306a36Sopenharmony_ci			return -EXDEV;
143462306a36Sopenharmony_ci	} else if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb) {
143562306a36Sopenharmony_ci		return -EXDEV;
143662306a36Sopenharmony_ci	}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	/* Don't touch certain kinds of inodes */
143962306a36Sopenharmony_ci	if (IS_IMMUTABLE(inode_out))
144062306a36Sopenharmony_ci		return -EPERM;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
144362306a36Sopenharmony_ci		return -ETXTBSY;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	/* Ensure offsets don't wrap. */
144662306a36Sopenharmony_ci	if (pos_in + count < pos_in || pos_out + count < pos_out)
144762306a36Sopenharmony_ci		return -EOVERFLOW;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	/* Shorten the copy to EOF */
145062306a36Sopenharmony_ci	size_in = i_size_read(inode_in);
145162306a36Sopenharmony_ci	if (pos_in >= size_in)
145262306a36Sopenharmony_ci		count = 0;
145362306a36Sopenharmony_ci	else
145462306a36Sopenharmony_ci		count = min(count, size_in - (uint64_t)pos_in);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	ret = generic_write_check_limits(file_out, pos_out, &count);
145762306a36Sopenharmony_ci	if (ret)
145862306a36Sopenharmony_ci		return ret;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/* Don't allow overlapped copying within the same file. */
146162306a36Sopenharmony_ci	if (inode_in == inode_out &&
146262306a36Sopenharmony_ci	    pos_out + count > pos_in &&
146362306a36Sopenharmony_ci	    pos_out < pos_in + count)
146462306a36Sopenharmony_ci		return -EINVAL;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	*req_count = count;
146762306a36Sopenharmony_ci	return 0;
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci/*
147162306a36Sopenharmony_ci * copy_file_range() differs from regular file read and write in that it
147262306a36Sopenharmony_ci * specifically allows return partial success.  When it does so is up to
147362306a36Sopenharmony_ci * the copy_file_range method.
147462306a36Sopenharmony_ci */
147562306a36Sopenharmony_cissize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
147662306a36Sopenharmony_ci			    struct file *file_out, loff_t pos_out,
147762306a36Sopenharmony_ci			    size_t len, unsigned int flags)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	ssize_t ret;
148062306a36Sopenharmony_ci	bool splice = flags & COPY_FILE_SPLICE;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if (flags & ~COPY_FILE_SPLICE)
148362306a36Sopenharmony_ci		return -EINVAL;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
148662306a36Sopenharmony_ci				       flags);
148762306a36Sopenharmony_ci	if (unlikely(ret))
148862306a36Sopenharmony_ci		return ret;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	ret = rw_verify_area(READ, file_in, &pos_in, len);
149162306a36Sopenharmony_ci	if (unlikely(ret))
149262306a36Sopenharmony_ci		return ret;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	ret = rw_verify_area(WRITE, file_out, &pos_out, len);
149562306a36Sopenharmony_ci	if (unlikely(ret))
149662306a36Sopenharmony_ci		return ret;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	if (len == 0)
149962306a36Sopenharmony_ci		return 0;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	file_start_write(file_out);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	/*
150462306a36Sopenharmony_ci	 * Cloning is supported by more file systems, so we implement copy on
150562306a36Sopenharmony_ci	 * same sb using clone, but for filesystems where both clone and copy
150662306a36Sopenharmony_ci	 * are supported (e.g. nfs,cifs), we only call the copy method.
150762306a36Sopenharmony_ci	 */
150862306a36Sopenharmony_ci	if (!splice && file_out->f_op->copy_file_range) {
150962306a36Sopenharmony_ci		ret = file_out->f_op->copy_file_range(file_in, pos_in,
151062306a36Sopenharmony_ci						      file_out, pos_out,
151162306a36Sopenharmony_ci						      len, flags);
151262306a36Sopenharmony_ci		goto done;
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	if (!splice && file_in->f_op->remap_file_range &&
151662306a36Sopenharmony_ci	    file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
151762306a36Sopenharmony_ci		ret = file_in->f_op->remap_file_range(file_in, pos_in,
151862306a36Sopenharmony_ci				file_out, pos_out,
151962306a36Sopenharmony_ci				min_t(loff_t, MAX_RW_COUNT, len),
152062306a36Sopenharmony_ci				REMAP_FILE_CAN_SHORTEN);
152162306a36Sopenharmony_ci		if (ret > 0)
152262306a36Sopenharmony_ci			goto done;
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	/*
152662306a36Sopenharmony_ci	 * We can get here for same sb copy of filesystems that do not implement
152762306a36Sopenharmony_ci	 * ->copy_file_range() in case filesystem does not support clone or in
152862306a36Sopenharmony_ci	 * case filesystem supports clone but rejected the clone request (e.g.
152962306a36Sopenharmony_ci	 * because it was not block aligned).
153062306a36Sopenharmony_ci	 *
153162306a36Sopenharmony_ci	 * In both cases, fall back to kernel copy so we are able to maintain a
153262306a36Sopenharmony_ci	 * consistent story about which filesystems support copy_file_range()
153362306a36Sopenharmony_ci	 * and which filesystems do not, that will allow userspace tools to
153462306a36Sopenharmony_ci	 * make consistent desicions w.r.t using copy_file_range().
153562306a36Sopenharmony_ci	 *
153662306a36Sopenharmony_ci	 * We also get here if caller (e.g. nfsd) requested COPY_FILE_SPLICE.
153762306a36Sopenharmony_ci	 */
153862306a36Sopenharmony_ci	ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
153962306a36Sopenharmony_ci				      flags);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cidone:
154262306a36Sopenharmony_ci	if (ret > 0) {
154362306a36Sopenharmony_ci		fsnotify_access(file_in);
154462306a36Sopenharmony_ci		add_rchar(current, ret);
154562306a36Sopenharmony_ci		fsnotify_modify(file_out);
154662306a36Sopenharmony_ci		add_wchar(current, ret);
154762306a36Sopenharmony_ci	}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	inc_syscr(current);
155062306a36Sopenharmony_ci	inc_syscw(current);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	file_end_write(file_out);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	return ret;
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_copy_file_range);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ciSYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
155962306a36Sopenharmony_ci		int, fd_out, loff_t __user *, off_out,
156062306a36Sopenharmony_ci		size_t, len, unsigned int, flags)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	loff_t pos_in;
156362306a36Sopenharmony_ci	loff_t pos_out;
156462306a36Sopenharmony_ci	struct fd f_in;
156562306a36Sopenharmony_ci	struct fd f_out;
156662306a36Sopenharmony_ci	ssize_t ret = -EBADF;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	f_in = fdget(fd_in);
156962306a36Sopenharmony_ci	if (!f_in.file)
157062306a36Sopenharmony_ci		goto out2;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	f_out = fdget(fd_out);
157362306a36Sopenharmony_ci	if (!f_out.file)
157462306a36Sopenharmony_ci		goto out1;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	ret = -EFAULT;
157762306a36Sopenharmony_ci	if (off_in) {
157862306a36Sopenharmony_ci		if (copy_from_user(&pos_in, off_in, sizeof(loff_t)))
157962306a36Sopenharmony_ci			goto out;
158062306a36Sopenharmony_ci	} else {
158162306a36Sopenharmony_ci		pos_in = f_in.file->f_pos;
158262306a36Sopenharmony_ci	}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	if (off_out) {
158562306a36Sopenharmony_ci		if (copy_from_user(&pos_out, off_out, sizeof(loff_t)))
158662306a36Sopenharmony_ci			goto out;
158762306a36Sopenharmony_ci	} else {
158862306a36Sopenharmony_ci		pos_out = f_out.file->f_pos;
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	ret = -EINVAL;
159262306a36Sopenharmony_ci	if (flags != 0)
159362306a36Sopenharmony_ci		goto out;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
159662306a36Sopenharmony_ci				  flags);
159762306a36Sopenharmony_ci	if (ret > 0) {
159862306a36Sopenharmony_ci		pos_in += ret;
159962306a36Sopenharmony_ci		pos_out += ret;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci		if (off_in) {
160262306a36Sopenharmony_ci			if (copy_to_user(off_in, &pos_in, sizeof(loff_t)))
160362306a36Sopenharmony_ci				ret = -EFAULT;
160462306a36Sopenharmony_ci		} else {
160562306a36Sopenharmony_ci			f_in.file->f_pos = pos_in;
160662306a36Sopenharmony_ci		}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		if (off_out) {
160962306a36Sopenharmony_ci			if (copy_to_user(off_out, &pos_out, sizeof(loff_t)))
161062306a36Sopenharmony_ci				ret = -EFAULT;
161162306a36Sopenharmony_ci		} else {
161262306a36Sopenharmony_ci			f_out.file->f_pos = pos_out;
161362306a36Sopenharmony_ci		}
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ciout:
161762306a36Sopenharmony_ci	fdput(f_out);
161862306a36Sopenharmony_ciout1:
161962306a36Sopenharmony_ci	fdput(f_in);
162062306a36Sopenharmony_ciout2:
162162306a36Sopenharmony_ci	return ret;
162262306a36Sopenharmony_ci}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci/*
162562306a36Sopenharmony_ci * Don't operate on ranges the page cache doesn't support, and don't exceed the
162662306a36Sopenharmony_ci * LFS limits.  If pos is under the limit it becomes a short access.  If it
162762306a36Sopenharmony_ci * exceeds the limit we return -EFBIG.
162862306a36Sopenharmony_ci */
162962306a36Sopenharmony_ciint generic_write_check_limits(struct file *file, loff_t pos, loff_t *count)
163062306a36Sopenharmony_ci{
163162306a36Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
163262306a36Sopenharmony_ci	loff_t max_size = inode->i_sb->s_maxbytes;
163362306a36Sopenharmony_ci	loff_t limit = rlimit(RLIMIT_FSIZE);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	if (limit != RLIM_INFINITY) {
163662306a36Sopenharmony_ci		if (pos >= limit) {
163762306a36Sopenharmony_ci			send_sig(SIGXFSZ, current, 0);
163862306a36Sopenharmony_ci			return -EFBIG;
163962306a36Sopenharmony_ci		}
164062306a36Sopenharmony_ci		*count = min(*count, limit - pos);
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	if (!(file->f_flags & O_LARGEFILE))
164462306a36Sopenharmony_ci		max_size = MAX_NON_LFS;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	if (unlikely(pos >= max_size))
164762306a36Sopenharmony_ci		return -EFBIG;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	*count = min(*count, max_size - pos);
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	return 0;
165262306a36Sopenharmony_ci}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci/* Like generic_write_checks(), but takes size of write instead of iter. */
165562306a36Sopenharmony_ciint generic_write_checks_count(struct kiocb *iocb, loff_t *count)
165662306a36Sopenharmony_ci{
165762306a36Sopenharmony_ci	struct file *file = iocb->ki_filp;
165862306a36Sopenharmony_ci	struct inode *inode = file->f_mapping->host;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	if (IS_SWAPFILE(inode))
166162306a36Sopenharmony_ci		return -ETXTBSY;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	if (!*count)
166462306a36Sopenharmony_ci		return 0;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	if (iocb->ki_flags & IOCB_APPEND)
166762306a36Sopenharmony_ci		iocb->ki_pos = i_size_read(inode);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if ((iocb->ki_flags & IOCB_NOWAIT) &&
167062306a36Sopenharmony_ci	    !((iocb->ki_flags & IOCB_DIRECT) ||
167162306a36Sopenharmony_ci	      (file->f_mode & FMODE_BUF_WASYNC)))
167262306a36Sopenharmony_ci		return -EINVAL;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	return generic_write_check_limits(iocb->ki_filp, iocb->ki_pos, count);
167562306a36Sopenharmony_ci}
167662306a36Sopenharmony_ciEXPORT_SYMBOL(generic_write_checks_count);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci/*
167962306a36Sopenharmony_ci * Performs necessary checks before doing a write
168062306a36Sopenharmony_ci *
168162306a36Sopenharmony_ci * Can adjust writing position or amount of bytes to write.
168262306a36Sopenharmony_ci * Returns appropriate error code that caller should return or
168362306a36Sopenharmony_ci * zero in case that write should be allowed.
168462306a36Sopenharmony_ci */
168562306a36Sopenharmony_cissize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
168662306a36Sopenharmony_ci{
168762306a36Sopenharmony_ci	loff_t count = iov_iter_count(from);
168862306a36Sopenharmony_ci	int ret;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	ret = generic_write_checks_count(iocb, &count);
169162306a36Sopenharmony_ci	if (ret)
169262306a36Sopenharmony_ci		return ret;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	iov_iter_truncate(from, count);
169562306a36Sopenharmony_ci	return iov_iter_count(from);
169662306a36Sopenharmony_ci}
169762306a36Sopenharmony_ciEXPORT_SYMBOL(generic_write_checks);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci/*
170062306a36Sopenharmony_ci * Performs common checks before doing a file copy/clone
170162306a36Sopenharmony_ci * from @file_in to @file_out.
170262306a36Sopenharmony_ci */
170362306a36Sopenharmony_ciint generic_file_rw_checks(struct file *file_in, struct file *file_out)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	struct inode *inode_in = file_inode(file_in);
170662306a36Sopenharmony_ci	struct inode *inode_out = file_inode(file_out);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	/* Don't copy dirs, pipes, sockets... */
170962306a36Sopenharmony_ci	if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
171062306a36Sopenharmony_ci		return -EISDIR;
171162306a36Sopenharmony_ci	if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
171262306a36Sopenharmony_ci		return -EINVAL;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	if (!(file_in->f_mode & FMODE_READ) ||
171562306a36Sopenharmony_ci	    !(file_out->f_mode & FMODE_WRITE) ||
171662306a36Sopenharmony_ci	    (file_out->f_flags & O_APPEND))
171762306a36Sopenharmony_ci		return -EBADF;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	return 0;
172062306a36Sopenharmony_ci}
1721