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