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