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