~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/block/ioctl.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php