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