LCOV - code coverage report
Current view: top level - block - ioctl.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 28 294 9.5 %
Date: 2021-04-22 12:43:58 Functions: 2 20 10.0 %

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

Generated by: LCOV version 1.14