xref: /openbmc/linux/fs/ioctl.c (revision 820831de)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/ioctl.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992  Linus Torvalds
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/syscalls.h>
91da177e4SLinus Torvalds #include <linux/mm.h>
1016f7e0feSRandy Dunlap #include <linux/capability.h>
112952db0fSArnd Bergmann #include <linux/compat.h>
121da177e4SLinus Torvalds #include <linux/file.h>
131da177e4SLinus Torvalds #include <linux/fs.h>
141da177e4SLinus Torvalds #include <linux/security.h>
15630d9c47SPaul Gortmaker #include <linux/export.h>
16c9845ff1SErez Zadok #include <linux/uaccess.h>
1768c9d702SJosef Bacik #include <linux/writeback.h>
1868c9d702SJosef Bacik #include <linux/buffer_head.h>
193e63cbb1SAnkit Jain #include <linux/falloc.h>
20f361bf4aSIngo Molnar #include <linux/sched/signal.h>
2110c5db28SChristoph Hellwig #include <linux/fiemap.h>
224c5b4799SMiklos Szeredi #include <linux/mount.h>
234c5b4799SMiklos Szeredi #include <linux/fscrypt.h>
244c5b4799SMiklos Szeredi #include <linux/fileattr.h>
25f361bf4aSIngo Molnar 
2666cf191fSAl Viro #include "internal.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <asm/ioctls.h>
291da177e4SLinus Torvalds 
30c4b929b8SMark Fasheh /* So that the fiemap access checks can't overflow on 32 bit machines. */
31c4b929b8SMark Fasheh #define FIEMAP_MAX_EXTENTS	(UINT_MAX / sizeof(struct fiemap_extent))
32c4b929b8SMark Fasheh 
33deb21db7SErez Zadok /**
34deb21db7SErez Zadok  * vfs_ioctl - call filesystem specific ioctl methods
35f6a4c8bdSChristoph Hellwig  * @filp:	open file to invoke ioctl method on
36f6a4c8bdSChristoph Hellwig  * @cmd:	ioctl command to execute
37f6a4c8bdSChristoph Hellwig  * @arg:	command-specific argument for ioctl
38deb21db7SErez Zadok  *
39deb21db7SErez Zadok  * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise
40deb21db7SErez Zadok  * returns -ENOTTY.
41deb21db7SErez Zadok  *
42deb21db7SErez Zadok  * Returns 0 on success, -errno on error.
43deb21db7SErez Zadok  */
vfs_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)4466cf191fSAl Viro long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds 	int error = -ENOTTY;
471da177e4SLinus Torvalds 
4872c2d531SAl Viro 	if (!filp->f_op->unlocked_ioctl)
491da177e4SLinus Torvalds 		goto out;
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds 	error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
521da177e4SLinus Torvalds 	if (error == -ENOIOCTLCMD)
5307d106d0SLinus Torvalds 		error = -ENOTTY;
541da177e4SLinus Torvalds  out:
551da177e4SLinus Torvalds 	return error;
561da177e4SLinus Torvalds }
579df6702aSMiklos Szeredi EXPORT_SYMBOL(vfs_ioctl);
581da177e4SLinus Torvalds 
ioctl_fibmap(struct file * filp,int __user * p)59aa81a7c7SErez Zadok static int ioctl_fibmap(struct file *filp, int __user *p)
601da177e4SLinus Torvalds {
610d89fdaeSCarlos Maiolino 	struct inode *inode = file_inode(filp);
62b75dfde1SRitesh Harjani 	struct super_block *sb = inode->i_sb;
630d89fdaeSCarlos Maiolino 	int error, ur_block;
640d89fdaeSCarlos Maiolino 	sector_t block;
65aa81a7c7SErez Zadok 
661da177e4SLinus Torvalds 	if (!capable(CAP_SYS_RAWIO))
671da177e4SLinus Torvalds 		return -EPERM;
680d89fdaeSCarlos Maiolino 
690d89fdaeSCarlos Maiolino 	error = get_user(ur_block, p);
700d89fdaeSCarlos Maiolino 	if (error)
710d89fdaeSCarlos Maiolino 		return error;
720d89fdaeSCarlos Maiolino 
73324282c0SCarlos Maiolino 	if (ur_block < 0)
74324282c0SCarlos Maiolino 		return -EINVAL;
75324282c0SCarlos Maiolino 
760d89fdaeSCarlos Maiolino 	block = ur_block;
770d89fdaeSCarlos Maiolino 	error = bmap(inode, &block);
780d89fdaeSCarlos Maiolino 
79b75dfde1SRitesh Harjani 	if (block > INT_MAX) {
80b75dfde1SRitesh Harjani 		error = -ERANGE;
81b75dfde1SRitesh Harjani 		pr_warn_ratelimited("[%s/%d] FS: %s File: %pD4 would truncate fibmap result\n",
82b75dfde1SRitesh Harjani 				    current->comm, task_pid_nr(current),
83b75dfde1SRitesh Harjani 				    sb->s_id, filp);
84b75dfde1SRitesh Harjani 	}
85b75dfde1SRitesh Harjani 
860d89fdaeSCarlos Maiolino 	if (error)
870d89fdaeSCarlos Maiolino 		ur_block = 0;
880d89fdaeSCarlos Maiolino 	else
890d89fdaeSCarlos Maiolino 		ur_block = block;
900d89fdaeSCarlos Maiolino 
910d89fdaeSCarlos Maiolino 	if (put_user(ur_block, p))
920d89fdaeSCarlos Maiolino 		error = -EFAULT;
930d89fdaeSCarlos Maiolino 
940d89fdaeSCarlos Maiolino 	return error;
951da177e4SLinus Torvalds }
96aa81a7c7SErez Zadok 
97c4b929b8SMark Fasheh /**
98c4b929b8SMark Fasheh  * fiemap_fill_next_extent - Fiemap helper function
99c4b929b8SMark Fasheh  * @fieinfo:	Fiemap context passed into ->fiemap
100c4b929b8SMark Fasheh  * @logical:	Extent logical start offset, in bytes
101c4b929b8SMark Fasheh  * @phys:	Extent physical start offset, in bytes
102c4b929b8SMark Fasheh  * @len:	Extent length, in bytes
103c4b929b8SMark Fasheh  * @flags:	FIEMAP_EXTENT flags that describe this extent
104c4b929b8SMark Fasheh  *
105c4b929b8SMark Fasheh  * Called from file system ->fiemap callback. Will populate extent
106c4b929b8SMark Fasheh  * info as passed in via arguments and copy to user memory. On
107c4b929b8SMark Fasheh  * success, extent count on fieinfo is incremented.
108c4b929b8SMark Fasheh  *
109c4b929b8SMark Fasheh  * Returns 0 on success, -errno on error, 1 if this was the last
110c4b929b8SMark Fasheh  * extent that will fit in user array.
111c4b929b8SMark Fasheh  */
fiemap_fill_next_extent(struct fiemap_extent_info * fieinfo,u64 logical,u64 phys,u64 len,u32 flags)112c4b929b8SMark Fasheh int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
113c4b929b8SMark Fasheh 			    u64 phys, u64 len, u32 flags)
114c4b929b8SMark Fasheh {
115c4b929b8SMark Fasheh 	struct fiemap_extent extent;
116ecf5632dSNamhyung Kim 	struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
117c4b929b8SMark Fasheh 
118c4b929b8SMark Fasheh 	/* only count the extents */
119c4b929b8SMark Fasheh 	if (fieinfo->fi_extents_max == 0) {
120c4b929b8SMark Fasheh 		fieinfo->fi_extents_mapped++;
121c4b929b8SMark Fasheh 		return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
122c4b929b8SMark Fasheh 	}
123c4b929b8SMark Fasheh 
124c4b929b8SMark Fasheh 	if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
125c4b929b8SMark Fasheh 		return 1;
126c4b929b8SMark Fasheh 
12735931eb3SMatthew Wilcox (Oracle) #define SET_UNKNOWN_FLAGS	(FIEMAP_EXTENT_DELALLOC)
12835931eb3SMatthew Wilcox (Oracle) #define SET_NO_UNMOUNTED_IO_FLAGS	(FIEMAP_EXTENT_DATA_ENCRYPTED)
12935931eb3SMatthew Wilcox (Oracle) #define SET_NOT_ALIGNED_FLAGS	(FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE)
13035931eb3SMatthew Wilcox (Oracle) 
131c4b929b8SMark Fasheh 	if (flags & SET_UNKNOWN_FLAGS)
132c4b929b8SMark Fasheh 		flags |= FIEMAP_EXTENT_UNKNOWN;
133c4b929b8SMark Fasheh 	if (flags & SET_NO_UNMOUNTED_IO_FLAGS)
134c4b929b8SMark Fasheh 		flags |= FIEMAP_EXTENT_ENCODED;
135c4b929b8SMark Fasheh 	if (flags & SET_NOT_ALIGNED_FLAGS)
136c4b929b8SMark Fasheh 		flags |= FIEMAP_EXTENT_NOT_ALIGNED;
137c4b929b8SMark Fasheh 
138c4b929b8SMark Fasheh 	memset(&extent, 0, sizeof(extent));
139c4b929b8SMark Fasheh 	extent.fe_logical = logical;
140c4b929b8SMark Fasheh 	extent.fe_physical = phys;
141c4b929b8SMark Fasheh 	extent.fe_length = len;
142c4b929b8SMark Fasheh 	extent.fe_flags = flags;
143c4b929b8SMark Fasheh 
144c4b929b8SMark Fasheh 	dest += fieinfo->fi_extents_mapped;
145c4b929b8SMark Fasheh 	if (copy_to_user(dest, &extent, sizeof(extent)))
146c4b929b8SMark Fasheh 		return -EFAULT;
147c4b929b8SMark Fasheh 
148c4b929b8SMark Fasheh 	fieinfo->fi_extents_mapped++;
149c4b929b8SMark Fasheh 	if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
150c4b929b8SMark Fasheh 		return 1;
151c4b929b8SMark Fasheh 	return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
152c4b929b8SMark Fasheh }
153c4b929b8SMark Fasheh EXPORT_SYMBOL(fiemap_fill_next_extent);
154c4b929b8SMark Fasheh 
155c4b929b8SMark Fasheh /**
156cddf8a2cSChristoph Hellwig  * fiemap_prep - check validity of requested flags for fiemap
157cddf8a2cSChristoph Hellwig  * @inode:	Inode to operate on
158c4b929b8SMark Fasheh  * @fieinfo:	Fiemap context passed into ->fiemap
159cddf8a2cSChristoph Hellwig  * @start:	Start of the mapped range
160cddf8a2cSChristoph Hellwig  * @len:	Length of the mapped range, can be truncated by this function.
161cddf8a2cSChristoph Hellwig  * @supported_flags:	Set of fiemap flags that the file system understands
162c4b929b8SMark Fasheh  *
163cddf8a2cSChristoph Hellwig  * This function must be called from each ->fiemap instance to validate the
164cddf8a2cSChristoph Hellwig  * fiemap request against the file system parameters.
165c4b929b8SMark Fasheh  *
166cddf8a2cSChristoph Hellwig  * Returns 0 on success, or a negative error on failure.
167c4b929b8SMark Fasheh  */
fiemap_prep(struct inode * inode,struct fiemap_extent_info * fieinfo,u64 start,u64 * len,u32 supported_flags)168cddf8a2cSChristoph Hellwig int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
169cddf8a2cSChristoph Hellwig 		u64 start, u64 *len, u32 supported_flags)
170c4b929b8SMark Fasheh {
171cddf8a2cSChristoph Hellwig 	u64 maxbytes = inode->i_sb->s_maxbytes;
172c4b929b8SMark Fasheh 	u32 incompat_flags;
17345dd052eSChristoph Hellwig 	int ret = 0;
174c4b929b8SMark Fasheh 
175cddf8a2cSChristoph Hellwig 	if (*len == 0)
176c4b929b8SMark Fasheh 		return -EINVAL;
17749df3422SGuo Xuenan 	if (start >= maxbytes)
178c4b929b8SMark Fasheh 		return -EFBIG;
179c4b929b8SMark Fasheh 
180c4b929b8SMark Fasheh 	/*
181c4b929b8SMark Fasheh 	 * Shrink request scope to what the fs can actually handle.
182c4b929b8SMark Fasheh 	 */
183cddf8a2cSChristoph Hellwig 	if (*len > maxbytes || (maxbytes - *len) < start)
184cddf8a2cSChristoph Hellwig 		*len = maxbytes - start;
185c4b929b8SMark Fasheh 
18645dd052eSChristoph Hellwig 	supported_flags |= FIEMAP_FLAG_SYNC;
187cddf8a2cSChristoph Hellwig 	supported_flags &= FIEMAP_FLAGS_COMPAT;
188cddf8a2cSChristoph Hellwig 	incompat_flags = fieinfo->fi_flags & ~supported_flags;
189cddf8a2cSChristoph Hellwig 	if (incompat_flags) {
190cddf8a2cSChristoph Hellwig 		fieinfo->fi_flags = incompat_flags;
191cddf8a2cSChristoph Hellwig 		return -EBADR;
192cddf8a2cSChristoph Hellwig 	}
19345dd052eSChristoph Hellwig 
19445dd052eSChristoph Hellwig 	if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC)
19545dd052eSChristoph Hellwig 		ret = filemap_write_and_wait(inode->i_mapping);
19645dd052eSChristoph Hellwig 	return ret;
197c4b929b8SMark Fasheh }
198cddf8a2cSChristoph Hellwig EXPORT_SYMBOL(fiemap_prep);
199c4b929b8SMark Fasheh 
ioctl_fiemap(struct file * filp,struct fiemap __user * ufiemap)20034d3d0e6SAl Viro static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)
201c4b929b8SMark Fasheh {
202c4b929b8SMark Fasheh 	struct fiemap fiemap;
203c4b929b8SMark Fasheh 	struct fiemap_extent_info fieinfo = { 0, };
204496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
205c4b929b8SMark Fasheh 	int error;
206c4b929b8SMark Fasheh 
207c4b929b8SMark Fasheh 	if (!inode->i_op->fiemap)
208c4b929b8SMark Fasheh 		return -EOPNOTSUPP;
209c4b929b8SMark Fasheh 
210ecf5632dSNamhyung Kim 	if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap)))
211c4b929b8SMark Fasheh 		return -EFAULT;
212c4b929b8SMark Fasheh 
213c4b929b8SMark Fasheh 	if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
214c4b929b8SMark Fasheh 		return -EINVAL;
215c4b929b8SMark Fasheh 
216c4b929b8SMark Fasheh 	fieinfo.fi_flags = fiemap.fm_flags;
217c4b929b8SMark Fasheh 	fieinfo.fi_extents_max = fiemap.fm_extent_count;
218ecf5632dSNamhyung Kim 	fieinfo.fi_extents_start = ufiemap->fm_extents;
219c4b929b8SMark Fasheh 
220cddf8a2cSChristoph Hellwig 	error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start,
221cddf8a2cSChristoph Hellwig 			fiemap.fm_length);
222c7d216e8SChristoph Hellwig 
223c4b929b8SMark Fasheh 	fiemap.fm_flags = fieinfo.fi_flags;
224c4b929b8SMark Fasheh 	fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
225ecf5632dSNamhyung Kim 	if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))
226c4b929b8SMark Fasheh 		error = -EFAULT;
227c4b929b8SMark Fasheh 
228c4b929b8SMark Fasheh 	return error;
229c4b929b8SMark Fasheh }
230c4b929b8SMark Fasheh 
ioctl_file_clone(struct file * dst_file,unsigned long srcfd,u64 off,u64 olen,u64 destoff)23104b38d60SChristoph Hellwig static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
23204b38d60SChristoph Hellwig 			     u64 off, u64 olen, u64 destoff)
23304b38d60SChristoph Hellwig {
23404b38d60SChristoph Hellwig 	struct fd src_file = fdget(srcfd);
23542ec3d4cSDarrick J. Wong 	loff_t cloned;
23604b38d60SChristoph Hellwig 	int ret;
23704b38d60SChristoph Hellwig 
23804b38d60SChristoph Hellwig 	if (!src_file.file)
23904b38d60SChristoph Hellwig 		return -EBADF;
24042ec3d4cSDarrick J. Wong 	cloned = vfs_clone_file_range(src_file.file, off, dst_file, destoff,
241452ce659SDarrick J. Wong 				      olen, 0);
24242ec3d4cSDarrick J. Wong 	if (cloned < 0)
24342ec3d4cSDarrick J. Wong 		ret = cloned;
24442ec3d4cSDarrick J. Wong 	else if (olen && cloned != olen)
24542ec3d4cSDarrick J. Wong 		ret = -EINVAL;
24642ec3d4cSDarrick J. Wong 	else
24742ec3d4cSDarrick J. Wong 		ret = 0;
24804b38d60SChristoph Hellwig 	fdput(src_file);
24904b38d60SChristoph Hellwig 	return ret;
25004b38d60SChristoph Hellwig }
25104b38d60SChristoph Hellwig 
ioctl_file_clone_range(struct file * file,struct file_clone_range __user * argp)25234d3d0e6SAl Viro static long ioctl_file_clone_range(struct file *file,
25334d3d0e6SAl Viro 				   struct file_clone_range __user *argp)
25404b38d60SChristoph Hellwig {
25504b38d60SChristoph Hellwig 	struct file_clone_range args;
25604b38d60SChristoph Hellwig 
25704b38d60SChristoph Hellwig 	if (copy_from_user(&args, argp, sizeof(args)))
25804b38d60SChristoph Hellwig 		return -EFAULT;
25904b38d60SChristoph Hellwig 	return ioctl_file_clone(file, args.src_fd, args.src_offset,
26004b38d60SChristoph Hellwig 				args.src_length, args.dest_offset);
26104b38d60SChristoph Hellwig }
26204b38d60SChristoph Hellwig 
2633e63cbb1SAnkit Jain /*
2643e63cbb1SAnkit Jain  * This provides compatibility with legacy XFS pre-allocation ioctls
2653e63cbb1SAnkit Jain  * which predate the fallocate syscall.
2663e63cbb1SAnkit Jain  *
2673e63cbb1SAnkit Jain  * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
2683e63cbb1SAnkit Jain  * are used here, rest are ignored.
2693e63cbb1SAnkit Jain  */
ioctl_preallocate(struct file * filp,int mode,void __user * argp)27077b90401SArnd Bergmann static int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
2713e63cbb1SAnkit Jain {
272496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
2733e63cbb1SAnkit Jain 	struct space_resv sr;
2743e63cbb1SAnkit Jain 
2753e63cbb1SAnkit Jain 	if (copy_from_user(&sr, argp, sizeof(sr)))
2763e63cbb1SAnkit Jain 		return -EFAULT;
2773e63cbb1SAnkit Jain 
2783e63cbb1SAnkit Jain 	switch (sr.l_whence) {
2793e63cbb1SAnkit Jain 	case SEEK_SET:
2803e63cbb1SAnkit Jain 		break;
2813e63cbb1SAnkit Jain 	case SEEK_CUR:
2823e63cbb1SAnkit Jain 		sr.l_start += filp->f_pos;
2833e63cbb1SAnkit Jain 		break;
2843e63cbb1SAnkit Jain 	case SEEK_END:
2853e63cbb1SAnkit Jain 		sr.l_start += i_size_read(inode);
2863e63cbb1SAnkit Jain 		break;
2873e63cbb1SAnkit Jain 	default:
2883e63cbb1SAnkit Jain 		return -EINVAL;
2893e63cbb1SAnkit Jain 	}
2903e63cbb1SAnkit Jain 
291837a6e7fSChristoph Hellwig 	return vfs_fallocate(filp, mode | FALLOC_FL_KEEP_SIZE, sr.l_start,
292837a6e7fSChristoph Hellwig 			sr.l_len);
2933e63cbb1SAnkit Jain }
2943e63cbb1SAnkit Jain 
295011da44bSAl Viro /* on ia32 l_start is on a 32-bit boundary */
296011da44bSAl Viro #if defined CONFIG_COMPAT && defined(CONFIG_X86_64)
297011da44bSAl Viro /* just account for different alignment */
compat_ioctl_preallocate(struct file * file,int mode,struct space_resv_32 __user * argp)29877b90401SArnd Bergmann static int compat_ioctl_preallocate(struct file *file, int mode,
299011da44bSAl Viro 				    struct space_resv_32 __user *argp)
300011da44bSAl Viro {
301011da44bSAl Viro 	struct inode *inode = file_inode(file);
302011da44bSAl Viro 	struct space_resv_32 sr;
303011da44bSAl Viro 
304011da44bSAl Viro 	if (copy_from_user(&sr, argp, sizeof(sr)))
305011da44bSAl Viro 		return -EFAULT;
306011da44bSAl Viro 
307011da44bSAl Viro 	switch (sr.l_whence) {
308011da44bSAl Viro 	case SEEK_SET:
309011da44bSAl Viro 		break;
310011da44bSAl Viro 	case SEEK_CUR:
311011da44bSAl Viro 		sr.l_start += file->f_pos;
312011da44bSAl Viro 		break;
313011da44bSAl Viro 	case SEEK_END:
314011da44bSAl Viro 		sr.l_start += i_size_read(inode);
315011da44bSAl Viro 		break;
316011da44bSAl Viro 	default:
317011da44bSAl Viro 		return -EINVAL;
318011da44bSAl Viro 	}
319011da44bSAl Viro 
32097eeb4d9SLinus Torvalds 	return vfs_fallocate(file, mode | FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
321011da44bSAl Viro }
322011da44bSAl Viro #endif
323011da44bSAl Viro 
file_ioctl(struct file * filp,unsigned int cmd,int __user * p)32477b90401SArnd Bergmann static int file_ioctl(struct file *filp, unsigned int cmd, int __user *p)
325aa81a7c7SErez Zadok {
326aa81a7c7SErez Zadok 	switch (cmd) {
327aa81a7c7SErez Zadok 	case FIBMAP:
328aa81a7c7SErez Zadok 		return ioctl_fibmap(filp, p);
3293e63cbb1SAnkit Jain 	case FS_IOC_RESVSP:
3303e63cbb1SAnkit Jain 	case FS_IOC_RESVSP64:
331837a6e7fSChristoph Hellwig 		return ioctl_preallocate(filp, 0, p);
332837a6e7fSChristoph Hellwig 	case FS_IOC_UNRESVSP:
333837a6e7fSChristoph Hellwig 	case FS_IOC_UNRESVSP64:
334837a6e7fSChristoph Hellwig 		return ioctl_preallocate(filp, FALLOC_FL_PUNCH_HOLE, p);
335837a6e7fSChristoph Hellwig 	case FS_IOC_ZERO_RANGE:
336837a6e7fSChristoph Hellwig 		return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p);
3371da177e4SLinus Torvalds 	}
3381da177e4SLinus Torvalds 
33977b90401SArnd Bergmann 	return -ENOIOCTLCMD;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
ioctl_fionbio(struct file * filp,int __user * argp)342aa81a7c7SErez Zadok static int ioctl_fionbio(struct file *filp, int __user *argp)
343aa81a7c7SErez Zadok {
344aa81a7c7SErez Zadok 	unsigned int flag;
345aa81a7c7SErez Zadok 	int on, error;
346aa81a7c7SErez Zadok 
347aa81a7c7SErez Zadok 	error = get_user(on, argp);
348aa81a7c7SErez Zadok 	if (error)
349aa81a7c7SErez Zadok 		return error;
350aa81a7c7SErez Zadok 	flag = O_NONBLOCK;
351aa81a7c7SErez Zadok #ifdef __sparc__
352aa81a7c7SErez Zadok 	/* SunOS compatibility item. */
353aa81a7c7SErez Zadok 	if (O_NONBLOCK != O_NDELAY)
354aa81a7c7SErez Zadok 		flag |= O_NDELAY;
355aa81a7c7SErez Zadok #endif
356db1dd4d3SJonathan Corbet 	spin_lock(&filp->f_lock);
357aa81a7c7SErez Zadok 	if (on)
358aa81a7c7SErez Zadok 		filp->f_flags |= flag;
359aa81a7c7SErez Zadok 	else
360aa81a7c7SErez Zadok 		filp->f_flags &= ~flag;
361db1dd4d3SJonathan Corbet 	spin_unlock(&filp->f_lock);
362aa81a7c7SErez Zadok 	return error;
363aa81a7c7SErez Zadok }
364aa81a7c7SErez Zadok 
ioctl_fioasync(unsigned int fd,struct file * filp,int __user * argp)365aa81a7c7SErez Zadok static int ioctl_fioasync(unsigned int fd, struct file *filp,
366aa81a7c7SErez Zadok 			  int __user *argp)
367aa81a7c7SErez Zadok {
368aa81a7c7SErez Zadok 	unsigned int flag;
369aa81a7c7SErez Zadok 	int on, error;
370aa81a7c7SErez Zadok 
371aa81a7c7SErez Zadok 	error = get_user(on, argp);
372aa81a7c7SErez Zadok 	if (error)
373aa81a7c7SErez Zadok 		return error;
374aa81a7c7SErez Zadok 	flag = on ? FASYNC : 0;
375aa81a7c7SErez Zadok 
376aa81a7c7SErez Zadok 	/* Did FASYNC state change ? */
377aa81a7c7SErez Zadok 	if ((flag ^ filp->f_flags) & FASYNC) {
37872c2d531SAl Viro 		if (filp->f_op->fasync)
37976398425SJonathan Corbet 			/* fasync() adjusts filp->f_flags */
380aa81a7c7SErez Zadok 			error = filp->f_op->fasync(fd, filp, on);
381218d11a8SJonathan Corbet 		else
382aa81a7c7SErez Zadok 			error = -ENOTTY;
383aa81a7c7SErez Zadok 	}
38460aa4924SJonathan Corbet 	return error < 0 ? error : 0;
385aa81a7c7SErez Zadok }
386aa81a7c7SErez Zadok 
ioctl_fsfreeze(struct file * filp)387fcccf502STakashi Sato static int ioctl_fsfreeze(struct file *filp)
388fcccf502STakashi Sato {
389496ad9aaSAl Viro 	struct super_block *sb = file_inode(filp)->i_sb;
390fcccf502STakashi Sato 
391f3f1a183SSeth Forshee 	if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
392fcccf502STakashi Sato 		return -EPERM;
393fcccf502STakashi Sato 
394fcccf502STakashi Sato 	/* If filesystem doesn't support freeze feature, return. */
39548b6bca6SBenjamin Marzinski 	if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL)
396fcccf502STakashi Sato 		return -EOPNOTSUPP;
397fcccf502STakashi Sato 
398fcccf502STakashi Sato 	/* Freeze */
39948b6bca6SBenjamin Marzinski 	if (sb->s_op->freeze_super)
400880b9577SDarrick J. Wong 		return sb->s_op->freeze_super(sb, FREEZE_HOLDER_USERSPACE);
401880b9577SDarrick J. Wong 	return freeze_super(sb, FREEZE_HOLDER_USERSPACE);
402fcccf502STakashi Sato }
403fcccf502STakashi Sato 
ioctl_fsthaw(struct file * filp)404fcccf502STakashi Sato static int ioctl_fsthaw(struct file *filp)
405fcccf502STakashi Sato {
406496ad9aaSAl Viro 	struct super_block *sb = file_inode(filp)->i_sb;
407fcccf502STakashi Sato 
408f3f1a183SSeth Forshee 	if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
409fcccf502STakashi Sato 		return -EPERM;
410fcccf502STakashi Sato 
411fcccf502STakashi Sato 	/* Thaw */
41248b6bca6SBenjamin Marzinski 	if (sb->s_op->thaw_super)
413880b9577SDarrick J. Wong 		return sb->s_op->thaw_super(sb, FREEZE_HOLDER_USERSPACE);
414880b9577SDarrick J. Wong 	return thaw_super(sb, FREEZE_HOLDER_USERSPACE);
415fcccf502STakashi Sato }
416fcccf502STakashi Sato 
ioctl_file_dedupe_range(struct file * file,struct file_dedupe_range __user * argp)41734d3d0e6SAl Viro static int ioctl_file_dedupe_range(struct file *file,
41834d3d0e6SAl Viro 				   struct file_dedupe_range __user *argp)
41954dbc151SDarrick J. Wong {
42054dbc151SDarrick J. Wong 	struct file_dedupe_range *same = NULL;
42154dbc151SDarrick J. Wong 	int ret;
42254dbc151SDarrick J. Wong 	unsigned long size;
42354dbc151SDarrick J. Wong 	u16 count;
42454dbc151SDarrick J. Wong 
42554dbc151SDarrick J. Wong 	if (get_user(count, &argp->dest_count)) {
42654dbc151SDarrick J. Wong 		ret = -EFAULT;
42754dbc151SDarrick J. Wong 		goto out;
42854dbc151SDarrick J. Wong 	}
42954dbc151SDarrick J. Wong 
430a12cf8b3SAmit Daniel Kachhap 	size = offsetof(struct file_dedupe_range, info[count]);
431b71dbf10SDarrick J. Wong 	if (size > PAGE_SIZE) {
432b71dbf10SDarrick J. Wong 		ret = -ENOMEM;
433b71dbf10SDarrick J. Wong 		goto out;
434b71dbf10SDarrick J. Wong 	}
43554dbc151SDarrick J. Wong 
43654dbc151SDarrick J. Wong 	same = memdup_user(argp, size);
43754dbc151SDarrick J. Wong 	if (IS_ERR(same)) {
43854dbc151SDarrick J. Wong 		ret = PTR_ERR(same);
43954dbc151SDarrick J. Wong 		same = NULL;
44054dbc151SDarrick J. Wong 		goto out;
44154dbc151SDarrick J. Wong 	}
44254dbc151SDarrick J. Wong 
44310eec60cSScott Bauer 	same->dest_count = count;
44454dbc151SDarrick J. Wong 	ret = vfs_dedupe_file_range(file, same);
44554dbc151SDarrick J. Wong 	if (ret)
44654dbc151SDarrick J. Wong 		goto out;
44754dbc151SDarrick J. Wong 
44854dbc151SDarrick J. Wong 	ret = copy_to_user(argp, same, size);
44954dbc151SDarrick J. Wong 	if (ret)
45054dbc151SDarrick J. Wong 		ret = -EFAULT;
45154dbc151SDarrick J. Wong 
45254dbc151SDarrick J. Wong out:
45354dbc151SDarrick J. Wong 	kfree(same);
45454dbc151SDarrick J. Wong 	return ret;
45554dbc151SDarrick J. Wong }
45654dbc151SDarrick J. Wong 
4574c5b4799SMiklos Szeredi /**
4584c5b4799SMiklos Szeredi  * fileattr_fill_xflags - initialize fileattr with xflags
4594c5b4799SMiklos Szeredi  * @fa:		fileattr pointer
4604c5b4799SMiklos Szeredi  * @xflags:	FS_XFLAG_* flags
4614c5b4799SMiklos Szeredi  *
4624c5b4799SMiklos Szeredi  * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags).  All
4634c5b4799SMiklos Szeredi  * other fields are zeroed.
4644c5b4799SMiklos Szeredi  */
fileattr_fill_xflags(struct fileattr * fa,u32 xflags)4654c5b4799SMiklos Szeredi void fileattr_fill_xflags(struct fileattr *fa, u32 xflags)
4664c5b4799SMiklos Szeredi {
4674c5b4799SMiklos Szeredi 	memset(fa, 0, sizeof(*fa));
4684c5b4799SMiklos Szeredi 	fa->fsx_valid = true;
4694c5b4799SMiklos Szeredi 	fa->fsx_xflags = xflags;
4704c5b4799SMiklos Szeredi 	if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)
4714c5b4799SMiklos Szeredi 		fa->flags |= FS_IMMUTABLE_FL;
4724c5b4799SMiklos Szeredi 	if (fa->fsx_xflags & FS_XFLAG_APPEND)
4734c5b4799SMiklos Szeredi 		fa->flags |= FS_APPEND_FL;
4744c5b4799SMiklos Szeredi 	if (fa->fsx_xflags & FS_XFLAG_SYNC)
4754c5b4799SMiklos Szeredi 		fa->flags |= FS_SYNC_FL;
4764c5b4799SMiklos Szeredi 	if (fa->fsx_xflags & FS_XFLAG_NOATIME)
4774c5b4799SMiklos Szeredi 		fa->flags |= FS_NOATIME_FL;
4784c5b4799SMiklos Szeredi 	if (fa->fsx_xflags & FS_XFLAG_NODUMP)
4794c5b4799SMiklos Szeredi 		fa->flags |= FS_NODUMP_FL;
4804c5b4799SMiklos Szeredi 	if (fa->fsx_xflags & FS_XFLAG_DAX)
4814c5b4799SMiklos Szeredi 		fa->flags |= FS_DAX_FL;
4824c5b4799SMiklos Szeredi 	if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT)
4834c5b4799SMiklos Szeredi 		fa->flags |= FS_PROJINHERIT_FL;
4844c5b4799SMiklos Szeredi }
4854c5b4799SMiklos Szeredi EXPORT_SYMBOL(fileattr_fill_xflags);
4864c5b4799SMiklos Szeredi 
4874c5b4799SMiklos Szeredi /**
4884c5b4799SMiklos Szeredi  * fileattr_fill_flags - initialize fileattr with flags
4894c5b4799SMiklos Szeredi  * @fa:		fileattr pointer
4904c5b4799SMiklos Szeredi  * @flags:	FS_*_FL flags
4914c5b4799SMiklos Szeredi  *
4924c5b4799SMiklos Szeredi  * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags).
4934c5b4799SMiklos Szeredi  * All other fields are zeroed.
4944c5b4799SMiklos Szeredi  */
fileattr_fill_flags(struct fileattr * fa,u32 flags)4954c5b4799SMiklos Szeredi void fileattr_fill_flags(struct fileattr *fa, u32 flags)
4964c5b4799SMiklos Szeredi {
4974c5b4799SMiklos Szeredi 	memset(fa, 0, sizeof(*fa));
4984c5b4799SMiklos Szeredi 	fa->flags_valid = true;
4994c5b4799SMiklos Szeredi 	fa->flags = flags;
5004c5b4799SMiklos Szeredi 	if (fa->flags & FS_SYNC_FL)
5014c5b4799SMiklos Szeredi 		fa->fsx_xflags |= FS_XFLAG_SYNC;
5024c5b4799SMiklos Szeredi 	if (fa->flags & FS_IMMUTABLE_FL)
5034c5b4799SMiklos Szeredi 		fa->fsx_xflags |= FS_XFLAG_IMMUTABLE;
5044c5b4799SMiklos Szeredi 	if (fa->flags & FS_APPEND_FL)
5054c5b4799SMiklos Szeredi 		fa->fsx_xflags |= FS_XFLAG_APPEND;
5064c5b4799SMiklos Szeredi 	if (fa->flags & FS_NODUMP_FL)
5074c5b4799SMiklos Szeredi 		fa->fsx_xflags |= FS_XFLAG_NODUMP;
5084c5b4799SMiklos Szeredi 	if (fa->flags & FS_NOATIME_FL)
5094c5b4799SMiklos Szeredi 		fa->fsx_xflags |= FS_XFLAG_NOATIME;
5104c5b4799SMiklos Szeredi 	if (fa->flags & FS_DAX_FL)
5114c5b4799SMiklos Szeredi 		fa->fsx_xflags |= FS_XFLAG_DAX;
5124c5b4799SMiklos Szeredi 	if (fa->flags & FS_PROJINHERIT_FL)
5134c5b4799SMiklos Szeredi 		fa->fsx_xflags |= FS_XFLAG_PROJINHERIT;
5144c5b4799SMiklos Szeredi }
5154c5b4799SMiklos Szeredi EXPORT_SYMBOL(fileattr_fill_flags);
5164c5b4799SMiklos Szeredi 
5174c5b4799SMiklos Szeredi /**
5184c5b4799SMiklos Szeredi  * vfs_fileattr_get - retrieve miscellaneous file attributes
5194c5b4799SMiklos Szeredi  * @dentry:	the object to retrieve from
5204c5b4799SMiklos Szeredi  * @fa:		fileattr pointer
5214c5b4799SMiklos Szeredi  *
5224c5b4799SMiklos Szeredi  * Call i_op->fileattr_get() callback, if exists.
5234c5b4799SMiklos Szeredi  *
5244c5b4799SMiklos Szeredi  * Return: 0 on success, or a negative error on failure.
5254c5b4799SMiklos Szeredi  */
vfs_fileattr_get(struct dentry * dentry,struct fileattr * fa)5264c5b4799SMiklos Szeredi int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
5274c5b4799SMiklos Szeredi {
5284c5b4799SMiklos Szeredi 	struct inode *inode = d_inode(dentry);
5294c5b4799SMiklos Szeredi 
5304c5b4799SMiklos Szeredi 	if (!inode->i_op->fileattr_get)
5314c5b4799SMiklos Szeredi 		return -ENOIOCTLCMD;
5324c5b4799SMiklos Szeredi 
5334c5b4799SMiklos Szeredi 	return inode->i_op->fileattr_get(dentry, fa);
5344c5b4799SMiklos Szeredi }
5354c5b4799SMiklos Szeredi EXPORT_SYMBOL(vfs_fileattr_get);
5364c5b4799SMiklos Szeredi 
5374c5b4799SMiklos Szeredi /**
5384c5b4799SMiklos Szeredi  * copy_fsxattr_to_user - copy fsxattr to userspace.
5394c5b4799SMiklos Szeredi  * @fa:		fileattr pointer
5404c5b4799SMiklos Szeredi  * @ufa:	fsxattr user pointer
5414c5b4799SMiklos Szeredi  *
5424c5b4799SMiklos Szeredi  * Return: 0 on success, or -EFAULT on failure.
5434c5b4799SMiklos Szeredi  */
copy_fsxattr_to_user(const struct fileattr * fa,struct fsxattr __user * ufa)5444c5b4799SMiklos Szeredi int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa)
5454c5b4799SMiklos Szeredi {
5464c5b4799SMiklos Szeredi 	struct fsxattr xfa;
5474c5b4799SMiklos Szeredi 
5484c5b4799SMiklos Szeredi 	memset(&xfa, 0, sizeof(xfa));
5494c5b4799SMiklos Szeredi 	xfa.fsx_xflags = fa->fsx_xflags;
5504c5b4799SMiklos Szeredi 	xfa.fsx_extsize = fa->fsx_extsize;
5514c5b4799SMiklos Szeredi 	xfa.fsx_nextents = fa->fsx_nextents;
5524c5b4799SMiklos Szeredi 	xfa.fsx_projid = fa->fsx_projid;
5534c5b4799SMiklos Szeredi 	xfa.fsx_cowextsize = fa->fsx_cowextsize;
5544c5b4799SMiklos Szeredi 
5554c5b4799SMiklos Szeredi 	if (copy_to_user(ufa, &xfa, sizeof(xfa)))
5564c5b4799SMiklos Szeredi 		return -EFAULT;
5574c5b4799SMiklos Szeredi 
5584c5b4799SMiklos Szeredi 	return 0;
5594c5b4799SMiklos Szeredi }
5604c5b4799SMiklos Szeredi EXPORT_SYMBOL(copy_fsxattr_to_user);
5614c5b4799SMiklos Szeredi 
copy_fsxattr_from_user(struct fileattr * fa,struct fsxattr __user * ufa)5624c5b4799SMiklos Szeredi static int copy_fsxattr_from_user(struct fileattr *fa,
5634c5b4799SMiklos Szeredi 				  struct fsxattr __user *ufa)
5644c5b4799SMiklos Szeredi {
5654c5b4799SMiklos Szeredi 	struct fsxattr xfa;
5664c5b4799SMiklos Szeredi 
5674c5b4799SMiklos Szeredi 	if (copy_from_user(&xfa, ufa, sizeof(xfa)))
5684c5b4799SMiklos Szeredi 		return -EFAULT;
5694c5b4799SMiklos Szeredi 
5704c5b4799SMiklos Szeredi 	fileattr_fill_xflags(fa, xfa.fsx_xflags);
5714c5b4799SMiklos Szeredi 	fa->fsx_extsize = xfa.fsx_extsize;
5724c5b4799SMiklos Szeredi 	fa->fsx_nextents = xfa.fsx_nextents;
5734c5b4799SMiklos Szeredi 	fa->fsx_projid = xfa.fsx_projid;
5744c5b4799SMiklos Szeredi 	fa->fsx_cowextsize = xfa.fsx_cowextsize;
5754c5b4799SMiklos Szeredi 
5764c5b4799SMiklos Szeredi 	return 0;
5774c5b4799SMiklos Szeredi }
5784c5b4799SMiklos Szeredi 
5794c5b4799SMiklos Szeredi /*
5804c5b4799SMiklos Szeredi  * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject
5814c5b4799SMiklos Szeredi  * any invalid configurations.
5824c5b4799SMiklos Szeredi  *
5834c5b4799SMiklos Szeredi  * Note: must be called with inode lock held.
5844c5b4799SMiklos Szeredi  */
fileattr_set_prepare(struct inode * inode,const struct fileattr * old_ma,struct fileattr * fa)5854c5b4799SMiklos Szeredi static int fileattr_set_prepare(struct inode *inode,
5864c5b4799SMiklos Szeredi 			      const struct fileattr *old_ma,
5874c5b4799SMiklos Szeredi 			      struct fileattr *fa)
5884c5b4799SMiklos Szeredi {
5894c5b4799SMiklos Szeredi 	int err;
5904c5b4799SMiklos Szeredi 
5914c5b4799SMiklos Szeredi 	/*
5924c5b4799SMiklos Szeredi 	 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
5934c5b4799SMiklos Szeredi 	 * the relevant capability.
5944c5b4799SMiklos Szeredi 	 */
5954c5b4799SMiklos Szeredi 	if ((fa->flags ^ old_ma->flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) &&
5964c5b4799SMiklos Szeredi 	    !capable(CAP_LINUX_IMMUTABLE))
5974c5b4799SMiklos Szeredi 		return -EPERM;
5984c5b4799SMiklos Szeredi 
5994c5b4799SMiklos Szeredi 	err = fscrypt_prepare_setflags(inode, old_ma->flags, fa->flags);
6004c5b4799SMiklos Szeredi 	if (err)
6014c5b4799SMiklos Szeredi 		return err;
6024c5b4799SMiklos Szeredi 
6034c5b4799SMiklos Szeredi 	/*
6044c5b4799SMiklos Szeredi 	 * Project Quota ID state is only allowed to change from within the init
6054c5b4799SMiklos Szeredi 	 * namespace. Enforce that restriction only if we are trying to change
6064c5b4799SMiklos Szeredi 	 * the quota ID state. Everything else is allowed in user namespaces.
6074c5b4799SMiklos Szeredi 	 */
6084c5b4799SMiklos Szeredi 	if (current_user_ns() != &init_user_ns) {
6094c5b4799SMiklos Szeredi 		if (old_ma->fsx_projid != fa->fsx_projid)
6104c5b4799SMiklos Szeredi 			return -EINVAL;
6114c5b4799SMiklos Szeredi 		if ((old_ma->fsx_xflags ^ fa->fsx_xflags) &
6124c5b4799SMiklos Szeredi 				FS_XFLAG_PROJINHERIT)
6134c5b4799SMiklos Szeredi 			return -EINVAL;
614d03ef4daSWang Shilong 	} else {
615d03ef4daSWang Shilong 		/*
616d03ef4daSWang Shilong 		 * Caller is allowed to change the project ID. If it is being
617d03ef4daSWang Shilong 		 * changed, make sure that the new value is valid.
618d03ef4daSWang Shilong 		 */
619d03ef4daSWang Shilong 		if (old_ma->fsx_projid != fa->fsx_projid &&
620d03ef4daSWang Shilong 		    !projid_valid(make_kprojid(&init_user_ns, fa->fsx_projid)))
621d03ef4daSWang Shilong 			return -EINVAL;
6224c5b4799SMiklos Szeredi 	}
6234c5b4799SMiklos Szeredi 
6244c5b4799SMiklos Szeredi 	/* Check extent size hints. */
6254c5b4799SMiklos Szeredi 	if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode))
6264c5b4799SMiklos Szeredi 		return -EINVAL;
6274c5b4799SMiklos Szeredi 
6284c5b4799SMiklos Szeredi 	if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) &&
6294c5b4799SMiklos Szeredi 			!S_ISDIR(inode->i_mode))
6304c5b4799SMiklos Szeredi 		return -EINVAL;
6314c5b4799SMiklos Szeredi 
6324c5b4799SMiklos Szeredi 	if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) &&
6334c5b4799SMiklos Szeredi 	    !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
6344c5b4799SMiklos Szeredi 		return -EINVAL;
6354c5b4799SMiklos Szeredi 
6364c5b4799SMiklos Szeredi 	/*
6374c5b4799SMiklos Szeredi 	 * It is only valid to set the DAX flag on regular files and
6384c5b4799SMiklos Szeredi 	 * directories on filesystems.
6394c5b4799SMiklos Szeredi 	 */
6404c5b4799SMiklos Szeredi 	if ((fa->fsx_xflags & FS_XFLAG_DAX) &&
6414c5b4799SMiklos Szeredi 	    !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
6424c5b4799SMiklos Szeredi 		return -EINVAL;
6434c5b4799SMiklos Szeredi 
6444c5b4799SMiklos Szeredi 	/* Extent size hints of zero turn off the flags. */
6454c5b4799SMiklos Szeredi 	if (fa->fsx_extsize == 0)
6464c5b4799SMiklos Szeredi 		fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT);
6474c5b4799SMiklos Szeredi 	if (fa->fsx_cowextsize == 0)
6484c5b4799SMiklos Szeredi 		fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE;
6494c5b4799SMiklos Szeredi 
6504c5b4799SMiklos Szeredi 	return 0;
6514c5b4799SMiklos Szeredi }
6524c5b4799SMiklos Szeredi 
6534c5b4799SMiklos Szeredi /**
6544c5b4799SMiklos Szeredi  * vfs_fileattr_set - change miscellaneous file attributes
6558782a9aeSChristian Brauner  * @idmap:	idmap of the mount
6564c5b4799SMiklos Szeredi  * @dentry:	the object to change
6574c5b4799SMiklos Szeredi  * @fa:		fileattr pointer
6584c5b4799SMiklos Szeredi  *
6594c5b4799SMiklos Szeredi  * After verifying permissions, call i_op->fileattr_set() callback, if
6604c5b4799SMiklos Szeredi  * exists.
6614c5b4799SMiklos Szeredi  *
6624c5b4799SMiklos Szeredi  * Verifying attributes involves retrieving current attributes with
6634c5b4799SMiklos Szeredi  * i_op->fileattr_get(), this also allows initializing attributes that have
6644c5b4799SMiklos Szeredi  * not been set by the caller to current values.  Inode lock is held
6654c5b4799SMiklos Szeredi  * thoughout to prevent racing with another instance.
6664c5b4799SMiklos Szeredi  *
6674c5b4799SMiklos Szeredi  * Return: 0 on success, or a negative error on failure.
6684c5b4799SMiklos Szeredi  */
vfs_fileattr_set(struct mnt_idmap * idmap,struct dentry * dentry,struct fileattr * fa)6698782a9aeSChristian Brauner int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
6704c5b4799SMiklos Szeredi 		     struct fileattr *fa)
6714c5b4799SMiklos Szeredi {
6724c5b4799SMiklos Szeredi 	struct inode *inode = d_inode(dentry);
6734c5b4799SMiklos Szeredi 	struct fileattr old_ma = {};
6744c5b4799SMiklos Szeredi 	int err;
6754c5b4799SMiklos Szeredi 
6764c5b4799SMiklos Szeredi 	if (!inode->i_op->fileattr_set)
6774c5b4799SMiklos Szeredi 		return -ENOIOCTLCMD;
6784c5b4799SMiklos Szeredi 
67901beba79SChristian Brauner 	if (!inode_owner_or_capable(idmap, inode))
6804c5b4799SMiklos Szeredi 		return -EPERM;
6814c5b4799SMiklos Szeredi 
6824c5b4799SMiklos Szeredi 	inode_lock(inode);
6834c5b4799SMiklos Szeredi 	err = vfs_fileattr_get(dentry, &old_ma);
6844c5b4799SMiklos Szeredi 	if (!err) {
6854c5b4799SMiklos Szeredi 		/* initialize missing bits from old_ma */
6864c5b4799SMiklos Szeredi 		if (fa->flags_valid) {
6874c5b4799SMiklos Szeredi 			fa->fsx_xflags |= old_ma.fsx_xflags & ~FS_XFLAG_COMMON;
6884c5b4799SMiklos Szeredi 			fa->fsx_extsize = old_ma.fsx_extsize;
6894c5b4799SMiklos Szeredi 			fa->fsx_nextents = old_ma.fsx_nextents;
6904c5b4799SMiklos Szeredi 			fa->fsx_projid = old_ma.fsx_projid;
6914c5b4799SMiklos Szeredi 			fa->fsx_cowextsize = old_ma.fsx_cowextsize;
6924c5b4799SMiklos Szeredi 		} else {
6934c5b4799SMiklos Szeredi 			fa->flags |= old_ma.flags & ~FS_COMMON_FL;
6944c5b4799SMiklos Szeredi 		}
6954c5b4799SMiklos Szeredi 		err = fileattr_set_prepare(inode, &old_ma, fa);
6964c5b4799SMiklos Szeredi 		if (!err)
6978782a9aeSChristian Brauner 			err = inode->i_op->fileattr_set(idmap, dentry, fa);
6984c5b4799SMiklos Szeredi 	}
6994c5b4799SMiklos Szeredi 	inode_unlock(inode);
7004c5b4799SMiklos Szeredi 
7014c5b4799SMiklos Szeredi 	return err;
7024c5b4799SMiklos Szeredi }
7034c5b4799SMiklos Szeredi EXPORT_SYMBOL(vfs_fileattr_set);
7044c5b4799SMiklos Szeredi 
ioctl_getflags(struct file * file,unsigned int __user * argp)7054c5b4799SMiklos Szeredi static int ioctl_getflags(struct file *file, unsigned int __user *argp)
7064c5b4799SMiklos Szeredi {
7074c5b4799SMiklos Szeredi 	struct fileattr fa = { .flags_valid = true }; /* hint only */
7084c5b4799SMiklos Szeredi 	int err;
7094c5b4799SMiklos Szeredi 
7104c5b4799SMiklos Szeredi 	err = vfs_fileattr_get(file->f_path.dentry, &fa);
7114c5b4799SMiklos Szeredi 	if (!err)
7124c5b4799SMiklos Szeredi 		err = put_user(fa.flags, argp);
7134c5b4799SMiklos Szeredi 	return err;
7144c5b4799SMiklos Szeredi }
7154c5b4799SMiklos Szeredi 
ioctl_setflags(struct file * file,unsigned int __user * argp)7164c5b4799SMiklos Szeredi static int ioctl_setflags(struct file *file, unsigned int __user *argp)
7174c5b4799SMiklos Szeredi {
7188782a9aeSChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(file);
7194c5b4799SMiklos Szeredi 	struct dentry *dentry = file->f_path.dentry;
7204c5b4799SMiklos Szeredi 	struct fileattr fa;
7214c5b4799SMiklos Szeredi 	unsigned int flags;
7224c5b4799SMiklos Szeredi 	int err;
7234c5b4799SMiklos Szeredi 
7244c5b4799SMiklos Szeredi 	err = get_user(flags, argp);
7254c5b4799SMiklos Szeredi 	if (!err) {
7264c5b4799SMiklos Szeredi 		err = mnt_want_write_file(file);
7274c5b4799SMiklos Szeredi 		if (!err) {
7284c5b4799SMiklos Szeredi 			fileattr_fill_flags(&fa, flags);
7298782a9aeSChristian Brauner 			err = vfs_fileattr_set(idmap, dentry, &fa);
7304c5b4799SMiklos Szeredi 			mnt_drop_write_file(file);
7314c5b4799SMiklos Szeredi 		}
7324c5b4799SMiklos Szeredi 	}
7334c5b4799SMiklos Szeredi 	return err;
7344c5b4799SMiklos Szeredi }
7354c5b4799SMiklos Szeredi 
ioctl_fsgetxattr(struct file * file,void __user * argp)7364c5b4799SMiklos Szeredi static int ioctl_fsgetxattr(struct file *file, void __user *argp)
7374c5b4799SMiklos Szeredi {
7384c5b4799SMiklos Szeredi 	struct fileattr fa = { .fsx_valid = true }; /* hint only */
7394c5b4799SMiklos Szeredi 	int err;
7404c5b4799SMiklos Szeredi 
7414c5b4799SMiklos Szeredi 	err = vfs_fileattr_get(file->f_path.dentry, &fa);
7424c5b4799SMiklos Szeredi 	if (!err)
7434c5b4799SMiklos Szeredi 		err = copy_fsxattr_to_user(&fa, argp);
7444c5b4799SMiklos Szeredi 
7454c5b4799SMiklos Szeredi 	return err;
7464c5b4799SMiklos Szeredi }
7474c5b4799SMiklos Szeredi 
ioctl_fssetxattr(struct file * file,void __user * argp)7484c5b4799SMiklos Szeredi static int ioctl_fssetxattr(struct file *file, void __user *argp)
7494c5b4799SMiklos Szeredi {
7508782a9aeSChristian Brauner 	struct mnt_idmap *idmap = file_mnt_idmap(file);
7514c5b4799SMiklos Szeredi 	struct dentry *dentry = file->f_path.dentry;
7524c5b4799SMiklos Szeredi 	struct fileattr fa;
7534c5b4799SMiklos Szeredi 	int err;
7544c5b4799SMiklos Szeredi 
7554c5b4799SMiklos Szeredi 	err = copy_fsxattr_from_user(&fa, argp);
7564c5b4799SMiklos Szeredi 	if (!err) {
7574c5b4799SMiklos Szeredi 		err = mnt_want_write_file(file);
7584c5b4799SMiklos Szeredi 		if (!err) {
7598782a9aeSChristian Brauner 			err = vfs_fileattr_set(idmap, dentry, &fa);
7604c5b4799SMiklos Szeredi 			mnt_drop_write_file(file);
7614c5b4799SMiklos Szeredi 		}
7624c5b4799SMiklos Szeredi 	}
7634c5b4799SMiklos Szeredi 	return err;
7644c5b4799SMiklos Szeredi }
7654c5b4799SMiklos Szeredi 
7661da177e4SLinus Torvalds /*
767deb21db7SErez Zadok  * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
7681da177e4SLinus Torvalds  * It's just a simple helper for sys_ioctl and compat_sys_ioctl.
76977b90401SArnd Bergmann  *
77077b90401SArnd Bergmann  * When you add any new common ioctls to the switches above and below,
77177b90401SArnd Bergmann  * please ensure they have compatible arguments in compat mode.
7721da177e4SLinus Torvalds  */
do_vfs_ioctl(struct file * filp,unsigned int fd,unsigned int cmd,unsigned long arg)77377b90401SArnd Bergmann static int do_vfs_ioctl(struct file *filp, unsigned int fd,
77477b90401SArnd Bergmann 			unsigned int cmd, unsigned long arg)
7751da177e4SLinus Torvalds {
77634d3d0e6SAl Viro 	void __user *argp = (void __user *)arg;
777496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds 	switch (cmd) {
7801da177e4SLinus Torvalds 	case FIOCLEX:
7811da177e4SLinus Torvalds 		set_close_on_exec(fd, 1);
78277b90401SArnd Bergmann 		return 0;
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds 	case FIONCLEX:
7851da177e4SLinus Torvalds 		set_close_on_exec(fd, 0);
78677b90401SArnd Bergmann 		return 0;
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds 	case FIONBIO:
78977b90401SArnd Bergmann 		return ioctl_fionbio(filp, argp);
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 	case FIOASYNC:
79277b90401SArnd Bergmann 		return ioctl_fioasync(fd, filp, argp);
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds 	case FIOQSIZE:
79527a4f7e6SNamhyung Kim 		if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
79627a4f7e6SNamhyung Kim 		    S_ISLNK(inode->i_mode)) {
79727a4f7e6SNamhyung Kim 			loff_t res = inode_get_bytes(inode);
79877b90401SArnd Bergmann 			return copy_to_user(argp, &res, sizeof(res)) ?
79927a4f7e6SNamhyung Kim 					    -EFAULT : 0;
80077b90401SArnd Bergmann 		}
80177b90401SArnd Bergmann 
80277b90401SArnd Bergmann 		return -ENOTTY;
803fcccf502STakashi Sato 
804fcccf502STakashi Sato 	case FIFREEZE:
80577b90401SArnd Bergmann 		return ioctl_fsfreeze(filp);
806fcccf502STakashi Sato 
807fcccf502STakashi Sato 	case FITHAW:
80877b90401SArnd Bergmann 		return ioctl_fsthaw(filp);
809fcccf502STakashi Sato 
81019ba0559SAneesh Kumar K.V 	case FS_IOC_FIEMAP:
81134d3d0e6SAl Viro 		return ioctl_fiemap(filp, argp);
81219ba0559SAneesh Kumar K.V 
81319ba0559SAneesh Kumar K.V 	case FIGETBSZ:
8148f97d1e9SAmir Goldstein 		/* anon_bdev filesystems may not have a block size */
8158f97d1e9SAmir Goldstein 		if (!inode->i_sb->s_blocksize)
8168f97d1e9SAmir Goldstein 			return -EINVAL;
81777b90401SArnd Bergmann 
81834d3d0e6SAl Viro 		return put_user(inode->i_sb->s_blocksize, (int __user *)argp);
81919ba0559SAneesh Kumar K.V 
82004b38d60SChristoph Hellwig 	case FICLONE:
82104b38d60SChristoph Hellwig 		return ioctl_file_clone(filp, arg, 0, 0, 0);
82204b38d60SChristoph Hellwig 
82304b38d60SChristoph Hellwig 	case FICLONERANGE:
82404b38d60SChristoph Hellwig 		return ioctl_file_clone_range(filp, argp);
82504b38d60SChristoph Hellwig 
82654dbc151SDarrick J. Wong 	case FIDEDUPERANGE:
82754dbc151SDarrick J. Wong 		return ioctl_file_dedupe_range(filp, argp);
82854dbc151SDarrick J. Wong 
8290a061743SArnd Bergmann 	case FIONREAD:
8300a061743SArnd Bergmann 		if (!S_ISREG(inode->i_mode))
8310a061743SArnd Bergmann 			return vfs_ioctl(filp, cmd, arg);
8320a061743SArnd Bergmann 
8330a061743SArnd Bergmann 		return put_user(i_size_read(inode) - filp->f_pos,
8340a061743SArnd Bergmann 				(int __user *)argp);
8350a061743SArnd Bergmann 
8364c5b4799SMiklos Szeredi 	case FS_IOC_GETFLAGS:
8374c5b4799SMiklos Szeredi 		return ioctl_getflags(filp, argp);
8384c5b4799SMiklos Szeredi 
8394c5b4799SMiklos Szeredi 	case FS_IOC_SETFLAGS:
8404c5b4799SMiklos Szeredi 		return ioctl_setflags(filp, argp);
8414c5b4799SMiklos Szeredi 
8424c5b4799SMiklos Szeredi 	case FS_IOC_FSGETXATTR:
8434c5b4799SMiklos Szeredi 		return ioctl_fsgetxattr(filp, argp);
8444c5b4799SMiklos Szeredi 
8454c5b4799SMiklos Szeredi 	case FS_IOC_FSSETXATTR:
8464c5b4799SMiklos Szeredi 		return ioctl_fssetxattr(filp, argp);
8474c5b4799SMiklos Szeredi 
8481da177e4SLinus Torvalds 	default:
84927a4f7e6SNamhyung Kim 		if (S_ISREG(inode->i_mode))
85077b90401SArnd Bergmann 			return file_ioctl(filp, cmd, argp);
8511da177e4SLinus Torvalds 		break;
8521da177e4SLinus Torvalds 	}
85377b90401SArnd Bergmann 
85477b90401SArnd Bergmann 	return -ENOIOCTLCMD;
8551da177e4SLinus Torvalds }
8561da177e4SLinus Torvalds 
SYSCALL_DEFINE3(ioctl,unsigned int,fd,unsigned int,cmd,unsigned long,arg)857863b67e1SChristoph Hellwig SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
8581da177e4SLinus Torvalds {
8592903ff01SAl Viro 	struct fd f = fdget(fd);
86077b90401SArnd Bergmann 	int error;
8611da177e4SLinus Torvalds 
8622903ff01SAl Viro 	if (!f.file)
8632903ff01SAl Viro 		return -EBADF;
86477b90401SArnd Bergmann 
8652903ff01SAl Viro 	error = security_file_ioctl(f.file, cmd, arg);
86677b90401SArnd Bergmann 	if (error)
86777b90401SArnd Bergmann 		goto out;
86877b90401SArnd Bergmann 
8692903ff01SAl Viro 	error = do_vfs_ioctl(f.file, fd, cmd, arg);
87077b90401SArnd Bergmann 	if (error == -ENOIOCTLCMD)
87177b90401SArnd Bergmann 		error = vfs_ioctl(f.file, cmd, arg);
87277b90401SArnd Bergmann 
87377b90401SArnd Bergmann out:
8742903ff01SAl Viro 	fdput(f);
8751da177e4SLinus Torvalds 	return error;
8761da177e4SLinus Torvalds }
877cbb60b92SDominik Brodowski 
8782952db0fSArnd Bergmann #ifdef CONFIG_COMPAT
8792952db0fSArnd Bergmann /**
8802952db0fSArnd Bergmann  * compat_ptr_ioctl - generic implementation of .compat_ioctl file operation
88135931eb3SMatthew Wilcox (Oracle)  * @file: The file to operate on.
88235931eb3SMatthew Wilcox (Oracle)  * @cmd: The ioctl command number.
88335931eb3SMatthew Wilcox (Oracle)  * @arg: The argument to the ioctl.
8842952db0fSArnd Bergmann  *
8852952db0fSArnd Bergmann  * This is not normally called as a function, but instead set in struct
8862952db0fSArnd Bergmann  * file_operations as
8872952db0fSArnd Bergmann  *
8882952db0fSArnd Bergmann  *     .compat_ioctl = compat_ptr_ioctl,
8892952db0fSArnd Bergmann  *
8902952db0fSArnd Bergmann  * On most architectures, the compat_ptr_ioctl() just passes all arguments
8912952db0fSArnd Bergmann  * to the corresponding ->ioctl handler. The exception is arch/s390, where
8922952db0fSArnd Bergmann  * compat_ptr() clears the top bit of a 32-bit pointer value, so user space
8932952db0fSArnd Bergmann  * pointers to the second 2GB alias the first 2GB, as is the case for
8942952db0fSArnd Bergmann  * native 32-bit s390 user space.
8952952db0fSArnd Bergmann  *
8962952db0fSArnd Bergmann  * The compat_ptr_ioctl() function must therefore be used only with ioctl
8972952db0fSArnd Bergmann  * functions that either ignore the argument or pass a pointer to a
8982952db0fSArnd Bergmann  * compatible data type.
8992952db0fSArnd Bergmann  *
9002952db0fSArnd Bergmann  * If any ioctl command handled by fops->unlocked_ioctl passes a plain
9012952db0fSArnd Bergmann  * integer instead of a pointer, or any of the passed data types
9022952db0fSArnd Bergmann  * is incompatible between 32-bit and 64-bit architectures, a proper
9032952db0fSArnd Bergmann  * handler is required instead of compat_ptr_ioctl.
9042952db0fSArnd Bergmann  */
compat_ptr_ioctl(struct file * file,unsigned int cmd,unsigned long arg)9052952db0fSArnd Bergmann long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
9062952db0fSArnd Bergmann {
9072952db0fSArnd Bergmann 	if (!file->f_op->unlocked_ioctl)
9082952db0fSArnd Bergmann 		return -ENOIOCTLCMD;
9092952db0fSArnd Bergmann 
9102952db0fSArnd Bergmann 	return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
9112952db0fSArnd Bergmann }
9122952db0fSArnd Bergmann EXPORT_SYMBOL(compat_ptr_ioctl);
9132af563d0SArnd Bergmann 
COMPAT_SYSCALL_DEFINE3(ioctl,unsigned int,fd,unsigned int,cmd,compat_ulong_t,arg)9142af563d0SArnd Bergmann COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
91577b90401SArnd Bergmann 		       compat_ulong_t, arg)
9162af563d0SArnd Bergmann {
9172af563d0SArnd Bergmann 	struct fd f = fdget(fd);
91877b90401SArnd Bergmann 	int error;
91977b90401SArnd Bergmann 
9202af563d0SArnd Bergmann 	if (!f.file)
92177b90401SArnd Bergmann 		return -EBADF;
9222af563d0SArnd Bergmann 
923*820831deSAlfred Piccioni 	error = security_file_ioctl_compat(f.file, cmd, arg);
9242af563d0SArnd Bergmann 	if (error)
92577b90401SArnd Bergmann 		goto out;
9262af563d0SArnd Bergmann 
9272af563d0SArnd Bergmann 	switch (cmd) {
92877b90401SArnd Bergmann 	/* FICLONE takes an int argument, so don't use compat_ptr() */
9292af563d0SArnd Bergmann 	case FICLONE:
93077b90401SArnd Bergmann 		error = ioctl_file_clone(f.file, arg, 0, 0, 0);
93177b90401SArnd Bergmann 		break;
93277b90401SArnd Bergmann 
9332af563d0SArnd Bergmann #if defined(CONFIG_X86_64)
93477b90401SArnd Bergmann 	/* these get messy on amd64 due to alignment differences */
9352af563d0SArnd Bergmann 	case FS_IOC_RESVSP_32:
9362af563d0SArnd Bergmann 	case FS_IOC_RESVSP64_32:
9372af563d0SArnd Bergmann 		error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
93877b90401SArnd Bergmann 		break;
9392af563d0SArnd Bergmann 	case FS_IOC_UNRESVSP_32:
9402af563d0SArnd Bergmann 	case FS_IOC_UNRESVSP64_32:
9412af563d0SArnd Bergmann 		error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
9422af563d0SArnd Bergmann 				compat_ptr(arg));
94377b90401SArnd Bergmann 		break;
9442af563d0SArnd Bergmann 	case FS_IOC_ZERO_RANGE_32:
9452af563d0SArnd Bergmann 		error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
9462af563d0SArnd Bergmann 				compat_ptr(arg));
94777b90401SArnd Bergmann 		break;
9482af563d0SArnd Bergmann #endif
9492af563d0SArnd Bergmann 
95077b90401SArnd Bergmann 	/*
9514c5b4799SMiklos Szeredi 	 * These access 32-bit values anyway so no further handling is
9524c5b4799SMiklos Szeredi 	 * necessary.
9534c5b4799SMiklos Szeredi 	 */
9544c5b4799SMiklos Szeredi 	case FS_IOC32_GETFLAGS:
9554c5b4799SMiklos Szeredi 	case FS_IOC32_SETFLAGS:
9564c5b4799SMiklos Szeredi 		cmd = (cmd == FS_IOC32_GETFLAGS) ?
9574c5b4799SMiklos Szeredi 			FS_IOC_GETFLAGS : FS_IOC_SETFLAGS;
9584c5b4799SMiklos Szeredi 		fallthrough;
9594c5b4799SMiklos Szeredi 	/*
96077b90401SArnd Bergmann 	 * everything else in do_vfs_ioctl() takes either a compatible
96177b90401SArnd Bergmann 	 * pointer argument or no argument -- call it with a modified
96277b90401SArnd Bergmann 	 * argument.
96377b90401SArnd Bergmann 	 */
9642af563d0SArnd Bergmann 	default:
96577b90401SArnd Bergmann 		error = do_vfs_ioctl(f.file, fd, cmd,
96677b90401SArnd Bergmann 				     (unsigned long)compat_ptr(arg));
9672af563d0SArnd Bergmann 		if (error != -ENOIOCTLCMD)
96877b90401SArnd Bergmann 			break;
96977b90401SArnd Bergmann 
97077b90401SArnd Bergmann 		if (f.file->f_op->compat_ioctl)
97177b90401SArnd Bergmann 			error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
97277b90401SArnd Bergmann 		if (error == -ENOIOCTLCMD)
9732af563d0SArnd Bergmann 			error = -ENOTTY;
97477b90401SArnd Bergmann 		break;
9752af563d0SArnd Bergmann 	}
9762af563d0SArnd Bergmann 
9772af563d0SArnd Bergmann  out:
97877b90401SArnd Bergmann 	fdput(f);
97977b90401SArnd Bergmann 
9802af563d0SArnd Bergmann 	return error;
9812af563d0SArnd Bergmann }
9822952db0fSArnd Bergmann #endif
983