xref: /OK3568_Linux_fs/kernel/block/ioctl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/capability.h>
3*4882a593Smuzhiyun #include <linux/compat.h>
4*4882a593Smuzhiyun #include <linux/blkdev.h>
5*4882a593Smuzhiyun #include <linux/export.h>
6*4882a593Smuzhiyun #include <linux/gfp.h>
7*4882a593Smuzhiyun #include <linux/blkpg.h>
8*4882a593Smuzhiyun #include <linux/hdreg.h>
9*4882a593Smuzhiyun #include <linux/backing-dev.h>
10*4882a593Smuzhiyun #include <linux/fs.h>
11*4882a593Smuzhiyun #include <linux/blktrace_api.h>
12*4882a593Smuzhiyun #include <linux/pr.h>
13*4882a593Smuzhiyun #include <linux/uaccess.h>
14*4882a593Smuzhiyun #include "blk.h"
15*4882a593Smuzhiyun 
blkpg_do_ioctl(struct block_device * bdev,struct blkpg_partition __user * upart,int op)16*4882a593Smuzhiyun static int blkpg_do_ioctl(struct block_device *bdev,
17*4882a593Smuzhiyun 			  struct blkpg_partition __user *upart, int op)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun 	struct blkpg_partition p;
20*4882a593Smuzhiyun 	long long start, length;
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
23*4882a593Smuzhiyun 		return -EACCES;
24*4882a593Smuzhiyun 	if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
25*4882a593Smuzhiyun 		return -EFAULT;
26*4882a593Smuzhiyun 	if (bdev_is_partition(bdev))
27*4882a593Smuzhiyun 		return -EINVAL;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	if (p.pno <= 0)
30*4882a593Smuzhiyun 		return -EINVAL;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	if (op == BLKPG_DEL_PARTITION)
33*4882a593Smuzhiyun 		return bdev_del_partition(bdev, p.pno);
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	start = p.start >> SECTOR_SHIFT;
36*4882a593Smuzhiyun 	length = p.length >> SECTOR_SHIFT;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	/* check for fit in a hd_struct */
39*4882a593Smuzhiyun 	if (sizeof(sector_t) < sizeof(long long)) {
40*4882a593Smuzhiyun 		long pstart = start, plength = length;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 		if (pstart != start || plength != length || pstart < 0 ||
43*4882a593Smuzhiyun 		    plength < 0 || p.pno > 65535)
44*4882a593Smuzhiyun 			return -EINVAL;
45*4882a593Smuzhiyun 	}
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	switch (op) {
48*4882a593Smuzhiyun 	case BLKPG_ADD_PARTITION:
49*4882a593Smuzhiyun 		/* check if partition is aligned to blocksize */
50*4882a593Smuzhiyun 		if (p.start & (bdev_logical_block_size(bdev) - 1))
51*4882a593Smuzhiyun 			return -EINVAL;
52*4882a593Smuzhiyun 		return bdev_add_partition(bdev, p.pno, start, length);
53*4882a593Smuzhiyun 	case BLKPG_RESIZE_PARTITION:
54*4882a593Smuzhiyun 		return bdev_resize_partition(bdev, p.pno, start, length);
55*4882a593Smuzhiyun 	default:
56*4882a593Smuzhiyun 		return -EINVAL;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
blkpg_ioctl(struct block_device * bdev,struct blkpg_ioctl_arg __user * arg)60*4882a593Smuzhiyun static int blkpg_ioctl(struct block_device *bdev,
61*4882a593Smuzhiyun 		       struct blkpg_ioctl_arg __user *arg)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	struct blkpg_partition __user *udata;
64*4882a593Smuzhiyun 	int op;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	if (get_user(op, &arg->op) || get_user(udata, &arg->data))
67*4882a593Smuzhiyun 		return -EFAULT;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	return blkpg_do_ioctl(bdev, udata, op);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
73*4882a593Smuzhiyun struct compat_blkpg_ioctl_arg {
74*4882a593Smuzhiyun 	compat_int_t op;
75*4882a593Smuzhiyun 	compat_int_t flags;
76*4882a593Smuzhiyun 	compat_int_t datalen;
77*4882a593Smuzhiyun 	compat_caddr_t data;
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun 
compat_blkpg_ioctl(struct block_device * bdev,struct compat_blkpg_ioctl_arg __user * arg)80*4882a593Smuzhiyun static int compat_blkpg_ioctl(struct block_device *bdev,
81*4882a593Smuzhiyun 			      struct compat_blkpg_ioctl_arg __user *arg)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	compat_caddr_t udata;
84*4882a593Smuzhiyun 	int op;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	if (get_user(op, &arg->op) || get_user(udata, &arg->data))
87*4882a593Smuzhiyun 		return -EFAULT;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	return blkpg_do_ioctl(bdev, compat_ptr(udata), op);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun #endif
92*4882a593Smuzhiyun 
blkdev_reread_part(struct block_device * bdev,fmode_t mode)93*4882a593Smuzhiyun static int blkdev_reread_part(struct block_device *bdev, fmode_t mode)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	struct block_device *tmp;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (!disk_part_scan_enabled(bdev->bd_disk) || bdev_is_partition(bdev))
98*4882a593Smuzhiyun 		return -EINVAL;
99*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
100*4882a593Smuzhiyun 		return -EACCES;
101*4882a593Smuzhiyun 	if (bdev->bd_part_count)
102*4882a593Smuzhiyun 		return -EBUSY;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	/*
105*4882a593Smuzhiyun 	 * Reopen the device to revalidate the driver state and force a
106*4882a593Smuzhiyun 	 * partition rescan.
107*4882a593Smuzhiyun 	 */
108*4882a593Smuzhiyun 	mode &= ~FMODE_EXCL;
109*4882a593Smuzhiyun 	set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	tmp = blkdev_get_by_dev(bdev->bd_dev, mode, NULL);
112*4882a593Smuzhiyun 	if (IS_ERR(tmp))
113*4882a593Smuzhiyun 		return PTR_ERR(tmp);
114*4882a593Smuzhiyun 	blkdev_put(tmp, mode);
115*4882a593Smuzhiyun 	return 0;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
blk_ioctl_discard(struct block_device * bdev,fmode_t mode,unsigned long arg,unsigned long flags)118*4882a593Smuzhiyun static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
119*4882a593Smuzhiyun 		unsigned long arg, unsigned long flags)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	uint64_t range[2];
122*4882a593Smuzhiyun 	uint64_t start, len;
123*4882a593Smuzhiyun 	struct request_queue *q = bdev_get_queue(bdev);
124*4882a593Smuzhiyun 	int err;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if (!(mode & FMODE_WRITE))
127*4882a593Smuzhiyun 		return -EBADF;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (!blk_queue_discard(q))
130*4882a593Smuzhiyun 		return -EOPNOTSUPP;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	if (copy_from_user(range, (void __user *)arg, sizeof(range)))
133*4882a593Smuzhiyun 		return -EFAULT;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	start = range[0];
136*4882a593Smuzhiyun 	len = range[1];
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if (start & 511)
139*4882a593Smuzhiyun 		return -EINVAL;
140*4882a593Smuzhiyun 	if (len & 511)
141*4882a593Smuzhiyun 		return -EINVAL;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (start + len > i_size_read(bdev->bd_inode))
144*4882a593Smuzhiyun 		return -EINVAL;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	err = truncate_bdev_range(bdev, mode, start, start + len - 1);
147*4882a593Smuzhiyun 	if (err)
148*4882a593Smuzhiyun 		return err;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	return blkdev_issue_discard(bdev, start >> 9, len >> 9,
151*4882a593Smuzhiyun 				    GFP_KERNEL, flags);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
blk_ioctl_zeroout(struct block_device * bdev,fmode_t mode,unsigned long arg)154*4882a593Smuzhiyun static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
155*4882a593Smuzhiyun 		unsigned long arg)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	uint64_t range[2];
158*4882a593Smuzhiyun 	uint64_t start, end, len;
159*4882a593Smuzhiyun 	int err;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	if (!(mode & FMODE_WRITE))
162*4882a593Smuzhiyun 		return -EBADF;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (copy_from_user(range, (void __user *)arg, sizeof(range)))
165*4882a593Smuzhiyun 		return -EFAULT;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	start = range[0];
168*4882a593Smuzhiyun 	len = range[1];
169*4882a593Smuzhiyun 	end = start + len - 1;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	if (start & 511)
172*4882a593Smuzhiyun 		return -EINVAL;
173*4882a593Smuzhiyun 	if (len & 511)
174*4882a593Smuzhiyun 		return -EINVAL;
175*4882a593Smuzhiyun 	if (end >= (uint64_t)i_size_read(bdev->bd_inode))
176*4882a593Smuzhiyun 		return -EINVAL;
177*4882a593Smuzhiyun 	if (end < start)
178*4882a593Smuzhiyun 		return -EINVAL;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	/* Invalidate the page cache, including dirty pages */
181*4882a593Smuzhiyun 	err = truncate_bdev_range(bdev, mode, start, end);
182*4882a593Smuzhiyun 	if (err)
183*4882a593Smuzhiyun 		return err;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
186*4882a593Smuzhiyun 			BLKDEV_ZERO_NOUNMAP);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
put_ushort(unsigned short __user * argp,unsigned short val)189*4882a593Smuzhiyun static int put_ushort(unsigned short __user *argp, unsigned short val)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	return put_user(val, argp);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
put_int(int __user * argp,int val)194*4882a593Smuzhiyun static int put_int(int __user *argp, int val)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	return put_user(val, argp);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
put_uint(unsigned int __user * argp,unsigned int val)199*4882a593Smuzhiyun static int put_uint(unsigned int __user *argp, unsigned int val)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	return put_user(val, argp);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
put_long(long __user * argp,long val)204*4882a593Smuzhiyun static int put_long(long __user *argp, long val)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	return put_user(val, argp);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
put_ulong(unsigned long __user * argp,unsigned long val)209*4882a593Smuzhiyun static int put_ulong(unsigned long __user *argp, unsigned long val)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	return put_user(val, argp);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
put_u64(u64 __user * argp,u64 val)214*4882a593Smuzhiyun static int put_u64(u64 __user *argp, u64 val)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	return put_user(val, argp);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
compat_put_long(compat_long_t __user * argp,long val)220*4882a593Smuzhiyun static int compat_put_long(compat_long_t __user *argp, long val)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	return put_user(val, argp);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
compat_put_ulong(compat_ulong_t __user * argp,compat_ulong_t val)225*4882a593Smuzhiyun static int compat_put_ulong(compat_ulong_t __user *argp, compat_ulong_t val)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	return put_user(val, argp);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun #endif
230*4882a593Smuzhiyun 
__blkdev_driver_ioctl(struct block_device * bdev,fmode_t mode,unsigned cmd,unsigned long arg)231*4882a593Smuzhiyun int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
232*4882a593Smuzhiyun 			unsigned cmd, unsigned long arg)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	struct gendisk *disk = bdev->bd_disk;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	if (disk->fops->ioctl)
237*4882a593Smuzhiyun 		return disk->fops->ioctl(bdev, mode, cmd, arg);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	return -ENOTTY;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun /*
242*4882a593Smuzhiyun  * For the record: _GPL here is only because somebody decided to slap it
243*4882a593Smuzhiyun  * on the previous export.  Sheer idiocy, since it wasn't copyrightable
244*4882a593Smuzhiyun  * at all and could be open-coded without any exports by anybody who cares.
245*4882a593Smuzhiyun  */
246*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
249*4882a593Smuzhiyun /*
250*4882a593Smuzhiyun  * This is the equivalent of compat_ptr_ioctl(), to be used by block
251*4882a593Smuzhiyun  * drivers that implement only commands that are completely compatible
252*4882a593Smuzhiyun  * between 32-bit and 64-bit user space
253*4882a593Smuzhiyun  */
blkdev_compat_ptr_ioctl(struct block_device * bdev,fmode_t mode,unsigned cmd,unsigned long arg)254*4882a593Smuzhiyun int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
255*4882a593Smuzhiyun 			unsigned cmd, unsigned long arg)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	struct gendisk *disk = bdev->bd_disk;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (disk->fops->ioctl)
260*4882a593Smuzhiyun 		return disk->fops->ioctl(bdev, mode, cmd,
261*4882a593Smuzhiyun 					 (unsigned long)compat_ptr(arg));
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return -ENOIOCTLCMD;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
266*4882a593Smuzhiyun #endif
267*4882a593Smuzhiyun 
blkdev_pr_register(struct block_device * bdev,struct pr_registration __user * arg)268*4882a593Smuzhiyun static int blkdev_pr_register(struct block_device *bdev,
269*4882a593Smuzhiyun 		struct pr_registration __user *arg)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
272*4882a593Smuzhiyun 	struct pr_registration reg;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
275*4882a593Smuzhiyun 		return -EPERM;
276*4882a593Smuzhiyun 	if (!ops || !ops->pr_register)
277*4882a593Smuzhiyun 		return -EOPNOTSUPP;
278*4882a593Smuzhiyun 	if (copy_from_user(&reg, arg, sizeof(reg)))
279*4882a593Smuzhiyun 		return -EFAULT;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (reg.flags & ~PR_FL_IGNORE_KEY)
282*4882a593Smuzhiyun 		return -EOPNOTSUPP;
283*4882a593Smuzhiyun 	return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
blkdev_pr_reserve(struct block_device * bdev,struct pr_reservation __user * arg)286*4882a593Smuzhiyun static int blkdev_pr_reserve(struct block_device *bdev,
287*4882a593Smuzhiyun 		struct pr_reservation __user *arg)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
290*4882a593Smuzhiyun 	struct pr_reservation rsv;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
293*4882a593Smuzhiyun 		return -EPERM;
294*4882a593Smuzhiyun 	if (!ops || !ops->pr_reserve)
295*4882a593Smuzhiyun 		return -EOPNOTSUPP;
296*4882a593Smuzhiyun 	if (copy_from_user(&rsv, arg, sizeof(rsv)))
297*4882a593Smuzhiyun 		return -EFAULT;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (rsv.flags & ~PR_FL_IGNORE_KEY)
300*4882a593Smuzhiyun 		return -EOPNOTSUPP;
301*4882a593Smuzhiyun 	return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
blkdev_pr_release(struct block_device * bdev,struct pr_reservation __user * arg)304*4882a593Smuzhiyun static int blkdev_pr_release(struct block_device *bdev,
305*4882a593Smuzhiyun 		struct pr_reservation __user *arg)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
308*4882a593Smuzhiyun 	struct pr_reservation rsv;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
311*4882a593Smuzhiyun 		return -EPERM;
312*4882a593Smuzhiyun 	if (!ops || !ops->pr_release)
313*4882a593Smuzhiyun 		return -EOPNOTSUPP;
314*4882a593Smuzhiyun 	if (copy_from_user(&rsv, arg, sizeof(rsv)))
315*4882a593Smuzhiyun 		return -EFAULT;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (rsv.flags)
318*4882a593Smuzhiyun 		return -EOPNOTSUPP;
319*4882a593Smuzhiyun 	return ops->pr_release(bdev, rsv.key, rsv.type);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
blkdev_pr_preempt(struct block_device * bdev,struct pr_preempt __user * arg,bool abort)322*4882a593Smuzhiyun static int blkdev_pr_preempt(struct block_device *bdev,
323*4882a593Smuzhiyun 		struct pr_preempt __user *arg, bool abort)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
326*4882a593Smuzhiyun 	struct pr_preempt p;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
329*4882a593Smuzhiyun 		return -EPERM;
330*4882a593Smuzhiyun 	if (!ops || !ops->pr_preempt)
331*4882a593Smuzhiyun 		return -EOPNOTSUPP;
332*4882a593Smuzhiyun 	if (copy_from_user(&p, arg, sizeof(p)))
333*4882a593Smuzhiyun 		return -EFAULT;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (p.flags)
336*4882a593Smuzhiyun 		return -EOPNOTSUPP;
337*4882a593Smuzhiyun 	return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
blkdev_pr_clear(struct block_device * bdev,struct pr_clear __user * arg)340*4882a593Smuzhiyun static int blkdev_pr_clear(struct block_device *bdev,
341*4882a593Smuzhiyun 		struct pr_clear __user *arg)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
344*4882a593Smuzhiyun 	struct pr_clear c;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
347*4882a593Smuzhiyun 		return -EPERM;
348*4882a593Smuzhiyun 	if (!ops || !ops->pr_clear)
349*4882a593Smuzhiyun 		return -EOPNOTSUPP;
350*4882a593Smuzhiyun 	if (copy_from_user(&c, arg, sizeof(c)))
351*4882a593Smuzhiyun 		return -EFAULT;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	if (c.flags)
354*4882a593Smuzhiyun 		return -EOPNOTSUPP;
355*4882a593Smuzhiyun 	return ops->pr_clear(bdev, c.key);
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun /*
359*4882a593Smuzhiyun  * Is it an unrecognized ioctl? The correct returns are either
360*4882a593Smuzhiyun  * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a
361*4882a593Smuzhiyun  * fallback"). ENOIOCTLCMD gets turned into ENOTTY by the ioctl
362*4882a593Smuzhiyun  * code before returning.
363*4882a593Smuzhiyun  *
364*4882a593Smuzhiyun  * Confused drivers sometimes return EINVAL, which is wrong. It
365*4882a593Smuzhiyun  * means "I understood the ioctl command, but the parameters to
366*4882a593Smuzhiyun  * it were wrong".
367*4882a593Smuzhiyun  *
368*4882a593Smuzhiyun  * We should aim to just fix the broken drivers, the EINVAL case
369*4882a593Smuzhiyun  * should go away.
370*4882a593Smuzhiyun  */
is_unrecognized_ioctl(int ret)371*4882a593Smuzhiyun static inline int is_unrecognized_ioctl(int ret)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	return	ret == -EINVAL ||
374*4882a593Smuzhiyun 		ret == -ENOTTY ||
375*4882a593Smuzhiyun 		ret == -ENOIOCTLCMD;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
blkdev_flushbuf(struct block_device * bdev,fmode_t mode,unsigned cmd,unsigned long arg)378*4882a593Smuzhiyun static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
379*4882a593Smuzhiyun 		unsigned cmd, unsigned long arg)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	int ret;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
384*4882a593Smuzhiyun 		return -EACCES;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
387*4882a593Smuzhiyun 	if (!is_unrecognized_ioctl(ret))
388*4882a593Smuzhiyun 		return ret;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	fsync_bdev(bdev);
391*4882a593Smuzhiyun 	invalidate_bdev(bdev);
392*4882a593Smuzhiyun 	return 0;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun 
blkdev_roset(struct block_device * bdev,fmode_t mode,unsigned cmd,unsigned long arg)395*4882a593Smuzhiyun static int blkdev_roset(struct block_device *bdev, fmode_t mode,
396*4882a593Smuzhiyun 		unsigned cmd, unsigned long arg)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	int ret, n;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
401*4882a593Smuzhiyun 		return -EACCES;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
404*4882a593Smuzhiyun 	if (!is_unrecognized_ioctl(ret))
405*4882a593Smuzhiyun 		return ret;
406*4882a593Smuzhiyun 	if (get_user(n, (int __user *)arg))
407*4882a593Smuzhiyun 		return -EFAULT;
408*4882a593Smuzhiyun 	set_device_ro(bdev, n);
409*4882a593Smuzhiyun 	return 0;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
blkdev_getgeo(struct block_device * bdev,struct hd_geometry __user * argp)412*4882a593Smuzhiyun static int blkdev_getgeo(struct block_device *bdev,
413*4882a593Smuzhiyun 		struct hd_geometry __user *argp)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	struct gendisk *disk = bdev->bd_disk;
416*4882a593Smuzhiyun 	struct hd_geometry geo;
417*4882a593Smuzhiyun 	int ret;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	if (!argp)
420*4882a593Smuzhiyun 		return -EINVAL;
421*4882a593Smuzhiyun 	if (!disk->fops->getgeo)
422*4882a593Smuzhiyun 		return -ENOTTY;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/*
425*4882a593Smuzhiyun 	 * We need to set the startsect first, the driver may
426*4882a593Smuzhiyun 	 * want to override it.
427*4882a593Smuzhiyun 	 */
428*4882a593Smuzhiyun 	memset(&geo, 0, sizeof(geo));
429*4882a593Smuzhiyun 	geo.start = get_start_sect(bdev);
430*4882a593Smuzhiyun 	ret = disk->fops->getgeo(bdev, &geo);
431*4882a593Smuzhiyun 	if (ret)
432*4882a593Smuzhiyun 		return ret;
433*4882a593Smuzhiyun 	if (copy_to_user(argp, &geo, sizeof(geo)))
434*4882a593Smuzhiyun 		return -EFAULT;
435*4882a593Smuzhiyun 	return 0;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
439*4882a593Smuzhiyun struct compat_hd_geometry {
440*4882a593Smuzhiyun 	unsigned char heads;
441*4882a593Smuzhiyun 	unsigned char sectors;
442*4882a593Smuzhiyun 	unsigned short cylinders;
443*4882a593Smuzhiyun 	u32 start;
444*4882a593Smuzhiyun };
445*4882a593Smuzhiyun 
compat_hdio_getgeo(struct block_device * bdev,struct compat_hd_geometry __user * ugeo)446*4882a593Smuzhiyun static int compat_hdio_getgeo(struct block_device *bdev,
447*4882a593Smuzhiyun 			      struct compat_hd_geometry __user *ugeo)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	struct gendisk *disk = bdev->bd_disk;
450*4882a593Smuzhiyun 	struct hd_geometry geo;
451*4882a593Smuzhiyun 	int ret;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	if (!ugeo)
454*4882a593Smuzhiyun 		return -EINVAL;
455*4882a593Smuzhiyun 	if (!disk->fops->getgeo)
456*4882a593Smuzhiyun 		return -ENOTTY;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	memset(&geo, 0, sizeof(geo));
459*4882a593Smuzhiyun 	/*
460*4882a593Smuzhiyun 	 * We need to set the startsect first, the driver may
461*4882a593Smuzhiyun 	 * want to override it.
462*4882a593Smuzhiyun 	 */
463*4882a593Smuzhiyun 	geo.start = get_start_sect(bdev);
464*4882a593Smuzhiyun 	ret = disk->fops->getgeo(bdev, &geo);
465*4882a593Smuzhiyun 	if (ret)
466*4882a593Smuzhiyun 		return ret;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	ret = copy_to_user(ugeo, &geo, 4);
469*4882a593Smuzhiyun 	ret |= put_user(geo.start, &ugeo->start);
470*4882a593Smuzhiyun 	if (ret)
471*4882a593Smuzhiyun 		ret = -EFAULT;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	return ret;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun #endif
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun /* set the logical block size */
blkdev_bszset(struct block_device * bdev,fmode_t mode,int __user * argp)478*4882a593Smuzhiyun static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
479*4882a593Smuzhiyun 		int __user *argp)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	int ret, n;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
484*4882a593Smuzhiyun 		return -EACCES;
485*4882a593Smuzhiyun 	if (!argp)
486*4882a593Smuzhiyun 		return -EINVAL;
487*4882a593Smuzhiyun 	if (get_user(n, argp))
488*4882a593Smuzhiyun 		return -EFAULT;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	if (mode & FMODE_EXCL)
491*4882a593Smuzhiyun 		return set_blocksize(bdev, n);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	if (IS_ERR(blkdev_get_by_dev(bdev->bd_dev, mode | FMODE_EXCL, &bdev)))
494*4882a593Smuzhiyun 		return -EBUSY;
495*4882a593Smuzhiyun 	ret = set_blocksize(bdev, n);
496*4882a593Smuzhiyun 	blkdev_put(bdev, mode | FMODE_EXCL);
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	return ret;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun /*
502*4882a593Smuzhiyun  * Common commands that are handled the same way on native and compat
503*4882a593Smuzhiyun  * user space. Note the separate arg/argp parameters that are needed
504*4882a593Smuzhiyun  * to deal with the compat_ptr() conversion.
505*4882a593Smuzhiyun  */
blkdev_common_ioctl(struct block_device * bdev,fmode_t mode,unsigned cmd,unsigned long arg,void __user * argp)506*4882a593Smuzhiyun static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
507*4882a593Smuzhiyun 				unsigned cmd, unsigned long arg, void __user *argp)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun 	unsigned int max_sectors;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	switch (cmd) {
512*4882a593Smuzhiyun 	case BLKFLSBUF:
513*4882a593Smuzhiyun 		return blkdev_flushbuf(bdev, mode, cmd, arg);
514*4882a593Smuzhiyun 	case BLKROSET:
515*4882a593Smuzhiyun 		return blkdev_roset(bdev, mode, cmd, arg);
516*4882a593Smuzhiyun 	case BLKDISCARD:
517*4882a593Smuzhiyun 		return blk_ioctl_discard(bdev, mode, arg, 0);
518*4882a593Smuzhiyun 	case BLKSECDISCARD:
519*4882a593Smuzhiyun 		return blk_ioctl_discard(bdev, mode, arg,
520*4882a593Smuzhiyun 				BLKDEV_DISCARD_SECURE);
521*4882a593Smuzhiyun 	case BLKZEROOUT:
522*4882a593Smuzhiyun 		return blk_ioctl_zeroout(bdev, mode, arg);
523*4882a593Smuzhiyun 	case BLKREPORTZONE:
524*4882a593Smuzhiyun 		return blkdev_report_zones_ioctl(bdev, mode, cmd, arg);
525*4882a593Smuzhiyun 	case BLKRESETZONE:
526*4882a593Smuzhiyun 	case BLKOPENZONE:
527*4882a593Smuzhiyun 	case BLKCLOSEZONE:
528*4882a593Smuzhiyun 	case BLKFINISHZONE:
529*4882a593Smuzhiyun 		return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
530*4882a593Smuzhiyun 	case BLKGETZONESZ:
531*4882a593Smuzhiyun 		return put_uint(argp, bdev_zone_sectors(bdev));
532*4882a593Smuzhiyun 	case BLKGETNRZONES:
533*4882a593Smuzhiyun 		return put_uint(argp, blkdev_nr_zones(bdev->bd_disk));
534*4882a593Smuzhiyun 	case BLKROGET:
535*4882a593Smuzhiyun 		return put_int(argp, bdev_read_only(bdev) != 0);
536*4882a593Smuzhiyun 	case BLKSSZGET: /* get block device logical block size */
537*4882a593Smuzhiyun 		return put_int(argp, bdev_logical_block_size(bdev));
538*4882a593Smuzhiyun 	case BLKPBSZGET: /* get block device physical block size */
539*4882a593Smuzhiyun 		return put_uint(argp, bdev_physical_block_size(bdev));
540*4882a593Smuzhiyun 	case BLKIOMIN:
541*4882a593Smuzhiyun 		return put_uint(argp, bdev_io_min(bdev));
542*4882a593Smuzhiyun 	case BLKIOOPT:
543*4882a593Smuzhiyun 		return put_uint(argp, bdev_io_opt(bdev));
544*4882a593Smuzhiyun 	case BLKALIGNOFF:
545*4882a593Smuzhiyun 		return put_int(argp, bdev_alignment_offset(bdev));
546*4882a593Smuzhiyun 	case BLKDISCARDZEROES:
547*4882a593Smuzhiyun 		return put_uint(argp, 0);
548*4882a593Smuzhiyun 	case BLKSECTGET:
549*4882a593Smuzhiyun 		max_sectors = min_t(unsigned int, USHRT_MAX,
550*4882a593Smuzhiyun 				    queue_max_sectors(bdev_get_queue(bdev)));
551*4882a593Smuzhiyun 		return put_ushort(argp, max_sectors);
552*4882a593Smuzhiyun 	case BLKROTATIONAL:
553*4882a593Smuzhiyun 		return put_ushort(argp, !blk_queue_nonrot(bdev_get_queue(bdev)));
554*4882a593Smuzhiyun 	case BLKRASET:
555*4882a593Smuzhiyun 	case BLKFRASET:
556*4882a593Smuzhiyun 		if(!capable(CAP_SYS_ADMIN))
557*4882a593Smuzhiyun 			return -EACCES;
558*4882a593Smuzhiyun 		bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
559*4882a593Smuzhiyun 		return 0;
560*4882a593Smuzhiyun 	case BLKRRPART:
561*4882a593Smuzhiyun 		return blkdev_reread_part(bdev, mode);
562*4882a593Smuzhiyun 	case BLKTRACESTART:
563*4882a593Smuzhiyun 	case BLKTRACESTOP:
564*4882a593Smuzhiyun 	case BLKTRACETEARDOWN:
565*4882a593Smuzhiyun 		return blk_trace_ioctl(bdev, cmd, argp);
566*4882a593Smuzhiyun 	case IOC_PR_REGISTER:
567*4882a593Smuzhiyun 		return blkdev_pr_register(bdev, argp);
568*4882a593Smuzhiyun 	case IOC_PR_RESERVE:
569*4882a593Smuzhiyun 		return blkdev_pr_reserve(bdev, argp);
570*4882a593Smuzhiyun 	case IOC_PR_RELEASE:
571*4882a593Smuzhiyun 		return blkdev_pr_release(bdev, argp);
572*4882a593Smuzhiyun 	case IOC_PR_PREEMPT:
573*4882a593Smuzhiyun 		return blkdev_pr_preempt(bdev, argp, false);
574*4882a593Smuzhiyun 	case IOC_PR_PREEMPT_ABORT:
575*4882a593Smuzhiyun 		return blkdev_pr_preempt(bdev, argp, true);
576*4882a593Smuzhiyun 	case IOC_PR_CLEAR:
577*4882a593Smuzhiyun 		return blkdev_pr_clear(bdev, argp);
578*4882a593Smuzhiyun 	default:
579*4882a593Smuzhiyun 		return -ENOIOCTLCMD;
580*4882a593Smuzhiyun 	}
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun /*
584*4882a593Smuzhiyun  * Always keep this in sync with compat_blkdev_ioctl()
585*4882a593Smuzhiyun  * to handle all incompatible commands in both functions.
586*4882a593Smuzhiyun  *
587*4882a593Smuzhiyun  * New commands must be compatible and go into blkdev_common_ioctl
588*4882a593Smuzhiyun  */
blkdev_ioctl(struct block_device * bdev,fmode_t mode,unsigned cmd,unsigned long arg)589*4882a593Smuzhiyun int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
590*4882a593Smuzhiyun 			unsigned long arg)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun 	int ret;
593*4882a593Smuzhiyun 	loff_t size;
594*4882a593Smuzhiyun 	void __user *argp = (void __user *)arg;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	switch (cmd) {
597*4882a593Smuzhiyun 	/* These need separate implementations for the data structure */
598*4882a593Smuzhiyun 	case HDIO_GETGEO:
599*4882a593Smuzhiyun 		return blkdev_getgeo(bdev, argp);
600*4882a593Smuzhiyun 	case BLKPG:
601*4882a593Smuzhiyun 		return blkpg_ioctl(bdev, argp);
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	/* Compat mode returns 32-bit data instead of 'long' */
604*4882a593Smuzhiyun 	case BLKRAGET:
605*4882a593Smuzhiyun 	case BLKFRAGET:
606*4882a593Smuzhiyun 		if (!argp)
607*4882a593Smuzhiyun 			return -EINVAL;
608*4882a593Smuzhiyun 		return put_long(argp, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
609*4882a593Smuzhiyun 	case BLKGETSIZE:
610*4882a593Smuzhiyun 		size = i_size_read(bdev->bd_inode);
611*4882a593Smuzhiyun 		if ((size >> 9) > ~0UL)
612*4882a593Smuzhiyun 			return -EFBIG;
613*4882a593Smuzhiyun 		return put_ulong(argp, size >> 9);
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	/* The data is compatible, but the command number is different */
616*4882a593Smuzhiyun 	case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
617*4882a593Smuzhiyun 		return put_int(argp, block_size(bdev));
618*4882a593Smuzhiyun 	case BLKBSZSET:
619*4882a593Smuzhiyun 		return blkdev_bszset(bdev, mode, argp);
620*4882a593Smuzhiyun 	case BLKGETSIZE64:
621*4882a593Smuzhiyun 		return put_u64(argp, i_size_read(bdev->bd_inode));
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	/* Incompatible alignment on i386 */
624*4882a593Smuzhiyun 	case BLKTRACESETUP:
625*4882a593Smuzhiyun 		return blk_trace_ioctl(bdev, cmd, argp);
626*4882a593Smuzhiyun 	default:
627*4882a593Smuzhiyun 		break;
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
631*4882a593Smuzhiyun 	if (ret == -ENOIOCTLCMD)
632*4882a593Smuzhiyun 		return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	return ret;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(blkdev_ioctl); /* for /dev/raw */
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun #define BLKBSZGET_32		_IOR(0x12, 112, int)
641*4882a593Smuzhiyun #define BLKBSZSET_32		_IOW(0x12, 113, int)
642*4882a593Smuzhiyun #define BLKGETSIZE64_32		_IOR(0x12, 114, int)
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun /* Most of the generic ioctls are handled in the normal fallback path.
645*4882a593Smuzhiyun    This assumes the blkdev's low level compat_ioctl always returns
646*4882a593Smuzhiyun    ENOIOCTLCMD for unknown ioctls. */
compat_blkdev_ioctl(struct file * file,unsigned cmd,unsigned long arg)647*4882a593Smuzhiyun long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun 	int ret;
650*4882a593Smuzhiyun 	void __user *argp = compat_ptr(arg);
651*4882a593Smuzhiyun 	struct inode *inode = file->f_mapping->host;
652*4882a593Smuzhiyun 	struct block_device *bdev = inode->i_bdev;
653*4882a593Smuzhiyun 	struct gendisk *disk = bdev->bd_disk;
654*4882a593Smuzhiyun 	fmode_t mode = file->f_mode;
655*4882a593Smuzhiyun 	loff_t size;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	/*
658*4882a593Smuzhiyun 	 * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
659*4882a593Smuzhiyun 	 * to updated it before every ioctl.
660*4882a593Smuzhiyun 	 */
661*4882a593Smuzhiyun 	if (file->f_flags & O_NDELAY)
662*4882a593Smuzhiyun 		mode |= FMODE_NDELAY;
663*4882a593Smuzhiyun 	else
664*4882a593Smuzhiyun 		mode &= ~FMODE_NDELAY;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	switch (cmd) {
667*4882a593Smuzhiyun 	/* These need separate implementations for the data structure */
668*4882a593Smuzhiyun 	case HDIO_GETGEO:
669*4882a593Smuzhiyun 		return compat_hdio_getgeo(bdev, argp);
670*4882a593Smuzhiyun 	case BLKPG:
671*4882a593Smuzhiyun 		return compat_blkpg_ioctl(bdev, argp);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	/* Compat mode returns 32-bit data instead of 'long' */
674*4882a593Smuzhiyun 	case BLKRAGET:
675*4882a593Smuzhiyun 	case BLKFRAGET:
676*4882a593Smuzhiyun 		if (!argp)
677*4882a593Smuzhiyun 			return -EINVAL;
678*4882a593Smuzhiyun 		return compat_put_long(argp,
679*4882a593Smuzhiyun 			       (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
680*4882a593Smuzhiyun 	case BLKGETSIZE:
681*4882a593Smuzhiyun 		size = i_size_read(bdev->bd_inode);
682*4882a593Smuzhiyun 		if ((size >> 9) > ~(compat_ulong_t)0)
683*4882a593Smuzhiyun 			return -EFBIG;
684*4882a593Smuzhiyun 		return compat_put_ulong(argp, size >> 9);
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	/* The data is compatible, but the command number is different */
687*4882a593Smuzhiyun 	case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
688*4882a593Smuzhiyun 		return put_int(argp, bdev_logical_block_size(bdev));
689*4882a593Smuzhiyun 	case BLKBSZSET_32:
690*4882a593Smuzhiyun 		return blkdev_bszset(bdev, mode, argp);
691*4882a593Smuzhiyun 	case BLKGETSIZE64_32:
692*4882a593Smuzhiyun 		return put_u64(argp, i_size_read(bdev->bd_inode));
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	/* Incompatible alignment on i386 */
695*4882a593Smuzhiyun 	case BLKTRACESETUP32:
696*4882a593Smuzhiyun 		return blk_trace_ioctl(bdev, cmd, argp);
697*4882a593Smuzhiyun 	default:
698*4882a593Smuzhiyun 		break;
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
702*4882a593Smuzhiyun 	if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
703*4882a593Smuzhiyun 		ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	return ret;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun #endif
708