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

Generated by: LCOV version 1.14