]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - block/ioctl.c
compat_ioctl: block: move blkdev_compat_ioctl() into ioctl.c
[mirror_ubuntu-jammy-kernel.git] / block / ioctl.c
CommitLineData
3dcf60bc 1// SPDX-License-Identifier: GPL-2.0
c59ede7b 2#include <linux/capability.h>
ee6a129d 3#include <linux/compat.h>
1da177e4 4#include <linux/blkdev.h>
d5decd3b 5#include <linux/export.h>
5a0e3ad6 6#include <linux/gfp.h>
1da177e4 7#include <linux/blkpg.h>
a885c8c4 8#include <linux/hdreg.h>
1da177e4 9#include <linux/backing-dev.h>
ff01bb48 10#include <linux/fs.h>
2056a782 11#include <linux/blktrace_api.h>
bbd3e064 12#include <linux/pr.h>
7c0f6ba6 13#include <linux/uaccess.h>
1da177e4
LT
14
15static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
16{
17 struct block_device *bdevp;
18 struct gendisk *disk;
c83f6bf9 19 struct hd_struct *part, *lpart;
1da177e4
LT
20 struct blkpg_ioctl_arg a;
21 struct blkpg_partition p;
e71bf0d0 22 struct disk_part_iter piter;
1da177e4 23 long long start, length;
cf771cb5 24 int partno;
1da177e4
LT
25
26 if (!capable(CAP_SYS_ADMIN))
27 return -EACCES;
28 if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
29 return -EFAULT;
30 if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
31 return -EFAULT;
32 disk = bdev->bd_disk;
33 if (bdev != bdev->bd_contains)
34 return -EINVAL;
cf771cb5 35 partno = p.pno;
540eed56 36 if (partno <= 0)
1da177e4
LT
37 return -EINVAL;
38 switch (a.op) {
39 case BLKPG_ADD_PARTITION:
40 start = p.start >> 9;
41 length = p.length >> 9;
c83f6bf9
VG
42 /* check for fit in a hd_struct */
43 if (sizeof(sector_t) == sizeof(long) &&
1da177e4
LT
44 sizeof(long long) > sizeof(long)) {
45 long pstart = start, plength = length;
46 if (pstart != start || plength != length
2bd6efad 47 || pstart < 0 || plength < 0 || partno > 65535)
1da177e4
LT
48 return -EINVAL;
49 }
633395b6
SH
50 /* check if partition is aligned to blocksize */
51 if (p.start & (bdev_logical_block_size(bdev) - 1))
52 return -EINVAL;
88e34126 53
c039e313 54 mutex_lock(&bdev->bd_mutex);
88e34126 55
1da177e4 56 /* overlap? */
e71bf0d0
TH
57 disk_part_iter_init(&piter, disk,
58 DISK_PITER_INCL_EMPTY);
59 while ((part = disk_part_iter_next(&piter))) {
60 if (!(start + length <= part->start_sect ||
61 start >= part->start_sect + part->nr_sects)) {
62 disk_part_iter_exit(&piter);
c039e313 63 mutex_unlock(&bdev->bd_mutex);
1da177e4
LT
64 return -EBUSY;
65 }
66 }
e71bf0d0
TH
67 disk_part_iter_exit(&piter);
68
1da177e4 69 /* all seems OK */
ba32929a 70 part = add_partition(disk, partno, start, length,
6d1d8050 71 ADDPART_FLAG_NONE, NULL);
c039e313 72 mutex_unlock(&bdev->bd_mutex);
c7d1ba41 73 return PTR_ERR_OR_ZERO(part);
1da177e4 74 case BLKPG_DEL_PARTITION:
e71bf0d0
TH
75 part = disk_get_part(disk, partno);
76 if (!part)
1da177e4 77 return -ENXIO;
e71bf0d0
TH
78
79 bdevp = bdget(part_devt(part));
80 disk_put_part(part);
1da177e4
LT
81 if (!bdevp)
82 return -ENOMEM;
e71bf0d0 83
2e7b651d 84 mutex_lock(&bdevp->bd_mutex);
1da177e4 85 if (bdevp->bd_openers) {
c039e313 86 mutex_unlock(&bdevp->bd_mutex);
1da177e4
LT
87 bdput(bdevp);
88 return -EBUSY;
89 }
90 /* all seems OK */
91 fsync_bdev(bdevp);
f98393a6 92 invalidate_bdev(bdevp);
1da177e4 93
6d740cd5 94 mutex_lock_nested(&bdev->bd_mutex, 1);
cf771cb5 95 delete_partition(disk, partno);
c039e313
AV
96 mutex_unlock(&bdev->bd_mutex);
97 mutex_unlock(&bdevp->bd_mutex);
1da177e4
LT
98 bdput(bdevp);
99
c83f6bf9
VG
100 return 0;
101 case BLKPG_RESIZE_PARTITION:
102 start = p.start >> 9;
103 /* new length of partition in bytes */
104 length = p.length >> 9;
105 /* check for fit in a hd_struct */
106 if (sizeof(sector_t) == sizeof(long) &&
107 sizeof(long long) > sizeof(long)) {
108 long pstart = start, plength = length;
109 if (pstart != start || plength != length
110 || pstart < 0 || plength < 0)
111 return -EINVAL;
112 }
113 part = disk_get_part(disk, partno);
114 if (!part)
115 return -ENXIO;
116 bdevp = bdget(part_devt(part));
117 if (!bdevp) {
118 disk_put_part(part);
119 return -ENOMEM;
120 }
121 mutex_lock(&bdevp->bd_mutex);
122 mutex_lock_nested(&bdev->bd_mutex, 1);
123 if (start != part->start_sect) {
124 mutex_unlock(&bdevp->bd_mutex);
125 mutex_unlock(&bdev->bd_mutex);
126 bdput(bdevp);
127 disk_put_part(part);
128 return -EINVAL;
129 }
130 /* overlap? */
131 disk_part_iter_init(&piter, disk,
132 DISK_PITER_INCL_EMPTY);
133 while ((lpart = disk_part_iter_next(&piter))) {
134 if (lpart->partno != partno &&
135 !(start + length <= lpart->start_sect ||
136 start >= lpart->start_sect + lpart->nr_sects)
137 ) {
138 disk_part_iter_exit(&piter);
139 mutex_unlock(&bdevp->bd_mutex);
140 mutex_unlock(&bdev->bd_mutex);
141 bdput(bdevp);
142 disk_put_part(part);
143 return -EBUSY;
144 }
145 }
146 disk_part_iter_exit(&piter);
147 part_nr_sects_write(part, (sector_t)length);
148 i_size_write(bdevp->bd_inode, p.length);
149 mutex_unlock(&bdevp->bd_mutex);
150 mutex_unlock(&bdev->bd_mutex);
151 bdput(bdevp);
152 disk_put_part(part);
1da177e4
LT
153 return 0;
154 default:
155 return -EINVAL;
156 }
157}
158
f0b870df 159static int blkdev_reread_part(struct block_device *bdev)
1da177e4 160{
f0b870df
CH
161 int ret;
162
142fe8f4 163 if (!disk_part_scan_enabled(bdev->bd_disk) || bdev != bdev->bd_contains)
1da177e4
LT
164 return -EINVAL;
165 if (!capable(CAP_SYS_ADMIN))
166 return -EACCES;
be324177 167
b04a5636 168 mutex_lock(&bdev->bd_mutex);
f0b870df 169 ret = bdev_disk_changed(bdev, false);
c039e313 170 mutex_unlock(&bdev->bd_mutex);
be324177 171
f0b870df 172 return ret;
1da177e4
LT
173}
174
d8e4bb81
CH
175static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
176 unsigned long arg, unsigned long flags)
d30a2605 177{
d8e4bb81
CH
178 uint64_t range[2];
179 uint64_t start, len;
351499a1
DM
180 struct request_queue *q = bdev_get_queue(bdev);
181 struct address_space *mapping = bdev->bd_inode->i_mapping;
182
d8e4bb81
CH
183
184 if (!(mode & FMODE_WRITE))
185 return -EBADF;
186
351499a1
DM
187 if (!blk_queue_discard(q))
188 return -EOPNOTSUPP;
189
d8e4bb81
CH
190 if (copy_from_user(range, (void __user *)arg, sizeof(range)))
191 return -EFAULT;
192
193 start = range[0];
194 len = range[1];
8d57a98c 195
d30a2605
DW
196 if (start & 511)
197 return -EINVAL;
198 if (len & 511)
199 return -EINVAL;
d30a2605 200
351499a1 201 if (start + len > i_size_read(bdev->bd_inode))
d30a2605 202 return -EINVAL;
0bd1ed48 203 truncate_inode_pages_range(mapping, start, start + len - 1);
351499a1
DM
204 return blkdev_issue_discard(bdev, start >> 9, len >> 9,
205 GFP_KERNEL, flags);
d30a2605
DW
206}
207
d8e4bb81
CH
208static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
209 unsigned long arg)
66ba32dc 210{
d8e4bb81 211 uint64_t range[2];
22dd6d35
DW
212 struct address_space *mapping;
213 uint64_t start, end, len;
d8e4bb81
CH
214
215 if (!(mode & FMODE_WRITE))
216 return -EBADF;
217
218 if (copy_from_user(range, (void __user *)arg, sizeof(range)))
219 return -EFAULT;
220
221 start = range[0];
222 len = range[1];
22dd6d35 223 end = start + len - 1;
d8e4bb81 224
66ba32dc
MP
225 if (start & 511)
226 return -EINVAL;
227 if (len & 511)
228 return -EINVAL;
22dd6d35
DW
229 if (end >= (uint64_t)i_size_read(bdev->bd_inode))
230 return -EINVAL;
231 if (end < start)
66ba32dc
MP
232 return -EINVAL;
233
22dd6d35
DW
234 /* Invalidate the page cache, including dirty pages */
235 mapping = bdev->bd_inode->i_mapping;
236 truncate_inode_pages_range(mapping, start, end);
237
238 return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
ee472d83 239 BLKDEV_ZERO_NOUNMAP);
66ba32dc
MP
240}
241
1da177e4
LT
242static int put_ushort(unsigned long arg, unsigned short val)
243{
244 return put_user(val, (unsigned short __user *)arg);
245}
246
247static int put_int(unsigned long arg, int val)
248{
249 return put_user(val, (int __user *)arg);
250}
251
ac481c20
MP
252static int put_uint(unsigned long arg, unsigned int val)
253{
254 return put_user(val, (unsigned int __user *)arg);
255}
256
1da177e4
LT
257static int put_long(unsigned long arg, long val)
258{
259 return put_user(val, (long __user *)arg);
260}
261
262static int put_ulong(unsigned long arg, unsigned long val)
263{
264 return put_user(val, (unsigned long __user *)arg);
265}
266
267static int put_u64(unsigned long arg, u64 val)
268{
269 return put_user(val, (u64 __user *)arg);
270}
271
bdc1ddad
AB
272#ifdef CONFIG_COMPAT
273static int compat_put_ushort(unsigned long arg, unsigned short val)
274{
275 return put_user(val, (unsigned short __user *)compat_ptr(arg));
276}
277
278static int compat_put_int(unsigned long arg, int val)
279{
280 return put_user(val, (compat_int_t __user *)compat_ptr(arg));
281}
282
283static int compat_put_uint(unsigned long arg, unsigned int val)
284{
285 return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
286}
287
288static int compat_put_long(unsigned long arg, long val)
289{
290 return put_user(val, (compat_long_t __user *)compat_ptr(arg));
291}
292
293static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
294{
295 return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
296}
297
298static int compat_put_u64(unsigned long arg, u64 val)
299{
300 return put_user(val, (compat_u64 __user *)compat_ptr(arg));
301}
302#endif
303
633a08b8
AV
304int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
305 unsigned cmd, unsigned long arg)
306{
307 struct gendisk *disk = bdev->bd_disk;
d4430d62
AV
308
309 if (disk->fops->ioctl)
310 return disk->fops->ioctl(bdev, mode, cmd, arg);
633a08b8 311
633a08b8
AV
312 return -ENOTTY;
313}
314/*
315 * For the record: _GPL here is only because somebody decided to slap it
316 * on the previous export. Sheer idiocy, since it wasn't copyrightable
317 * at all and could be open-coded without any exports by anybody who cares.
318 */
319EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
320
ee6a129d
AB
321#ifdef CONFIG_COMPAT
322/*
323 * This is the equivalent of compat_ptr_ioctl(), to be used by block
324 * drivers that implement only commands that are completely compatible
325 * between 32-bit and 64-bit user space
326 */
327int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
328 unsigned cmd, unsigned long arg)
329{
330 struct gendisk *disk = bdev->bd_disk;
331
332 if (disk->fops->ioctl)
333 return disk->fops->ioctl(bdev, mode, cmd,
334 (unsigned long)compat_ptr(arg));
335
336 return -ENOIOCTLCMD;
337}
338EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
339#endif
340
bbd3e064
CH
341static int blkdev_pr_register(struct block_device *bdev,
342 struct pr_registration __user *arg)
343{
344 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
345 struct pr_registration reg;
346
347 if (!capable(CAP_SYS_ADMIN))
348 return -EPERM;
349 if (!ops || !ops->pr_register)
350 return -EOPNOTSUPP;
351 if (copy_from_user(&reg, arg, sizeof(reg)))
352 return -EFAULT;
353
354 if (reg.flags & ~PR_FL_IGNORE_KEY)
355 return -EOPNOTSUPP;
356 return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags);
357}
358
359static int blkdev_pr_reserve(struct block_device *bdev,
360 struct pr_reservation __user *arg)
361{
362 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
363 struct pr_reservation rsv;
364
365 if (!capable(CAP_SYS_ADMIN))
366 return -EPERM;
367 if (!ops || !ops->pr_reserve)
368 return -EOPNOTSUPP;
369 if (copy_from_user(&rsv, arg, sizeof(rsv)))
370 return -EFAULT;
371
372 if (rsv.flags & ~PR_FL_IGNORE_KEY)
373 return -EOPNOTSUPP;
374 return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags);
375}
376
377static int blkdev_pr_release(struct block_device *bdev,
378 struct pr_reservation __user *arg)
379{
380 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
381 struct pr_reservation rsv;
382
383 if (!capable(CAP_SYS_ADMIN))
384 return -EPERM;
385 if (!ops || !ops->pr_release)
386 return -EOPNOTSUPP;
387 if (copy_from_user(&rsv, arg, sizeof(rsv)))
388 return -EFAULT;
389
390 if (rsv.flags)
391 return -EOPNOTSUPP;
392 return ops->pr_release(bdev, rsv.key, rsv.type);
393}
394
395static int blkdev_pr_preempt(struct block_device *bdev,
396 struct pr_preempt __user *arg, bool abort)
397{
398 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
399 struct pr_preempt p;
400
401 if (!capable(CAP_SYS_ADMIN))
402 return -EPERM;
403 if (!ops || !ops->pr_preempt)
404 return -EOPNOTSUPP;
405 if (copy_from_user(&p, arg, sizeof(p)))
406 return -EFAULT;
407
408 if (p.flags)
409 return -EOPNOTSUPP;
410 return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort);
411}
412
413static int blkdev_pr_clear(struct block_device *bdev,
414 struct pr_clear __user *arg)
415{
416 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
417 struct pr_clear c;
418
419 if (!capable(CAP_SYS_ADMIN))
420 return -EPERM;
421 if (!ops || !ops->pr_clear)
422 return -EOPNOTSUPP;
423 if (copy_from_user(&c, arg, sizeof(c)))
424 return -EFAULT;
425
426 if (c.flags)
427 return -EOPNOTSUPP;
428 return ops->pr_clear(bdev, c.key);
429}
430
07d106d0
LT
431/*
432 * Is it an unrecognized ioctl? The correct returns are either
433 * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a
434 * fallback"). ENOIOCTLCMD gets turned into ENOTTY by the ioctl
435 * code before returning.
436 *
437 * Confused drivers sometimes return EINVAL, which is wrong. It
438 * means "I understood the ioctl command, but the parameters to
439 * it were wrong".
440 *
441 * We should aim to just fix the broken drivers, the EINVAL case
442 * should go away.
443 */
444static inline int is_unrecognized_ioctl(int ret)
445{
446 return ret == -EINVAL ||
447 ret == -ENOTTY ||
448 ret == -ENOIOCTLCMD;
449}
450
d8e4bb81
CH
451static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
452 unsigned cmd, unsigned long arg)
bb93e3a5 453{
d8e4bb81 454 int ret;
bb93e3a5 455
d8e4bb81
CH
456 if (!capable(CAP_SYS_ADMIN))
457 return -EACCES;
bb93e3a5 458
d8e4bb81
CH
459 ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
460 if (!is_unrecognized_ioctl(ret))
461 return ret;
bb93e3a5 462
d8e4bb81
CH
463 fsync_bdev(bdev);
464 invalidate_bdev(bdev);
465 return 0;
466}
d30a2605 467
d8e4bb81
CH
468static int blkdev_roset(struct block_device *bdev, fmode_t mode,
469 unsigned cmd, unsigned long arg)
470{
471 int ret, n;
d30a2605 472
bb749b31
ID
473 if (!capable(CAP_SYS_ADMIN))
474 return -EACCES;
475
d8e4bb81
CH
476 ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
477 if (!is_unrecognized_ioctl(ret))
478 return ret;
d8e4bb81
CH
479 if (get_user(n, (int __user *)arg))
480 return -EFAULT;
481 set_device_ro(bdev, n);
482 return 0;
483}
d30a2605 484
d8e4bb81
CH
485static int blkdev_getgeo(struct block_device *bdev,
486 struct hd_geometry __user *argp)
487{
488 struct gendisk *disk = bdev->bd_disk;
489 struct hd_geometry geo;
490 int ret;
d30a2605 491
d8e4bb81
CH
492 if (!argp)
493 return -EINVAL;
494 if (!disk->fops->getgeo)
495 return -ENOTTY;
496
497 /*
498 * We need to set the startsect first, the driver may
499 * want to override it.
500 */
501 memset(&geo, 0, sizeof(geo));
502 geo.start = get_start_sect(bdev);
503 ret = disk->fops->getgeo(bdev, &geo);
504 if (ret)
505 return ret;
506 if (copy_to_user(argp, &geo, sizeof(geo)))
507 return -EFAULT;
508 return 0;
509}
66ba32dc 510
bdc1ddad
AB
511#ifdef CONFIG_COMPAT
512struct compat_hd_geometry {
513 unsigned char heads;
514 unsigned char sectors;
515 unsigned short cylinders;
516 u32 start;
517};
518
519static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
520 struct compat_hd_geometry __user *ugeo)
521{
522 struct hd_geometry geo;
523 int ret;
524
525 if (!ugeo)
526 return -EINVAL;
527 if (!disk->fops->getgeo)
528 return -ENOTTY;
529
530 memset(&geo, 0, sizeof(geo));
531 /*
532 * We need to set the startsect first, the driver may
533 * want to override it.
534 */
535 geo.start = get_start_sect(bdev);
536 ret = disk->fops->getgeo(bdev, &geo);
537 if (ret)
538 return ret;
539
540 ret = copy_to_user(ugeo, &geo, 4);
541 ret |= put_user(geo.start, &ugeo->start);
542 if (ret)
543 ret = -EFAULT;
544
545 return ret;
546}
547#endif
548
d8e4bb81
CH
549/* set the logical block size */
550static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
551 int __user *argp)
552{
553 int ret, n;
66ba32dc 554
d8e4bb81
CH
555 if (!capable(CAP_SYS_ADMIN))
556 return -EACCES;
557 if (!argp)
558 return -EINVAL;
559 if (get_user(n, argp))
560 return -EFAULT;
66ba32dc 561
d8e4bb81
CH
562 if (!(mode & FMODE_EXCL)) {
563 bdgrab(bdev);
564 if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
565 return -EBUSY;
66ba32dc 566 }
d30a2605 567
d8e4bb81
CH
568 ret = set_blocksize(bdev, n);
569 if (!(mode & FMODE_EXCL))
570 blkdev_put(bdev, mode | FMODE_EXCL);
571 return ret;
572}
a885c8c4 573
d8e4bb81
CH
574/*
575 * always keep this in sync with compat_blkdev_ioctl()
576 */
577int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
578 unsigned long arg)
579{
d8e4bb81
CH
580 void __user *argp = (void __user *)arg;
581 loff_t size;
582 unsigned int max_sectors;
583
584 switch (cmd) {
585 case BLKFLSBUF:
586 return blkdev_flushbuf(bdev, mode, cmd, arg);
587 case BLKROSET:
588 return blkdev_roset(bdev, mode, cmd, arg);
589 case BLKDISCARD:
590 return blk_ioctl_discard(bdev, mode, arg, 0);
591 case BLKSECDISCARD:
592 return blk_ioctl_discard(bdev, mode, arg,
593 BLKDEV_DISCARD_SECURE);
594 case BLKZEROOUT:
595 return blk_ioctl_zeroout(bdev, mode, arg);
3ed05a98
ST
596 case BLKREPORTZONE:
597 return blkdev_report_zones_ioctl(bdev, mode, cmd, arg);
598 case BLKRESETZONE:
e876df1f
AJ
599 case BLKOPENZONE:
600 case BLKCLOSEZONE:
601 case BLKFINISHZONE:
602 return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
72cd8757
DLM
603 case BLKGETZONESZ:
604 return put_uint(arg, bdev_zone_sectors(bdev));
65e4e3ee 605 case BLKGETNRZONES:
9b38bb4b 606 return put_uint(arg, blkdev_nr_zones(bdev->bd_disk));
d8e4bb81
CH
607 case HDIO_GETGEO:
608 return blkdev_getgeo(bdev, argp);
45048d09
AV
609 case BLKRAGET:
610 case BLKFRAGET:
611 if (!arg)
612 return -EINVAL;
efa7c9f9 613 return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
45048d09
AV
614 case BLKROGET:
615 return put_int(arg, bdev_read_only(bdev) != 0);
ac481c20 616 case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
45048d09 617 return put_int(arg, block_size(bdev));
ac481c20 618 case BLKSSZGET: /* get block device logical block size */
e1defc4f 619 return put_int(arg, bdev_logical_block_size(bdev));
ac481c20
MP
620 case BLKPBSZGET: /* get block device physical block size */
621 return put_uint(arg, bdev_physical_block_size(bdev));
622 case BLKIOMIN:
623 return put_uint(arg, bdev_io_min(bdev));
624 case BLKIOOPT:
625 return put_uint(arg, bdev_io_opt(bdev));
626 case BLKALIGNOFF:
627 return put_int(arg, bdev_alignment_offset(bdev));
98262f27 628 case BLKDISCARDZEROES:
48920ff2 629 return put_uint(arg, 0);
45048d09 630 case BLKSECTGET:
63f26496
AM
631 max_sectors = min_t(unsigned int, USHRT_MAX,
632 queue_max_sectors(bdev_get_queue(bdev)));
633 return put_ushort(arg, max_sectors);
ef00f59c
MP
634 case BLKROTATIONAL:
635 return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
45048d09
AV
636 case BLKRASET:
637 case BLKFRASET:
638 if(!capable(CAP_SYS_ADMIN))
639 return -EACCES;
efa7c9f9 640 bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
45048d09
AV
641 return 0;
642 case BLKBSZSET:
d8e4bb81 643 return blkdev_bszset(bdev, mode, argp);
45048d09 644 case BLKPG:
d8e4bb81 645 return blkpg_ioctl(bdev, argp);
45048d09 646 case BLKRRPART:
d8e4bb81 647 return blkdev_reread_part(bdev);
45048d09 648 case BLKGETSIZE:
77304d2a 649 size = i_size_read(bdev->bd_inode);
45048d09
AV
650 if ((size >> 9) > ~0UL)
651 return -EFBIG;
652 return put_ulong(arg, size >> 9);
653 case BLKGETSIZE64:
77304d2a 654 return put_u64(arg, i_size_read(bdev->bd_inode));
45048d09
AV
655 case BLKTRACESTART:
656 case BLKTRACESTOP:
657 case BLKTRACESETUP:
658 case BLKTRACETEARDOWN:
d8e4bb81 659 return blk_trace_ioctl(bdev, cmd, argp);
bbd3e064
CH
660 case IOC_PR_REGISTER:
661 return blkdev_pr_register(bdev, argp);
662 case IOC_PR_RESERVE:
663 return blkdev_pr_reserve(bdev, argp);
664 case IOC_PR_RELEASE:
665 return blkdev_pr_release(bdev, argp);
666 case IOC_PR_PREEMPT:
667 return blkdev_pr_preempt(bdev, argp, false);
668 case IOC_PR_PREEMPT_ABORT:
669 return blkdev_pr_preempt(bdev, argp, true);
670 case IOC_PR_CLEAR:
671 return blkdev_pr_clear(bdev, argp);
45048d09 672 default:
d8e4bb81 673 return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
45048d09 674 }
1da177e4 675}
68f66feb 676EXPORT_SYMBOL_GPL(blkdev_ioctl);
bdc1ddad
AB
677
678#ifdef CONFIG_COMPAT
679struct compat_blkpg_ioctl_arg {
680 compat_int_t op;
681 compat_int_t flags;
682 compat_int_t datalen;
683 compat_caddr_t data;
684};
685
686static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
687 unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
688{
689 struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
690 compat_caddr_t udata;
691 compat_int_t n;
692 int err;
693
694 err = get_user(n, &ua32->op);
695 err |= put_user(n, &a->op);
696 err |= get_user(n, &ua32->flags);
697 err |= put_user(n, &a->flags);
698 err |= get_user(n, &ua32->datalen);
699 err |= put_user(n, &a->datalen);
700 err |= get_user(udata, &ua32->data);
701 err |= put_user(compat_ptr(udata), &a->data);
702 if (err)
703 return err;
704
705 return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
706}
707
708#define BLKBSZGET_32 _IOR(0x12, 112, int)
709#define BLKBSZSET_32 _IOW(0x12, 113, int)
710#define BLKGETSIZE64_32 _IOR(0x12, 114, int)
711
712/* Most of the generic ioctls are handled in the normal fallback path.
713 This assumes the blkdev's low level compat_ioctl always returns
714 ENOIOCTLCMD for unknown ioctls. */
715long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
716{
717 int ret = -ENOIOCTLCMD;
718 struct inode *inode = file->f_mapping->host;
719 struct block_device *bdev = inode->i_bdev;
720 struct gendisk *disk = bdev->bd_disk;
721 fmode_t mode = file->f_mode;
722 loff_t size;
723 unsigned int max_sectors;
724
725 /*
726 * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
727 * to updated it before every ioctl.
728 */
729 if (file->f_flags & O_NDELAY)
730 mode |= FMODE_NDELAY;
731 else
732 mode &= ~FMODE_NDELAY;
733
734 switch (cmd) {
735 case HDIO_GETGEO:
736 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
737 case BLKPBSZGET:
738 return compat_put_uint(arg, bdev_physical_block_size(bdev));
739 case BLKIOMIN:
740 return compat_put_uint(arg, bdev_io_min(bdev));
741 case BLKIOOPT:
742 return compat_put_uint(arg, bdev_io_opt(bdev));
743 case BLKALIGNOFF:
744 return compat_put_int(arg, bdev_alignment_offset(bdev));
745 case BLKDISCARDZEROES:
746 return compat_put_uint(arg, 0);
747 case BLKFLSBUF:
748 case BLKROSET:
749 case BLKDISCARD:
750 case BLKSECDISCARD:
751 case BLKZEROOUT:
752 /*
753 * the ones below are implemented in blkdev_locked_ioctl,
754 * but we call blkdev_ioctl, which gets the lock for us
755 */
756 case BLKRRPART:
757 case BLKREPORTZONE:
758 case BLKRESETZONE:
759 case BLKOPENZONE:
760 case BLKCLOSEZONE:
761 case BLKFINISHZONE:
762 case BLKGETZONESZ:
763 case BLKGETNRZONES:
764 return blkdev_ioctl(bdev, mode, cmd,
765 (unsigned long)compat_ptr(arg));
766 case BLKBSZSET_32:
767 return blkdev_ioctl(bdev, mode, BLKBSZSET,
768 (unsigned long)compat_ptr(arg));
769 case BLKPG:
770 return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
771 case BLKRAGET:
772 case BLKFRAGET:
773 if (!arg)
774 return -EINVAL;
775 return compat_put_long(arg,
776 (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
777 case BLKROGET: /* compatible */
778 return compat_put_int(arg, bdev_read_only(bdev) != 0);
779 case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
780 return compat_put_int(arg, block_size(bdev));
781 case BLKSSZGET: /* get block device hardware sector size */
782 return compat_put_int(arg, bdev_logical_block_size(bdev));
783 case BLKSECTGET:
784 max_sectors = min_t(unsigned int, USHRT_MAX,
785 queue_max_sectors(bdev_get_queue(bdev)));
786 return compat_put_ushort(arg, max_sectors);
787 case BLKROTATIONAL:
788 return compat_put_ushort(arg,
789 !blk_queue_nonrot(bdev_get_queue(bdev)));
790 case BLKRASET: /* compatible, but no compat_ptr (!) */
791 case BLKFRASET:
792 if (!capable(CAP_SYS_ADMIN))
793 return -EACCES;
794 bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
795 return 0;
796 case BLKGETSIZE:
797 size = i_size_read(bdev->bd_inode);
798 if ((size >> 9) > ~0UL)
799 return -EFBIG;
800 return compat_put_ulong(arg, size >> 9);
801
802 case BLKGETSIZE64_32:
803 return compat_put_u64(arg, i_size_read(bdev->bd_inode));
804
805 case BLKTRACESETUP32:
806 case BLKTRACESTART: /* compatible */
807 case BLKTRACESTOP: /* compatible */
808 case BLKTRACETEARDOWN: /* compatible */
809 ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
810 return ret;
811 case IOC_PR_REGISTER:
812 case IOC_PR_RESERVE:
813 case IOC_PR_RELEASE:
814 case IOC_PR_PREEMPT:
815 case IOC_PR_PREEMPT_ABORT:
816 case IOC_PR_CLEAR:
817 return blkdev_ioctl(bdev, mode, cmd,
818 (unsigned long)compat_ptr(arg));
819 default:
820 if (disk->fops->compat_ioctl)
821 ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
822 return ret;
823 }
824}
825#endif