]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - block/ioctl.c
Merge tag 'for-6.10/block-20240511' of git://git.kernel.dk/linux
[thirdparty/kernel/stable.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>
581e2600 14#include "blk.h"
1da177e4 15
5fb889f5
AB
16static int blkpg_do_ioctl(struct block_device *bdev,
17 struct blkpg_partition __user *upart, int op)
1da177e4 18{
7f6be376 19 struct gendisk *disk = bdev->bd_disk;
1da177e4 20 struct blkpg_partition p;
b9355185 21 sector_t start, length, capacity, end;
1da177e4
LT
22
23 if (!capable(CAP_SYS_ADMIN))
24 return -EACCES;
5fb889f5 25 if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
1da177e4 26 return -EFAULT;
fa01b1e9 27 if (bdev_is_partition(bdev))
1da177e4 28 return -EINVAL;
88e34126 29
fa9156ae
CH
30 if (p.pno <= 0)
31 return -EINVAL;
e71bf0d0 32
fa9156ae 33 if (op == BLKPG_DEL_PARTITION)
926fbb16 34 return bdev_del_partition(disk, p.pno);
e71bf0d0 35
ccb326b5 36 if (p.start < 0 || p.length <= 0 || LLONG_MAX - p.length < p.start)
6f64f866
ML
37 return -EINVAL;
38 /* Check that the partition is aligned to the block size */
39 if (!IS_ALIGNED(p.start | p.length, bdev_logical_block_size(bdev)))
40 return -EINVAL;
41
fa9156ae
CH
42 start = p.start >> SECTOR_SHIFT;
43 length = p.length >> SECTOR_SHIFT;
b9355185
LL
44 capacity = get_capacity(disk);
45
46 if (check_add_overflow(start, length, &end))
47 return -EINVAL;
48
49 if (start >= capacity || end > capacity)
50 return -EINVAL;
e71bf0d0 51
fa9156ae
CH
52 switch (op) {
53 case BLKPG_ADD_PARTITION:
7f6be376 54 return bdev_add_partition(disk, p.pno, start, length);
fa9156ae 55 case BLKPG_RESIZE_PARTITION:
3d2e7989 56 return bdev_resize_partition(disk, p.pno, start, length);
fa9156ae
CH
57 default:
58 return -EINVAL;
1da177e4
LT
59 }
60}
61
5fb889f5
AB
62static int blkpg_ioctl(struct block_device *bdev,
63 struct blkpg_ioctl_arg __user *arg)
64{
65 struct blkpg_partition __user *udata;
66 int op;
67
68 if (get_user(op, &arg->op) || get_user(udata, &arg->data))
69 return -EFAULT;
70
71 return blkpg_do_ioctl(bdev, udata, op);
72}
73
74#ifdef CONFIG_COMPAT
75struct compat_blkpg_ioctl_arg {
76 compat_int_t op;
77 compat_int_t flags;
78 compat_int_t datalen;
79 compat_caddr_t data;
80};
81
82static int compat_blkpg_ioctl(struct block_device *bdev,
83 struct compat_blkpg_ioctl_arg __user *arg)
84{
85 compat_caddr_t udata;
86 int op;
87
88 if (get_user(op, &arg->op) || get_user(udata, &arg->data))
89 return -EFAULT;
90
91 return blkpg_do_ioctl(bdev, compat_ptr(udata), op);
92}
93#endif
94
05bdb996 95static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
44abff2c 96 unsigned long arg)
d30a2605 97{
30f1e724 98 unsigned int bs_mask = bdev_logical_block_size(bdev) - 1;
7607c44c 99 struct inode *inode = bdev->bd_inode;
0c9f4ac8 100 uint64_t range[2], start, len, end;
719c15a7
CH
101 struct bio *prev = NULL, *bio;
102 sector_t sector, nr_sects;
103 struct blk_plug plug;
384d87ef 104 int err;
d8e4bb81 105
05bdb996 106 if (!(mode & BLK_OPEN_WRITE))
d8e4bb81
CH
107 return -EBADF;
108
70200574 109 if (!bdev_max_discard_sectors(bdev))
351499a1 110 return -EOPNOTSUPP;
30f1e724
CH
111 if (bdev_read_only(bdev))
112 return -EPERM;
351499a1 113
d8e4bb81
CH
114 if (copy_from_user(range, (void __user *)arg, sizeof(range)))
115 return -EFAULT;
116
117 start = range[0];
118 len = range[1];
8d57a98c 119
30f1e724 120 if (!len)
d30a2605 121 return -EINVAL;
30f1e724 122 if ((start | len) & bs_mask)
d30a2605 123 return -EINVAL;
d30a2605 124
22d24a54
LN
125 if (check_add_overflow(start, len, &end) ||
126 end > bdev_nr_bytes(bdev))
d30a2605 127 return -EINVAL;
384d87ef 128
7607c44c 129 filemap_invalidate_lock(inode->i_mapping);
384d87ef
JK
130 err = truncate_bdev_range(bdev, mode, start, start + len - 1);
131 if (err)
7607c44c 132 goto fail;
719c15a7
CH
133
134 sector = start >> SECTOR_SHIFT;
135 nr_sects = len >> SECTOR_SHIFT;
136
137 blk_start_plug(&plug);
138 while (1) {
139 if (fatal_signal_pending(current)) {
140 if (prev)
141 bio_await_chain(prev);
142 err = -EINTR;
143 goto out_unplug;
144 }
145 bio = blk_alloc_discard_bio(bdev, &sector, &nr_sects,
146 GFP_KERNEL);
147 if (!bio)
148 break;
149 prev = bio_chain_and_submit(prev, bio);
150 }
151 if (prev) {
152 err = submit_bio_wait(prev);
153 if (err == -EOPNOTSUPP)
154 err = 0;
155 bio_put(prev);
156 }
157out_unplug:
158 blk_finish_plug(&plug);
7607c44c
SK
159fail:
160 filemap_invalidate_unlock(inode->i_mapping);
161 return err;
d30a2605
DW
162}
163
05bdb996 164static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
44abff2c
CH
165 void __user *argp)
166{
167 uint64_t start, len;
168 uint64_t range[2];
169 int err;
170
05bdb996 171 if (!(mode & BLK_OPEN_WRITE))
44abff2c
CH
172 return -EBADF;
173 if (!bdev_max_secure_erase_sectors(bdev))
174 return -EOPNOTSUPP;
175 if (copy_from_user(range, argp, sizeof(range)))
176 return -EFAULT;
177
178 start = range[0];
179 len = range[1];
180 if ((start & 511) || (len & 511))
181 return -EINVAL;
182 if (start + len > bdev_nr_bytes(bdev))
183 return -EINVAL;
184
185 filemap_invalidate_lock(bdev->bd_inode->i_mapping);
186 err = truncate_bdev_range(bdev, mode, start, start + len - 1);
187 if (!err)
188 err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9,
189 GFP_KERNEL);
190 filemap_invalidate_unlock(bdev->bd_inode->i_mapping);
191 return err;
192}
193
194
05bdb996 195static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode,
d8e4bb81 196 unsigned long arg)
66ba32dc 197{
d8e4bb81 198 uint64_t range[2];
22dd6d35 199 uint64_t start, end, len;
35e4c6c1 200 struct inode *inode = bdev->bd_inode;
384d87ef 201 int err;
d8e4bb81 202
05bdb996 203 if (!(mode & BLK_OPEN_WRITE))
d8e4bb81
CH
204 return -EBADF;
205
206 if (copy_from_user(range, (void __user *)arg, sizeof(range)))
207 return -EFAULT;
208
209 start = range[0];
210 len = range[1];
22dd6d35 211 end = start + len - 1;
d8e4bb81 212
66ba32dc
MP
213 if (start & 511)
214 return -EINVAL;
215 if (len & 511)
216 return -EINVAL;
946e9937 217 if (end >= (uint64_t)bdev_nr_bytes(bdev))
22dd6d35
DW
218 return -EINVAL;
219 if (end < start)
66ba32dc
MP
220 return -EINVAL;
221
22dd6d35 222 /* Invalidate the page cache, including dirty pages */
35e4c6c1 223 filemap_invalidate_lock(inode->i_mapping);
384d87ef
JK
224 err = truncate_bdev_range(bdev, mode, start, end);
225 if (err)
35e4c6c1
SK
226 goto fail;
227
228 err = blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
229 BLKDEV_ZERO_NOUNMAP);
22dd6d35 230
35e4c6c1
SK
231fail:
232 filemap_invalidate_unlock(inode->i_mapping);
233 return err;
66ba32dc
MP
234}
235
9b81648c 236static int put_ushort(unsigned short __user *argp, unsigned short val)
1da177e4 237{
9b81648c 238 return put_user(val, argp);
1da177e4
LT
239}
240
9b81648c 241static int put_int(int __user *argp, int val)
1da177e4 242{
9b81648c 243 return put_user(val, argp);
1da177e4
LT
244}
245
9b81648c 246static int put_uint(unsigned int __user *argp, unsigned int val)
ac481c20 247{
9b81648c 248 return put_user(val, argp);
ac481c20
MP
249}
250
9b81648c 251static int put_long(long __user *argp, long val)
1da177e4 252{
9b81648c 253 return put_user(val, argp);
1da177e4
LT
254}
255
9b81648c 256static int put_ulong(unsigned long __user *argp, unsigned long val)
1da177e4 257{
9b81648c 258 return put_user(val, argp);
1da177e4
LT
259}
260
9b81648c 261static int put_u64(u64 __user *argp, u64 val)
1da177e4 262{
9b81648c 263 return put_user(val, argp);
1da177e4
LT
264}
265
bdc1ddad 266#ifdef CONFIG_COMPAT
c8210a57 267static int compat_put_long(compat_long_t __user *argp, long val)
bdc1ddad 268{
9b81648c 269 return put_user(val, argp);
bdc1ddad
AB
270}
271
c8210a57 272static int compat_put_ulong(compat_ulong_t __user *argp, compat_ulong_t val)
bdc1ddad 273{
9b81648c 274 return put_user(val, argp);
bdc1ddad
AB
275}
276#endif
277
ee6a129d
AB
278#ifdef CONFIG_COMPAT
279/*
280 * This is the equivalent of compat_ptr_ioctl(), to be used by block
281 * drivers that implement only commands that are completely compatible
282 * between 32-bit and 64-bit user space
283 */
05bdb996 284int blkdev_compat_ptr_ioctl(struct block_device *bdev, blk_mode_t mode,
ee6a129d
AB
285 unsigned cmd, unsigned long arg)
286{
287 struct gendisk *disk = bdev->bd_disk;
288
289 if (disk->fops->ioctl)
290 return disk->fops->ioctl(bdev, mode, cmd,
291 (unsigned long)compat_ptr(arg));
292
293 return -ENOIOCTLCMD;
294}
295EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
296#endif
297
9a72a024 298static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode)
12629621
JX
299{
300 /* no sense to make reservations for partitions */
301 if (bdev_is_partition(bdev))
302 return false;
303
304 if (capable(CAP_SYS_ADMIN))
305 return true;
9a72a024
JX
306 /*
307 * Only allow unprivileged reservations if the file descriptor is open
308 * for writing.
309 */
310 return mode & BLK_OPEN_WRITE;
12629621
JX
311}
312
9a72a024 313static int blkdev_pr_register(struct block_device *bdev, blk_mode_t mode,
bbd3e064
CH
314 struct pr_registration __user *arg)
315{
316 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
317 struct pr_registration reg;
318
9a72a024 319 if (!blkdev_pr_allowed(bdev, mode))
bbd3e064
CH
320 return -EPERM;
321 if (!ops || !ops->pr_register)
322 return -EOPNOTSUPP;
323 if (copy_from_user(&reg, arg, sizeof(reg)))
324 return -EFAULT;
325
326 if (reg.flags & ~PR_FL_IGNORE_KEY)
327 return -EOPNOTSUPP;
328 return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags);
329}
330
9a72a024 331static int blkdev_pr_reserve(struct block_device *bdev, blk_mode_t mode,
bbd3e064
CH
332 struct pr_reservation __user *arg)
333{
334 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
335 struct pr_reservation rsv;
336
9a72a024 337 if (!blkdev_pr_allowed(bdev, mode))
bbd3e064
CH
338 return -EPERM;
339 if (!ops || !ops->pr_reserve)
340 return -EOPNOTSUPP;
341 if (copy_from_user(&rsv, arg, sizeof(rsv)))
342 return -EFAULT;
343
344 if (rsv.flags & ~PR_FL_IGNORE_KEY)
345 return -EOPNOTSUPP;
346 return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags);
347}
348
9a72a024 349static int blkdev_pr_release(struct block_device *bdev, blk_mode_t mode,
bbd3e064
CH
350 struct pr_reservation __user *arg)
351{
352 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
353 struct pr_reservation rsv;
354
9a72a024 355 if (!blkdev_pr_allowed(bdev, mode))
bbd3e064
CH
356 return -EPERM;
357 if (!ops || !ops->pr_release)
358 return -EOPNOTSUPP;
359 if (copy_from_user(&rsv, arg, sizeof(rsv)))
360 return -EFAULT;
361
362 if (rsv.flags)
363 return -EOPNOTSUPP;
364 return ops->pr_release(bdev, rsv.key, rsv.type);
365}
366
9a72a024 367static int blkdev_pr_preempt(struct block_device *bdev, blk_mode_t mode,
bbd3e064
CH
368 struct pr_preempt __user *arg, bool abort)
369{
370 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
371 struct pr_preempt p;
372
9a72a024 373 if (!blkdev_pr_allowed(bdev, mode))
bbd3e064
CH
374 return -EPERM;
375 if (!ops || !ops->pr_preempt)
376 return -EOPNOTSUPP;
377 if (copy_from_user(&p, arg, sizeof(p)))
378 return -EFAULT;
379
380 if (p.flags)
381 return -EOPNOTSUPP;
382 return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort);
383}
384
9a72a024 385static int blkdev_pr_clear(struct block_device *bdev, blk_mode_t mode,
bbd3e064
CH
386 struct pr_clear __user *arg)
387{
388 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
389 struct pr_clear c;
390
9a72a024 391 if (!blkdev_pr_allowed(bdev, mode))
bbd3e064
CH
392 return -EPERM;
393 if (!ops || !ops->pr_clear)
394 return -EOPNOTSUPP;
395 if (copy_from_user(&c, arg, sizeof(c)))
396 return -EFAULT;
397
398 if (c.flags)
399 return -EOPNOTSUPP;
400 return ops->pr_clear(bdev, c.key);
401}
402
5e4ea834
CH
403static int blkdev_flushbuf(struct block_device *bdev, unsigned cmd,
404 unsigned long arg)
bb93e3a5 405{
d8e4bb81
CH
406 if (!capable(CAP_SYS_ADMIN))
407 return -EACCES;
2142b88c
CH
408
409 mutex_lock(&bdev->bd_holder_lock);
410 if (bdev->bd_holder_ops && bdev->bd_holder_ops->sync)
411 bdev->bd_holder_ops->sync(bdev);
fd146410
JK
412 else {
413 mutex_unlock(&bdev->bd_holder_lock);
2142b88c 414 sync_blockdev(bdev);
fd146410 415 }
2142b88c 416
d8e4bb81
CH
417 invalidate_bdev(bdev);
418 return 0;
419}
d30a2605 420
5e4ea834
CH
421static int blkdev_roset(struct block_device *bdev, unsigned cmd,
422 unsigned long arg)
d8e4bb81
CH
423{
424 int ret, n;
d30a2605 425
bb749b31
ID
426 if (!capable(CAP_SYS_ADMIN))
427 return -EACCES;
428
d8e4bb81
CH
429 if (get_user(n, (int __user *)arg))
430 return -EFAULT;
e00adcad
CH
431 if (bdev->bd_disk->fops->set_read_only) {
432 ret = bdev->bd_disk->fops->set_read_only(bdev, n);
433 if (ret)
434 return ret;
435 }
83950d35 436 bdev->bd_read_only = n;
d8e4bb81
CH
437 return 0;
438}
d30a2605 439
d8e4bb81
CH
440static int blkdev_getgeo(struct block_device *bdev,
441 struct hd_geometry __user *argp)
442{
443 struct gendisk *disk = bdev->bd_disk;
444 struct hd_geometry geo;
445 int ret;
d30a2605 446
d8e4bb81
CH
447 if (!argp)
448 return -EINVAL;
449 if (!disk->fops->getgeo)
450 return -ENOTTY;
451
452 /*
453 * We need to set the startsect first, the driver may
454 * want to override it.
455 */
456 memset(&geo, 0, sizeof(geo));
457 geo.start = get_start_sect(bdev);
458 ret = disk->fops->getgeo(bdev, &geo);
459 if (ret)
460 return ret;
461 if (copy_to_user(argp, &geo, sizeof(geo)))
462 return -EFAULT;
463 return 0;
464}
66ba32dc 465
bdc1ddad
AB
466#ifdef CONFIG_COMPAT
467struct compat_hd_geometry {
468 unsigned char heads;
469 unsigned char sectors;
470 unsigned short cylinders;
471 u32 start;
472};
473
9b81648c
AB
474static int compat_hdio_getgeo(struct block_device *bdev,
475 struct compat_hd_geometry __user *ugeo)
bdc1ddad 476{
9b81648c 477 struct gendisk *disk = bdev->bd_disk;
bdc1ddad
AB
478 struct hd_geometry geo;
479 int ret;
480
481 if (!ugeo)
482 return -EINVAL;
483 if (!disk->fops->getgeo)
484 return -ENOTTY;
485
486 memset(&geo, 0, sizeof(geo));
487 /*
488 * We need to set the startsect first, the driver may
489 * want to override it.
490 */
491 geo.start = get_start_sect(bdev);
492 ret = disk->fops->getgeo(bdev, &geo);
493 if (ret)
494 return ret;
495
496 ret = copy_to_user(ugeo, &geo, 4);
497 ret |= put_user(geo.start, &ugeo->start);
498 if (ret)
499 ret = -EFAULT;
500
501 return ret;
502}
503#endif
504
d8e4bb81 505/* set the logical block size */
05bdb996 506static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode,
d8e4bb81
CH
507 int __user *argp)
508{
509 int ret, n;
e5ca9d39 510 struct file *file;
66ba32dc 511
d8e4bb81
CH
512 if (!capable(CAP_SYS_ADMIN))
513 return -EACCES;
514 if (!argp)
515 return -EINVAL;
516 if (get_user(n, argp))
517 return -EFAULT;
66ba32dc 518
05bdb996 519 if (mode & BLK_OPEN_EXCL)
47816282 520 return set_blocksize(bdev, n);
d30a2605 521
e5ca9d39
CB
522 file = bdev_file_open_by_dev(bdev->bd_dev, mode, &bdev, NULL);
523 if (IS_ERR(file))
47816282 524 return -EBUSY;
d8e4bb81 525 ret = set_blocksize(bdev, n);
e5ca9d39 526 fput(file);
d8e4bb81
CH
527 return ret;
528}
a885c8c4 529
d8e4bb81 530/*
9b81648c
AB
531 * Common commands that are handled the same way on native and compat
532 * user space. Note the separate arg/argp parameters that are needed
533 * to deal with the compat_ptr() conversion.
d8e4bb81 534 */
05bdb996 535static int blkdev_common_ioctl(struct block_device *bdev, blk_mode_t mode,
0f77b29a
YK
536 unsigned int cmd, unsigned long arg,
537 void __user *argp)
d8e4bb81 538{
d8e4bb81
CH
539 unsigned int max_sectors;
540
541 switch (cmd) {
542 case BLKFLSBUF:
5e4ea834 543 return blkdev_flushbuf(bdev, cmd, arg);
d8e4bb81 544 case BLKROSET:
5e4ea834 545 return blkdev_roset(bdev, cmd, arg);
d8e4bb81 546 case BLKDISCARD:
44abff2c 547 return blk_ioctl_discard(bdev, mode, arg);
d8e4bb81 548 case BLKSECDISCARD:
44abff2c 549 return blk_ioctl_secure_erase(bdev, mode, argp);
d8e4bb81
CH
550 case BLKZEROOUT:
551 return blk_ioctl_zeroout(bdev, mode, arg);
7957d93b
MC
552 case BLKGETDISKSEQ:
553 return put_u64(argp, bdev->bd_disk->diskseq);
3ed05a98 554 case BLKREPORTZONE:
5e4ea834 555 return blkdev_report_zones_ioctl(bdev, cmd, arg);
3ed05a98 556 case BLKRESETZONE:
e876df1f
AJ
557 case BLKOPENZONE:
558 case BLKCLOSEZONE:
559 case BLKFINISHZONE:
560 return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
72cd8757 561 case BLKGETZONESZ:
9b81648c 562 return put_uint(argp, bdev_zone_sectors(bdev));
65e4e3ee 563 case BLKGETNRZONES:
b623e347 564 return put_uint(argp, bdev_nr_zones(bdev));
45048d09 565 case BLKROGET:
9b81648c 566 return put_int(argp, bdev_read_only(bdev) != 0);
ac481c20 567 case BLKSSZGET: /* get block device logical block size */
9b81648c 568 return put_int(argp, bdev_logical_block_size(bdev));
ac481c20 569 case BLKPBSZGET: /* get block device physical block size */
9b81648c 570 return put_uint(argp, bdev_physical_block_size(bdev));
ac481c20 571 case BLKIOMIN:
9b81648c 572 return put_uint(argp, bdev_io_min(bdev));
ac481c20 573 case BLKIOOPT:
9b81648c 574 return put_uint(argp, bdev_io_opt(bdev));
ac481c20 575 case BLKALIGNOFF:
9b81648c 576 return put_int(argp, bdev_alignment_offset(bdev));
98262f27 577 case BLKDISCARDZEROES:
9b81648c 578 return put_uint(argp, 0);
45048d09 579 case BLKSECTGET:
63f26496
AM
580 max_sectors = min_t(unsigned int, USHRT_MAX,
581 queue_max_sectors(bdev_get_queue(bdev)));
9b81648c 582 return put_ushort(argp, max_sectors);
ef00f59c 583 case BLKROTATIONAL:
10f0d2a5 584 return put_ushort(argp, !bdev_nonrot(bdev));
45048d09
AV
585 case BLKRASET:
586 case BLKFRASET:
587 if(!capable(CAP_SYS_ADMIN))
588 return -EACCES;
a11d7fc2 589 bdev->bd_disk->bdi->ra_pages = (arg * 512) / PAGE_SIZE;
45048d09 590 return 0;
45048d09 591 case BLKRRPART:
e16e506c
CH
592 if (!capable(CAP_SYS_ADMIN))
593 return -EACCES;
594 if (bdev_is_partition(bdev))
595 return -EINVAL;
752863bd
CH
596 return disk_scan_partitions(bdev->bd_disk,
597 mode | BLK_OPEN_STRICT_SCAN);
45048d09
AV
598 case BLKTRACESTART:
599 case BLKTRACESTOP:
45048d09 600 case BLKTRACETEARDOWN:
d8e4bb81 601 return blk_trace_ioctl(bdev, cmd, argp);
bbd3e064 602 case IOC_PR_REGISTER:
9a72a024 603 return blkdev_pr_register(bdev, mode, argp);
bbd3e064 604 case IOC_PR_RESERVE:
9a72a024 605 return blkdev_pr_reserve(bdev, mode, argp);
bbd3e064 606 case IOC_PR_RELEASE:
9a72a024 607 return blkdev_pr_release(bdev, mode, argp);
bbd3e064 608 case IOC_PR_PREEMPT:
9a72a024 609 return blkdev_pr_preempt(bdev, mode, argp, false);
bbd3e064 610 case IOC_PR_PREEMPT_ABORT:
9a72a024 611 return blkdev_pr_preempt(bdev, mode, argp, true);
bbd3e064 612 case IOC_PR_CLEAR:
9a72a024 613 return blkdev_pr_clear(bdev, mode, argp);
45048d09 614 default:
9b81648c 615 return -ENOIOCTLCMD;
45048d09 616 }
1da177e4 617}
9b81648c
AB
618
619/*
620 * Always keep this in sync with compat_blkdev_ioctl()
621 * to handle all incompatible commands in both functions.
622 *
623 * New commands must be compatible and go into blkdev_common_ioctl
624 */
8a709512 625long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
9b81648c 626{
8a709512 627 struct block_device *bdev = I_BDEV(file->f_mapping->host);
9b81648c 628 void __user *argp = (void __user *)arg;
05bdb996 629 blk_mode_t mode = file_to_blk_mode(file);
8a709512
CH
630 int ret;
631
9b81648c
AB
632 switch (cmd) {
633 /* These need separate implementations for the data structure */
634 case HDIO_GETGEO:
635 return blkdev_getgeo(bdev, argp);
636 case BLKPG:
637 return blkpg_ioctl(bdev, argp);
638
639 /* Compat mode returns 32-bit data instead of 'long' */
640 case BLKRAGET:
641 case BLKFRAGET:
642 if (!argp)
643 return -EINVAL;
a11d7fc2
CH
644 return put_long(argp,
645 (bdev->bd_disk->bdi->ra_pages * PAGE_SIZE) / 512);
9b81648c 646 case BLKGETSIZE:
946e9937 647 if (bdev_nr_sectors(bdev) > ~0UL)
9b81648c 648 return -EFBIG;
946e9937 649 return put_ulong(argp, bdev_nr_sectors(bdev));
9b81648c
AB
650
651 /* The data is compatible, but the command number is different */
652 case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
653 return put_int(argp, block_size(bdev));
654 case BLKBSZSET:
655 return blkdev_bszset(bdev, mode, argp);
656 case BLKGETSIZE64:
946e9937 657 return put_u64(argp, bdev_nr_bytes(bdev));
9b81648c
AB
658
659 /* Incompatible alignment on i386 */
660 case BLKTRACESETUP:
661 return blk_trace_ioctl(bdev, cmd, argp);
662 default:
663 break;
664 }
665
0f77b29a 666 ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
a7cb3d2f
CH
667 if (ret != -ENOIOCTLCMD)
668 return ret;
9b81648c 669
a7cb3d2f
CH
670 if (!bdev->bd_disk->fops->ioctl)
671 return -ENOTTY;
672 return bdev->bd_disk->fops->ioctl(bdev, mode, cmd, arg);
9b81648c 673}
bdc1ddad
AB
674
675#ifdef CONFIG_COMPAT
9b81648c 676
bdc1ddad
AB
677#define BLKBSZGET_32 _IOR(0x12, 112, int)
678#define BLKBSZSET_32 _IOW(0x12, 113, int)
679#define BLKGETSIZE64_32 _IOR(0x12, 114, int)
680
681/* Most of the generic ioctls are handled in the normal fallback path.
682 This assumes the blkdev's low level compat_ioctl always returns
683 ENOIOCTLCMD for unknown ioctls. */
684long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
685{
9b81648c
AB
686 int ret;
687 void __user *argp = compat_ptr(arg);
4e7b5671 688 struct block_device *bdev = I_BDEV(file->f_mapping->host);
bdc1ddad 689 struct gendisk *disk = bdev->bd_disk;
05bdb996 690 blk_mode_t mode = file_to_blk_mode(file);
bdc1ddad
AB
691
692 switch (cmd) {
9b81648c 693 /* These need separate implementations for the data structure */
bdc1ddad 694 case HDIO_GETGEO:
9b81648c 695 return compat_hdio_getgeo(bdev, argp);
bdc1ddad 696 case BLKPG:
9b81648c
AB
697 return compat_blkpg_ioctl(bdev, argp);
698
699 /* Compat mode returns 32-bit data instead of 'long' */
bdc1ddad
AB
700 case BLKRAGET:
701 case BLKFRAGET:
9b81648c 702 if (!argp)
bdc1ddad 703 return -EINVAL;
9b81648c 704 return compat_put_long(argp,
a11d7fc2 705 (bdev->bd_disk->bdi->ra_pages * PAGE_SIZE) / 512);
bdc1ddad 706 case BLKGETSIZE:
ccf16413 707 if (bdev_nr_sectors(bdev) > ~(compat_ulong_t)0)
bdc1ddad 708 return -EFBIG;
946e9937 709 return compat_put_ulong(argp, bdev_nr_sectors(bdev));
bdc1ddad 710
9b81648c
AB
711 /* The data is compatible, but the command number is different */
712 case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
713 return put_int(argp, bdev_logical_block_size(bdev));
714 case BLKBSZSET_32:
715 return blkdev_bszset(bdev, mode, argp);
bdc1ddad 716 case BLKGETSIZE64_32:
946e9937 717 return put_u64(argp, bdev_nr_bytes(bdev));
bdc1ddad 718
9b81648c 719 /* Incompatible alignment on i386 */
bdc1ddad 720 case BLKTRACESETUP32:
9b81648c 721 return blk_trace_ioctl(bdev, cmd, argp);
bdc1ddad 722 default:
9b81648c 723 break;
bdc1ddad 724 }
9b81648c 725
0f77b29a 726 ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
9b81648c
AB
727 if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
728 ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
729
730 return ret;
bdc1ddad
AB
731}
732#endif