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-04-06 08:38:28 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, fmode_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 & FMODE_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, fmode_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 & FMODE_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, fmode_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 & FMODE_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, fmode_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           0 : static int blkdev_pr_register(struct block_device *bdev,
     258             :                 struct pr_registration __user *arg)
     259             : {
     260           0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     261             :         struct pr_registration reg;
     262             : 
     263           0 :         if (!capable(CAP_SYS_ADMIN))
     264             :                 return -EPERM;
     265           0 :         if (!ops || !ops->pr_register)
     266             :                 return -EOPNOTSUPP;
     267           0 :         if (copy_from_user(&reg, arg, sizeof(reg)))
     268             :                 return -EFAULT;
     269             : 
     270           0 :         if (reg.flags & ~PR_FL_IGNORE_KEY)
     271             :                 return -EOPNOTSUPP;
     272           0 :         return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags);
     273             : }
     274             : 
     275           0 : static int blkdev_pr_reserve(struct block_device *bdev,
     276             :                 struct pr_reservation __user *arg)
     277             : {
     278           0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     279             :         struct pr_reservation rsv;
     280             : 
     281           0 :         if (!capable(CAP_SYS_ADMIN))
     282             :                 return -EPERM;
     283           0 :         if (!ops || !ops->pr_reserve)
     284             :                 return -EOPNOTSUPP;
     285           0 :         if (copy_from_user(&rsv, arg, sizeof(rsv)))
     286             :                 return -EFAULT;
     287             : 
     288           0 :         if (rsv.flags & ~PR_FL_IGNORE_KEY)
     289             :                 return -EOPNOTSUPP;
     290           0 :         return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags);
     291             : }
     292             : 
     293           0 : static int blkdev_pr_release(struct block_device *bdev,
     294             :                 struct pr_reservation __user *arg)
     295             : {
     296           0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     297             :         struct pr_reservation rsv;
     298             : 
     299           0 :         if (!capable(CAP_SYS_ADMIN))
     300             :                 return -EPERM;
     301           0 :         if (!ops || !ops->pr_release)
     302             :                 return -EOPNOTSUPP;
     303           0 :         if (copy_from_user(&rsv, arg, sizeof(rsv)))
     304             :                 return -EFAULT;
     305             : 
     306           0 :         if (rsv.flags)
     307             :                 return -EOPNOTSUPP;
     308           0 :         return ops->pr_release(bdev, rsv.key, rsv.type);
     309             : }
     310             : 
     311           0 : static int blkdev_pr_preempt(struct block_device *bdev,
     312             :                 struct pr_preempt __user *arg, bool abort)
     313             : {
     314           0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     315             :         struct pr_preempt p;
     316             : 
     317           0 :         if (!capable(CAP_SYS_ADMIN))
     318             :                 return -EPERM;
     319           0 :         if (!ops || !ops->pr_preempt)
     320             :                 return -EOPNOTSUPP;
     321           0 :         if (copy_from_user(&p, arg, sizeof(p)))
     322             :                 return -EFAULT;
     323             : 
     324           0 :         if (p.flags)
     325             :                 return -EOPNOTSUPP;
     326           0 :         return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort);
     327             : }
     328             : 
     329           0 : static int blkdev_pr_clear(struct block_device *bdev,
     330             :                 struct pr_clear __user *arg)
     331             : {
     332           0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     333             :         struct pr_clear c;
     334             : 
     335           0 :         if (!capable(CAP_SYS_ADMIN))
     336             :                 return -EPERM;
     337           0 :         if (!ops || !ops->pr_clear)
     338             :                 return -EOPNOTSUPP;
     339           0 :         if (copy_from_user(&c, arg, sizeof(c)))
     340             :                 return -EFAULT;
     341             : 
     342           0 :         if (c.flags)
     343             :                 return -EOPNOTSUPP;
     344           0 :         return ops->pr_clear(bdev, c.key);
     345             : }
     346             : 
     347           0 : static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
     348             :                 unsigned cmd, unsigned long arg)
     349             : {
     350           0 :         if (!capable(CAP_SYS_ADMIN))
     351             :                 return -EACCES;
     352           0 :         fsync_bdev(bdev);
     353           0 :         invalidate_bdev(bdev);
     354             :         return 0;
     355             : }
     356             : 
     357           0 : static int blkdev_roset(struct block_device *bdev, fmode_t mode,
     358             :                 unsigned cmd, unsigned long arg)
     359             : {
     360             :         int ret, n;
     361             : 
     362           0 :         if (!capable(CAP_SYS_ADMIN))
     363             :                 return -EACCES;
     364             : 
     365           0 :         if (get_user(n, (int __user *)arg))
     366             :                 return -EFAULT;
     367           0 :         if (bdev->bd_disk->fops->set_read_only) {
     368           0 :                 ret = bdev->bd_disk->fops->set_read_only(bdev, n);
     369           0 :                 if (ret)
     370             :                         return ret;
     371             :         }
     372           0 :         bdev->bd_read_only = n;
     373             :         return 0;
     374             : }
     375             : 
     376           0 : static int blkdev_getgeo(struct block_device *bdev,
     377             :                 struct hd_geometry __user *argp)
     378             : {
     379           0 :         struct gendisk *disk = bdev->bd_disk;
     380             :         struct hd_geometry geo;
     381             :         int ret;
     382             : 
     383           0 :         if (!argp)
     384             :                 return -EINVAL;
     385           0 :         if (!disk->fops->getgeo)
     386             :                 return -ENOTTY;
     387             : 
     388             :         /*
     389             :          * We need to set the startsect first, the driver may
     390             :          * want to override it.
     391             :          */
     392           0 :         memset(&geo, 0, sizeof(geo));
     393           0 :         geo.start = get_start_sect(bdev);
     394           0 :         ret = disk->fops->getgeo(bdev, &geo);
     395           0 :         if (ret)
     396             :                 return ret;
     397           0 :         if (copy_to_user(argp, &geo, sizeof(geo)))
     398             :                 return -EFAULT;
     399           0 :         return 0;
     400             : }
     401             : 
     402             : #ifdef CONFIG_COMPAT
     403             : struct compat_hd_geometry {
     404             :         unsigned char heads;
     405             :         unsigned char sectors;
     406             :         unsigned short cylinders;
     407             :         u32 start;
     408             : };
     409             : 
     410             : static int compat_hdio_getgeo(struct block_device *bdev,
     411             :                               struct compat_hd_geometry __user *ugeo)
     412             : {
     413             :         struct gendisk *disk = bdev->bd_disk;
     414             :         struct hd_geometry geo;
     415             :         int ret;
     416             : 
     417             :         if (!ugeo)
     418             :                 return -EINVAL;
     419             :         if (!disk->fops->getgeo)
     420             :                 return -ENOTTY;
     421             : 
     422             :         memset(&geo, 0, sizeof(geo));
     423             :         /*
     424             :          * We need to set the startsect first, the driver may
     425             :          * want to override it.
     426             :          */
     427             :         geo.start = get_start_sect(bdev);
     428             :         ret = disk->fops->getgeo(bdev, &geo);
     429             :         if (ret)
     430             :                 return ret;
     431             : 
     432             :         ret = copy_to_user(ugeo, &geo, 4);
     433             :         ret |= put_user(geo.start, &ugeo->start);
     434             :         if (ret)
     435             :                 ret = -EFAULT;
     436             : 
     437             :         return ret;
     438             : }
     439             : #endif
     440             : 
     441             : /* set the logical block size */
     442           0 : static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
     443             :                 int __user *argp)
     444             : {
     445             :         int ret, n;
     446             : 
     447           0 :         if (!capable(CAP_SYS_ADMIN))
     448             :                 return -EACCES;
     449           0 :         if (!argp)
     450             :                 return -EINVAL;
     451           0 :         if (get_user(n, argp))
     452             :                 return -EFAULT;
     453             : 
     454           0 :         if (mode & FMODE_EXCL)
     455           0 :                 return set_blocksize(bdev, n);
     456             : 
     457           0 :         if (IS_ERR(blkdev_get_by_dev(bdev->bd_dev, mode | FMODE_EXCL, &bdev)))
     458             :                 return -EBUSY;
     459           0 :         ret = set_blocksize(bdev, n);
     460           0 :         blkdev_put(bdev, mode | FMODE_EXCL);
     461             : 
     462           0 :         return ret;
     463             : }
     464             : 
     465             : /*
     466             :  * Common commands that are handled the same way on native and compat
     467             :  * user space. Note the separate arg/argp parameters that are needed
     468             :  * to deal with the compat_ptr() conversion.
     469             :  */
     470           0 : static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
     471             :                                unsigned int cmd, unsigned long arg,
     472             :                                void __user *argp)
     473             : {
     474             :         unsigned int max_sectors;
     475             : 
     476           0 :         switch (cmd) {
     477             :         case BLKFLSBUF:
     478           0 :                 return blkdev_flushbuf(bdev, mode, cmd, arg);
     479             :         case BLKROSET:
     480           0 :                 return blkdev_roset(bdev, mode, cmd, arg);
     481             :         case BLKDISCARD:
     482           0 :                 return blk_ioctl_discard(bdev, mode, arg);
     483             :         case BLKSECDISCARD:
     484           0 :                 return blk_ioctl_secure_erase(bdev, mode, argp);
     485             :         case BLKZEROOUT:
     486           0 :                 return blk_ioctl_zeroout(bdev, mode, arg);
     487             :         case BLKGETDISKSEQ:
     488           0 :                 return put_u64(argp, bdev->bd_disk->diskseq);
     489             :         case BLKREPORTZONE:
     490             :                 return blkdev_report_zones_ioctl(bdev, mode, cmd, arg);
     491             :         case BLKRESETZONE:
     492             :         case BLKOPENZONE:
     493             :         case BLKCLOSEZONE:
     494             :         case BLKFINISHZONE:
     495             :                 return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
     496             :         case BLKGETZONESZ:
     497           0 :                 return put_uint(argp, bdev_zone_sectors(bdev));
     498             :         case BLKGETNRZONES:
     499           0 :                 return put_uint(argp, bdev_nr_zones(bdev));
     500             :         case BLKROGET:
     501           0 :                 return put_int(argp, bdev_read_only(bdev) != 0);
     502             :         case BLKSSZGET: /* get block device logical block size */
     503           0 :                 return put_int(argp, bdev_logical_block_size(bdev));
     504             :         case BLKPBSZGET: /* get block device physical block size */
     505           0 :                 return put_uint(argp, bdev_physical_block_size(bdev));
     506             :         case BLKIOMIN:
     507           0 :                 return put_uint(argp, bdev_io_min(bdev));
     508             :         case BLKIOOPT:
     509           0 :                 return put_uint(argp, bdev_io_opt(bdev));
     510             :         case BLKALIGNOFF:
     511           0 :                 return put_int(argp, bdev_alignment_offset(bdev));
     512             :         case BLKDISCARDZEROES:
     513           0 :                 return put_uint(argp, 0);
     514             :         case BLKSECTGET:
     515           0 :                 max_sectors = min_t(unsigned int, USHRT_MAX,
     516             :                                     queue_max_sectors(bdev_get_queue(bdev)));
     517           0 :                 return put_ushort(argp, max_sectors);
     518             :         case BLKROTATIONAL:
     519           0 :                 return put_ushort(argp, !bdev_nonrot(bdev));
     520             :         case BLKRASET:
     521             :         case BLKFRASET:
     522           0 :                 if(!capable(CAP_SYS_ADMIN))
     523             :                         return -EACCES;
     524           0 :                 bdev->bd_disk->bdi->ra_pages = (arg * 512) / PAGE_SIZE;
     525           0 :                 return 0;
     526             :         case BLKRRPART:
     527           0 :                 if (!capable(CAP_SYS_ADMIN))
     528             :                         return -EACCES;
     529           0 :                 if (bdev_is_partition(bdev))
     530             :                         return -EINVAL;
     531           0 :                 return disk_scan_partitions(bdev->bd_disk, mode);
     532             :         case BLKTRACESTART:
     533             :         case BLKTRACESTOP:
     534             :         case BLKTRACETEARDOWN:
     535             :                 return blk_trace_ioctl(bdev, cmd, argp);
     536             :         case IOC_PR_REGISTER:
     537           0 :                 return blkdev_pr_register(bdev, argp);
     538             :         case IOC_PR_RESERVE:
     539           0 :                 return blkdev_pr_reserve(bdev, argp);
     540             :         case IOC_PR_RELEASE:
     541           0 :                 return blkdev_pr_release(bdev, argp);
     542             :         case IOC_PR_PREEMPT:
     543           0 :                 return blkdev_pr_preempt(bdev, argp, false);
     544             :         case IOC_PR_PREEMPT_ABORT:
     545           0 :                 return blkdev_pr_preempt(bdev, argp, true);
     546             :         case IOC_PR_CLEAR:
     547           0 :                 return blkdev_pr_clear(bdev, argp);
     548             :         default:
     549           0 :                 return -ENOIOCTLCMD;
     550             :         }
     551             : }
     552             : 
     553             : /*
     554             :  * Always keep this in sync with compat_blkdev_ioctl()
     555             :  * to handle all incompatible commands in both functions.
     556             :  *
     557             :  * New commands must be compatible and go into blkdev_common_ioctl
     558             :  */
     559           0 : long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
     560             : {
     561           0 :         struct block_device *bdev = I_BDEV(file->f_mapping->host);
     562           0 :         void __user *argp = (void __user *)arg;
     563           0 :         fmode_t mode = file->f_mode;
     564             :         int ret;
     565             : 
     566             :         /*
     567             :          * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
     568             :          * to updated it before every ioctl.
     569             :          */
     570           0 :         if (file->f_flags & O_NDELAY)
     571           0 :                 mode |= FMODE_NDELAY;
     572             :         else
     573           0 :                 mode &= ~FMODE_NDELAY;
     574             : 
     575           0 :         switch (cmd) {
     576             :         /* These need separate implementations for the data structure */
     577             :         case HDIO_GETGEO:
     578           0 :                 return blkdev_getgeo(bdev, argp);
     579             :         case BLKPG:
     580           0 :                 return blkpg_ioctl(bdev, argp);
     581             : 
     582             :         /* Compat mode returns 32-bit data instead of 'long' */
     583             :         case BLKRAGET:
     584             :         case BLKFRAGET:
     585           0 :                 if (!argp)
     586             :                         return -EINVAL;
     587           0 :                 return put_long(argp,
     588           0 :                         (bdev->bd_disk->bdi->ra_pages * PAGE_SIZE) / 512);
     589             :         case BLKGETSIZE:
     590           0 :                 if (bdev_nr_sectors(bdev) > ~0UL)
     591             :                         return -EFBIG;
     592           0 :                 return put_ulong(argp, bdev_nr_sectors(bdev));
     593             : 
     594             :         /* The data is compatible, but the command number is different */
     595             :         case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
     596           0 :                 return put_int(argp, block_size(bdev));
     597             :         case BLKBSZSET:
     598           0 :                 return blkdev_bszset(bdev, mode, argp);
     599             :         case BLKGETSIZE64:
     600           0 :                 return put_u64(argp, bdev_nr_bytes(bdev));
     601             : 
     602             :         /* Incompatible alignment on i386 */
     603             :         case BLKTRACESETUP:
     604             :                 return blk_trace_ioctl(bdev, cmd, argp);
     605             :         default:
     606             :                 break;
     607             :         }
     608             : 
     609           0 :         ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
     610           0 :         if (ret != -ENOIOCTLCMD)
     611           0 :                 return ret;
     612             : 
     613           0 :         if (!bdev->bd_disk->fops->ioctl)
     614             :                 return -ENOTTY;
     615           0 :         return bdev->bd_disk->fops->ioctl(bdev, mode, cmd, arg);
     616             : }
     617             : 
     618             : #ifdef CONFIG_COMPAT
     619             : 
     620             : #define BLKBSZGET_32            _IOR(0x12, 112, int)
     621             : #define BLKBSZSET_32            _IOW(0x12, 113, int)
     622             : #define BLKGETSIZE64_32         _IOR(0x12, 114, int)
     623             : 
     624             : /* Most of the generic ioctls are handled in the normal fallback path.
     625             :    This assumes the blkdev's low level compat_ioctl always returns
     626             :    ENOIOCTLCMD for unknown ioctls. */
     627             : long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
     628             : {
     629             :         int ret;
     630             :         void __user *argp = compat_ptr(arg);
     631             :         struct block_device *bdev = I_BDEV(file->f_mapping->host);
     632             :         struct gendisk *disk = bdev->bd_disk;
     633             :         fmode_t mode = file->f_mode;
     634             : 
     635             :         /*
     636             :          * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
     637             :          * to updated it before every ioctl.
     638             :          */
     639             :         if (file->f_flags & O_NDELAY)
     640             :                 mode |= FMODE_NDELAY;
     641             :         else
     642             :                 mode &= ~FMODE_NDELAY;
     643             : 
     644             :         switch (cmd) {
     645             :         /* These need separate implementations for the data structure */
     646             :         case HDIO_GETGEO:
     647             :                 return compat_hdio_getgeo(bdev, argp);
     648             :         case BLKPG:
     649             :                 return compat_blkpg_ioctl(bdev, argp);
     650             : 
     651             :         /* Compat mode returns 32-bit data instead of 'long' */
     652             :         case BLKRAGET:
     653             :         case BLKFRAGET:
     654             :                 if (!argp)
     655             :                         return -EINVAL;
     656             :                 return compat_put_long(argp,
     657             :                         (bdev->bd_disk->bdi->ra_pages * PAGE_SIZE) / 512);
     658             :         case BLKGETSIZE:
     659             :                 if (bdev_nr_sectors(bdev) > ~(compat_ulong_t)0)
     660             :                         return -EFBIG;
     661             :                 return compat_put_ulong(argp, bdev_nr_sectors(bdev));
     662             : 
     663             :         /* The data is compatible, but the command number is different */
     664             :         case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
     665             :                 return put_int(argp, bdev_logical_block_size(bdev));
     666             :         case BLKBSZSET_32:
     667             :                 return blkdev_bszset(bdev, mode, argp);
     668             :         case BLKGETSIZE64_32:
     669             :                 return put_u64(argp, bdev_nr_bytes(bdev));
     670             : 
     671             :         /* Incompatible alignment on i386 */
     672             :         case BLKTRACESETUP32:
     673             :                 return blk_trace_ioctl(bdev, cmd, argp);
     674             :         default:
     675             :                 break;
     676             :         }
     677             : 
     678             :         ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
     679             :         if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
     680             :                 ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
     681             : 
     682             :         return ret;
     683             : }
     684             : #endif

Generated by: LCOV version 1.14