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

Generated by: LCOV version 1.14