LCOV - code coverage report
Current view: top level - block - ioctl.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 24 374 6.4 %
Date: 2022-03-28 16:04:14 Functions: 2 21 9.5 %
Branches: 8 257 3.1 %

           Branch data     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                 :            : 
      15                 :          0 : static int blkpg_do_ioctl(struct block_device *bdev,
      16                 :            :                           struct blkpg_partition __user *upart, int op)
      17                 :            : {
      18                 :          0 :         struct block_device *bdevp;
      19                 :          0 :         struct gendisk *disk;
      20                 :          0 :         struct hd_struct *part, *lpart;
      21                 :          0 :         struct blkpg_partition p;
      22                 :          0 :         struct disk_part_iter piter;
      23                 :          0 :         long long start, length;
      24                 :          0 :         int partno;
      25                 :            : 
      26         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
      27                 :            :                 return -EACCES;
      28         [ #  # ]:          0 :         if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
      29                 :            :                 return -EFAULT;
      30                 :          0 :         disk = bdev->bd_disk;
      31         [ #  # ]:          0 :         if (bdev != bdev->bd_contains)
      32                 :            :                 return -EINVAL;
      33                 :          0 :         partno = p.pno;
      34         [ #  # ]:          0 :         if (partno <= 0)
      35                 :            :                 return -EINVAL;
      36   [ #  #  #  # ]:          0 :         switch (op) {
      37                 :          0 :                 case BLKPG_ADD_PARTITION:
      38                 :          0 :                         start = p.start >> 9;
      39                 :          0 :                         length = p.length >> 9;
      40                 :            :                         /* check for fit in a hd_struct */
      41                 :          0 :                         if (sizeof(sector_t) == sizeof(long) &&
      42                 :            :                             sizeof(long long) > sizeof(long)) {
      43                 :            :                                 long pstart = start, plength = length;
      44                 :            :                                 if (pstart != start || plength != length
      45                 :            :                                     || pstart < 0 || plength < 0 || partno > 65535)
      46                 :            :                                         return -EINVAL;
      47                 :            :                         }
      48                 :            :                         /* check if partition is aligned to blocksize */
      49   [ #  #  #  # ]:          0 :                         if (p.start & (bdev_logical_block_size(bdev) - 1))
      50                 :            :                                 return -EINVAL;
      51                 :            : 
      52                 :          0 :                         mutex_lock(&bdev->bd_mutex);
      53                 :            : 
      54                 :            :                         /* overlap? */
      55                 :          0 :                         disk_part_iter_init(&piter, disk,
      56                 :            :                                             DISK_PITER_INCL_EMPTY);
      57         [ #  # ]:          0 :                         while ((part = disk_part_iter_next(&piter))) {
      58         [ #  # ]:          0 :                                 if (!(start + length <= part->start_sect ||
      59         [ #  # ]:          0 :                                       start >= part->start_sect + part->nr_sects)) {
      60                 :          0 :                                         disk_part_iter_exit(&piter);
      61                 :          0 :                                         mutex_unlock(&bdev->bd_mutex);
      62                 :          0 :                                         return -EBUSY;
      63                 :            :                                 }
      64                 :            :                         }
      65                 :          0 :                         disk_part_iter_exit(&piter);
      66                 :            : 
      67                 :            :                         /* all seems OK */
      68                 :          0 :                         part = add_partition(disk, partno, start, length,
      69                 :            :                                              ADDPART_FLAG_NONE, NULL);
      70                 :          0 :                         mutex_unlock(&bdev->bd_mutex);
      71         [ #  # ]:          0 :                         return PTR_ERR_OR_ZERO(part);
      72                 :          0 :                 case BLKPG_DEL_PARTITION:
      73                 :          0 :                         part = disk_get_part(disk, partno);
      74         [ #  # ]:          0 :                         if (!part)
      75                 :            :                                 return -ENXIO;
      76                 :            : 
      77                 :          0 :                         bdevp = bdget(part_devt(part));
      78                 :          0 :                         disk_put_part(part);
      79         [ #  # ]:          0 :                         if (!bdevp)
      80                 :            :                                 return -ENOMEM;
      81                 :            : 
      82                 :          0 :                         mutex_lock(&bdevp->bd_mutex);
      83         [ #  # ]:          0 :                         if (bdevp->bd_openers) {
      84                 :          0 :                                 mutex_unlock(&bdevp->bd_mutex);
      85                 :          0 :                                 bdput(bdevp);
      86                 :          0 :                                 return -EBUSY;
      87                 :            :                         }
      88                 :            :                         /* all seems OK */
      89                 :          0 :                         fsync_bdev(bdevp);
      90                 :          0 :                         invalidate_bdev(bdevp);
      91                 :            : 
      92                 :          0 :                         mutex_lock_nested(&bdev->bd_mutex, 1);
      93                 :          0 :                         delete_partition(disk, partno);
      94                 :          0 :                         mutex_unlock(&bdev->bd_mutex);
      95                 :          0 :                         mutex_unlock(&bdevp->bd_mutex);
      96                 :          0 :                         bdput(bdevp);
      97                 :            : 
      98                 :          0 :                         return 0;
      99                 :          0 :                 case BLKPG_RESIZE_PARTITION:
     100                 :          0 :                         start = p.start >> 9;
     101                 :            :                         /* new length of partition in bytes */
     102                 :          0 :                         length = p.length >> 9;
     103                 :            :                         /* check for fit in a hd_struct */
     104                 :          0 :                         if (sizeof(sector_t) == sizeof(long) &&
     105                 :            :                             sizeof(long long) > sizeof(long)) {
     106                 :            :                                 long pstart = start, plength = length;
     107                 :            :                                 if (pstart != start || plength != length
     108                 :            :                                     || pstart < 0 || plength < 0)
     109                 :            :                                         return -EINVAL;
     110                 :            :                         }
     111                 :          0 :                         part = disk_get_part(disk, partno);
     112         [ #  # ]:          0 :                         if (!part)
     113                 :            :                                 return -ENXIO;
     114                 :          0 :                         bdevp = bdget(part_devt(part));
     115         [ #  # ]:          0 :                         if (!bdevp) {
     116                 :          0 :                                 disk_put_part(part);
     117                 :          0 :                                 return -ENOMEM;
     118                 :            :                         }
     119                 :          0 :                         mutex_lock(&bdevp->bd_mutex);
     120                 :          0 :                         mutex_lock_nested(&bdev->bd_mutex, 1);
     121         [ #  # ]:          0 :                         if (start != part->start_sect) {
     122                 :          0 :                                 mutex_unlock(&bdevp->bd_mutex);
     123                 :          0 :                                 mutex_unlock(&bdev->bd_mutex);
     124                 :          0 :                                 bdput(bdevp);
     125                 :          0 :                                 disk_put_part(part);
     126                 :          0 :                                 return -EINVAL;
     127                 :            :                         }
     128                 :            :                         /* overlap? */
     129                 :          0 :                         disk_part_iter_init(&piter, disk,
     130                 :            :                                             DISK_PITER_INCL_EMPTY);
     131         [ #  # ]:          0 :                         while ((lpart = disk_part_iter_next(&piter))) {
     132         [ #  # ]:          0 :                                 if (lpart->partno != partno &&
     133         [ #  # ]:          0 :                                    !(start + length <= lpart->start_sect ||
     134         [ #  # ]:          0 :                                    start >= lpart->start_sect + lpart->nr_sects)
     135                 :            :                                    ) {
     136                 :          0 :                                         disk_part_iter_exit(&piter);
     137                 :          0 :                                         mutex_unlock(&bdevp->bd_mutex);
     138                 :          0 :                                         mutex_unlock(&bdev->bd_mutex);
     139                 :          0 :                                         bdput(bdevp);
     140                 :          0 :                                         disk_put_part(part);
     141                 :          0 :                                         return -EBUSY;
     142                 :            :                                 }
     143                 :            :                         }
     144                 :          0 :                         disk_part_iter_exit(&piter);
     145                 :          0 :                         part_nr_sects_write(part, (sector_t)length);
     146                 :          0 :                         i_size_write(bdevp->bd_inode, p.length);
     147                 :          0 :                         mutex_unlock(&bdevp->bd_mutex);
     148                 :          0 :                         mutex_unlock(&bdev->bd_mutex);
     149                 :          0 :                         bdput(bdevp);
     150                 :          0 :                         disk_put_part(part);
     151                 :          0 :                         return 0;
     152                 :            :                 default:
     153                 :            :                         return -EINVAL;
     154                 :            :         }
     155                 :            : }
     156                 :            : 
     157                 :          0 : static int blkpg_ioctl(struct block_device *bdev,
     158                 :            :                        struct blkpg_ioctl_arg __user *arg)
     159                 :            : {
     160                 :          0 :         struct blkpg_partition __user *udata;
     161                 :          0 :         int op;
     162                 :            : 
     163   [ #  #  #  # ]:          0 :         if (get_user(op, &arg->op) || get_user(udata, &arg->data))
     164                 :          0 :                 return -EFAULT;
     165                 :            : 
     166                 :          0 :         return blkpg_do_ioctl(bdev, udata, op);
     167                 :            : }
     168                 :            : 
     169                 :            : #ifdef CONFIG_COMPAT
     170                 :            : struct compat_blkpg_ioctl_arg {
     171                 :            :         compat_int_t op;
     172                 :            :         compat_int_t flags;
     173                 :            :         compat_int_t datalen;
     174                 :            :         compat_caddr_t data;
     175                 :            : };
     176                 :            : 
     177                 :          0 : static int compat_blkpg_ioctl(struct block_device *bdev,
     178                 :            :                               struct compat_blkpg_ioctl_arg __user *arg)
     179                 :            : {
     180                 :          0 :         compat_caddr_t udata;
     181                 :          0 :         int op;
     182                 :            : 
     183   [ #  #  #  # ]:          0 :         if (get_user(op, &arg->op) || get_user(udata, &arg->data))
     184                 :          0 :                 return -EFAULT;
     185                 :            : 
     186                 :          0 :         return blkpg_do_ioctl(bdev, compat_ptr(udata), op);
     187                 :            : }
     188                 :            : #endif
     189                 :            : 
     190                 :          0 : static int blkdev_reread_part(struct block_device *bdev)
     191                 :            : {
     192                 :          0 :         int ret;
     193                 :            : 
     194   [ #  #  #  #  :          0 :         if (!disk_part_scan_enabled(bdev->bd_disk) || bdev != bdev->bd_contains)
                   #  # ]
     195                 :            :                 return -EINVAL;
     196         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     197                 :            :                 return -EACCES;
     198                 :            : 
     199                 :          0 :         mutex_lock(&bdev->bd_mutex);
     200                 :          0 :         ret = bdev_disk_changed(bdev, false);
     201                 :          0 :         mutex_unlock(&bdev->bd_mutex);
     202                 :            : 
     203                 :          0 :         return ret;
     204                 :            : }
     205                 :            : 
     206                 :          0 : static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
     207                 :            :                 unsigned long arg, unsigned long flags)
     208                 :            : {
     209                 :          0 :         uint64_t range[2];
     210                 :          0 :         uint64_t start, len;
     211         [ #  # ]:          0 :         struct request_queue *q = bdev_get_queue(bdev);
     212                 :          0 :         struct address_space *mapping = bdev->bd_inode->i_mapping;
     213                 :            : 
     214                 :            : 
     215         [ #  # ]:          0 :         if (!(mode & FMODE_WRITE))
     216                 :            :                 return -EBADF;
     217                 :            : 
     218         [ #  # ]:          0 :         if (!blk_queue_discard(q))
     219                 :            :                 return -EOPNOTSUPP;
     220                 :            : 
     221         [ #  # ]:          0 :         if (copy_from_user(range, (void __user *)arg, sizeof(range)))
     222                 :            :                 return -EFAULT;
     223                 :            : 
     224                 :          0 :         start = range[0];
     225                 :          0 :         len = range[1];
     226                 :            : 
     227         [ #  # ]:          0 :         if (start & 511)
     228                 :            :                 return -EINVAL;
     229         [ #  # ]:          0 :         if (len & 511)
     230                 :            :                 return -EINVAL;
     231                 :            : 
     232         [ #  # ]:          0 :         if (start + len > i_size_read(bdev->bd_inode))
     233                 :            :                 return -EINVAL;
     234                 :          0 :         truncate_inode_pages_range(mapping, start, start + len - 1);
     235                 :          0 :         return blkdev_issue_discard(bdev, start >> 9, len >> 9,
     236                 :            :                                     GFP_KERNEL, flags);
     237                 :            : }
     238                 :            : 
     239                 :          0 : static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
     240                 :            :                 unsigned long arg)
     241                 :            : {
     242                 :          0 :         uint64_t range[2];
     243                 :          0 :         struct address_space *mapping;
     244                 :          0 :         uint64_t start, end, len;
     245                 :            : 
     246         [ #  # ]:          0 :         if (!(mode & FMODE_WRITE))
     247                 :            :                 return -EBADF;
     248                 :            : 
     249         [ #  # ]:          0 :         if (copy_from_user(range, (void __user *)arg, sizeof(range)))
     250                 :            :                 return -EFAULT;
     251                 :            : 
     252                 :          0 :         start = range[0];
     253                 :          0 :         len = range[1];
     254                 :          0 :         end = start + len - 1;
     255                 :            : 
     256         [ #  # ]:          0 :         if (start & 511)
     257                 :            :                 return -EINVAL;
     258         [ #  # ]:          0 :         if (len & 511)
     259                 :            :                 return -EINVAL;
     260         [ #  # ]:          0 :         if (end >= (uint64_t)i_size_read(bdev->bd_inode))
     261                 :            :                 return -EINVAL;
     262         [ #  # ]:          0 :         if (end < start)
     263                 :            :                 return -EINVAL;
     264                 :            : 
     265                 :            :         /* Invalidate the page cache, including dirty pages */
     266                 :          0 :         mapping = bdev->bd_inode->i_mapping;
     267                 :          0 :         truncate_inode_pages_range(mapping, start, end);
     268                 :            : 
     269                 :          0 :         return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
     270                 :            :                         BLKDEV_ZERO_NOUNMAP);
     271                 :            : }
     272                 :            : 
     273                 :          0 : static int put_ushort(unsigned short __user *argp, unsigned short val)
     274                 :            : {
     275                 :          0 :         return put_user(val, argp);
     276                 :            : }
     277                 :            : 
     278                 :         39 : static int put_int(int __user *argp, int val)
     279                 :            : {
     280                 :         39 :         return put_user(val, argp);
     281                 :            : }
     282                 :            : 
     283                 :          0 : static int put_uint(unsigned int __user *argp, unsigned int val)
     284                 :            : {
     285                 :          0 :         return put_user(val, argp);
     286                 :            : }
     287                 :            : 
     288                 :          0 : static int put_long(long __user *argp, long val)
     289                 :            : {
     290                 :          0 :         return put_user(val, argp);
     291                 :            : }
     292                 :            : 
     293                 :          0 : static int put_ulong(unsigned long __user *argp, unsigned long val)
     294                 :            : {
     295                 :          0 :         return put_user(val, argp);
     296                 :            : }
     297                 :            : 
     298                 :        143 : static int put_u64(u64 __user *argp, u64 val)
     299                 :            : {
     300                 :        143 :         return put_user(val, argp);
     301                 :            : }
     302                 :            : 
     303                 :            : #ifdef CONFIG_COMPAT
     304                 :          0 : static int compat_put_long(compat_long_t *argp, long val)
     305                 :            : {
     306                 :          0 :         return put_user(val, argp);
     307                 :            : }
     308                 :            : 
     309                 :          0 : static int compat_put_ulong(compat_ulong_t *argp, compat_ulong_t val)
     310                 :            : {
     311                 :          0 :         return put_user(val, argp);
     312                 :            : }
     313                 :            : #endif
     314                 :            : 
     315                 :        273 : int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
     316                 :            :                         unsigned cmd, unsigned long arg)
     317                 :            : {
     318                 :        273 :         struct gendisk *disk = bdev->bd_disk;
     319                 :            : 
     320         [ #  # ]:          0 :         if (disk->fops->ioctl)
     321                 :        273 :                 return disk->fops->ioctl(bdev, mode, cmd, arg);
     322                 :            : 
     323                 :            :         return -ENOTTY;
     324                 :            : }
     325                 :            : /*
     326                 :            :  * For the record: _GPL here is only because somebody decided to slap it
     327                 :            :  * on the previous export.  Sheer idiocy, since it wasn't copyrightable
     328                 :            :  * at all and could be open-coded without any exports by anybody who cares.
     329                 :            :  */
     330                 :            : EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
     331                 :            : 
     332                 :            : #ifdef CONFIG_COMPAT
     333                 :            : /*
     334                 :            :  * This is the equivalent of compat_ptr_ioctl(), to be used by block
     335                 :            :  * drivers that implement only commands that are completely compatible
     336                 :            :  * between 32-bit and 64-bit user space
     337                 :            :  */
     338                 :          0 : int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
     339                 :            :                         unsigned cmd, unsigned long arg)
     340                 :            : {
     341                 :          0 :         struct gendisk *disk = bdev->bd_disk;
     342                 :            : 
     343         [ #  # ]:          0 :         if (disk->fops->ioctl)
     344                 :          0 :                 return disk->fops->ioctl(bdev, mode, cmd,
     345                 :            :                                          (unsigned long)compat_ptr(arg));
     346                 :            : 
     347                 :            :         return -ENOIOCTLCMD;
     348                 :            : }
     349                 :            : EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
     350                 :            : #endif
     351                 :            : 
     352                 :          0 : static int blkdev_pr_register(struct block_device *bdev,
     353                 :            :                 struct pr_registration __user *arg)
     354                 :            : {
     355                 :          0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     356                 :          0 :         struct pr_registration reg;
     357                 :            : 
     358         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     359                 :            :                 return -EPERM;
     360   [ #  #  #  # ]:          0 :         if (!ops || !ops->pr_register)
     361                 :            :                 return -EOPNOTSUPP;
     362         [ #  # ]:          0 :         if (copy_from_user(&reg, arg, sizeof(reg)))
     363                 :            :                 return -EFAULT;
     364                 :            : 
     365         [ #  # ]:          0 :         if (reg.flags & ~PR_FL_IGNORE_KEY)
     366                 :            :                 return -EOPNOTSUPP;
     367                 :          0 :         return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags);
     368                 :            : }
     369                 :            : 
     370                 :          0 : static int blkdev_pr_reserve(struct block_device *bdev,
     371                 :            :                 struct pr_reservation __user *arg)
     372                 :            : {
     373                 :          0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     374                 :          0 :         struct pr_reservation rsv;
     375                 :            : 
     376         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     377                 :            :                 return -EPERM;
     378   [ #  #  #  # ]:          0 :         if (!ops || !ops->pr_reserve)
     379                 :            :                 return -EOPNOTSUPP;
     380         [ #  # ]:          0 :         if (copy_from_user(&rsv, arg, sizeof(rsv)))
     381                 :            :                 return -EFAULT;
     382                 :            : 
     383         [ #  # ]:          0 :         if (rsv.flags & ~PR_FL_IGNORE_KEY)
     384                 :            :                 return -EOPNOTSUPP;
     385                 :          0 :         return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags);
     386                 :            : }
     387                 :            : 
     388                 :          0 : static int blkdev_pr_release(struct block_device *bdev,
     389                 :            :                 struct pr_reservation __user *arg)
     390                 :            : {
     391                 :          0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     392                 :          0 :         struct pr_reservation rsv;
     393                 :            : 
     394         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     395                 :            :                 return -EPERM;
     396   [ #  #  #  # ]:          0 :         if (!ops || !ops->pr_release)
     397                 :            :                 return -EOPNOTSUPP;
     398         [ #  # ]:          0 :         if (copy_from_user(&rsv, arg, sizeof(rsv)))
     399                 :            :                 return -EFAULT;
     400                 :            : 
     401         [ #  # ]:          0 :         if (rsv.flags)
     402                 :            :                 return -EOPNOTSUPP;
     403                 :          0 :         return ops->pr_release(bdev, rsv.key, rsv.type);
     404                 :            : }
     405                 :            : 
     406                 :          0 : static int blkdev_pr_preempt(struct block_device *bdev,
     407                 :            :                 struct pr_preempt __user *arg, bool abort)
     408                 :            : {
     409                 :          0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     410                 :          0 :         struct pr_preempt p;
     411                 :            : 
     412         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     413                 :            :                 return -EPERM;
     414   [ #  #  #  # ]:          0 :         if (!ops || !ops->pr_preempt)
     415                 :            :                 return -EOPNOTSUPP;
     416         [ #  # ]:          0 :         if (copy_from_user(&p, arg, sizeof(p)))
     417                 :            :                 return -EFAULT;
     418                 :            : 
     419         [ #  # ]:          0 :         if (p.flags)
     420                 :            :                 return -EOPNOTSUPP;
     421                 :          0 :         return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort);
     422                 :            : }
     423                 :            : 
     424                 :          0 : static int blkdev_pr_clear(struct block_device *bdev,
     425                 :            :                 struct pr_clear __user *arg)
     426                 :            : {
     427                 :          0 :         const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
     428                 :          0 :         struct pr_clear c;
     429                 :            : 
     430         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     431                 :            :                 return -EPERM;
     432   [ #  #  #  # ]:          0 :         if (!ops || !ops->pr_clear)
     433                 :            :                 return -EOPNOTSUPP;
     434         [ #  # ]:          0 :         if (copy_from_user(&c, arg, sizeof(c)))
     435                 :            :                 return -EFAULT;
     436                 :            : 
     437         [ #  # ]:          0 :         if (c.flags)
     438                 :            :                 return -EOPNOTSUPP;
     439                 :          0 :         return ops->pr_clear(bdev, c.key);
     440                 :            : }
     441                 :            : 
     442                 :            : /*
     443                 :            :  * Is it an unrecognized ioctl? The correct returns are either
     444                 :            :  * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a
     445                 :            :  * fallback"). ENOIOCTLCMD gets turned into ENOTTY by the ioctl
     446                 :            :  * code before returning.
     447                 :            :  *
     448                 :            :  * Confused drivers sometimes return EINVAL, which is wrong. It
     449                 :            :  * means "I understood the ioctl command, but the parameters to
     450                 :            :  * it were wrong".
     451                 :            :  *
     452                 :            :  * We should aim to just fix the broken drivers, the EINVAL case
     453                 :            :  * should go away.
     454                 :            :  */
     455                 :          0 : static inline int is_unrecognized_ioctl(int ret)
     456                 :            : {
     457                 :          0 :         return  ret == -EINVAL ||
     458   [ #  #  #  # ]:          0 :                 ret == -ENOTTY ||
     459                 :            :                 ret == -ENOIOCTLCMD;
     460                 :            : }
     461                 :            : 
     462                 :          0 : static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
     463                 :            :                 unsigned cmd, unsigned long arg)
     464                 :            : {
     465                 :          0 :         int ret;
     466                 :            : 
     467         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     468                 :            :                 return -EACCES;
     469                 :            : 
     470         [ #  # ]:          0 :         ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
     471         [ #  # ]:          0 :         if (!is_unrecognized_ioctl(ret))
     472                 :            :                 return ret;
     473                 :            : 
     474                 :          0 :         fsync_bdev(bdev);
     475                 :          0 :         invalidate_bdev(bdev);
     476                 :          0 :         return 0;
     477                 :            : }
     478                 :            : 
     479                 :          0 : static int blkdev_roset(struct block_device *bdev, fmode_t mode,
     480                 :            :                 unsigned cmd, unsigned long arg)
     481                 :            : {
     482                 :          0 :         int ret, n;
     483                 :            : 
     484         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     485                 :            :                 return -EACCES;
     486                 :            : 
     487         [ #  # ]:          0 :         ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
     488         [ #  # ]:          0 :         if (!is_unrecognized_ioctl(ret))
     489                 :            :                 return ret;
     490         [ #  # ]:          0 :         if (get_user(n, (int __user *)arg))
     491                 :            :                 return -EFAULT;
     492                 :          0 :         set_device_ro(bdev, n);
     493                 :          0 :         return 0;
     494                 :            : }
     495                 :            : 
     496                 :          0 : static int blkdev_getgeo(struct block_device *bdev,
     497                 :            :                 struct hd_geometry __user *argp)
     498                 :            : {
     499                 :          0 :         struct gendisk *disk = bdev->bd_disk;
     500                 :          0 :         struct hd_geometry geo;
     501                 :          0 :         int ret;
     502                 :            : 
     503         [ #  # ]:          0 :         if (!argp)
     504                 :            :                 return -EINVAL;
     505         [ #  # ]:          0 :         if (!disk->fops->getgeo)
     506                 :            :                 return -ENOTTY;
     507                 :            : 
     508                 :            :         /*
     509                 :            :          * We need to set the startsect first, the driver may
     510                 :            :          * want to override it.
     511                 :            :          */
     512                 :          0 :         memset(&geo, 0, sizeof(geo));
     513                 :          0 :         geo.start = get_start_sect(bdev);
     514                 :          0 :         ret = disk->fops->getgeo(bdev, &geo);
     515         [ #  # ]:          0 :         if (ret)
     516                 :            :                 return ret;
     517         [ #  # ]:          0 :         if (copy_to_user(argp, &geo, sizeof(geo)))
     518                 :          0 :                 return -EFAULT;
     519                 :            :         return 0;
     520                 :            : }
     521                 :            : 
     522                 :            : #ifdef CONFIG_COMPAT
     523                 :            : struct compat_hd_geometry {
     524                 :            :         unsigned char heads;
     525                 :            :         unsigned char sectors;
     526                 :            :         unsigned short cylinders;
     527                 :            :         u32 start;
     528                 :            : };
     529                 :            : 
     530                 :          0 : static int compat_hdio_getgeo(struct block_device *bdev,
     531                 :            :                               struct compat_hd_geometry __user *ugeo)
     532                 :            : {
     533                 :          0 :         struct gendisk *disk = bdev->bd_disk;
     534                 :          0 :         struct hd_geometry geo;
     535                 :          0 :         int ret;
     536                 :            : 
     537         [ #  # ]:          0 :         if (!ugeo)
     538                 :            :                 return -EINVAL;
     539         [ #  # ]:          0 :         if (!disk->fops->getgeo)
     540                 :            :                 return -ENOTTY;
     541                 :            : 
     542                 :          0 :         memset(&geo, 0, sizeof(geo));
     543                 :            :         /*
     544                 :            :          * We need to set the startsect first, the driver may
     545                 :            :          * want to override it.
     546                 :            :          */
     547                 :          0 :         geo.start = get_start_sect(bdev);
     548                 :          0 :         ret = disk->fops->getgeo(bdev, &geo);
     549         [ #  # ]:          0 :         if (ret)
     550                 :            :                 return ret;
     551                 :            : 
     552                 :          0 :         ret = copy_to_user(ugeo, &geo, 4);
     553                 :          0 :         ret |= put_user(geo.start, &ugeo->start);
     554         [ #  # ]:          0 :         if (ret)
     555                 :          0 :                 ret = -EFAULT;
     556                 :            : 
     557                 :            :         return ret;
     558                 :            : }
     559                 :            : #endif
     560                 :            : 
     561                 :            : /* set the logical block size */
     562                 :          0 : static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
     563                 :            :                 int __user *argp)
     564                 :            : {
     565                 :          0 :         int ret, n;
     566                 :            : 
     567         [ #  # ]:          0 :         if (!capable(CAP_SYS_ADMIN))
     568                 :            :                 return -EACCES;
     569         [ #  # ]:          0 :         if (!argp)
     570                 :            :                 return -EINVAL;
     571         [ #  # ]:          0 :         if (get_user(n, argp))
     572                 :            :                 return -EFAULT;
     573                 :            : 
     574         [ #  # ]:          0 :         if (!(mode & FMODE_EXCL)) {
     575                 :          0 :                 bdgrab(bdev);
     576         [ #  # ]:          0 :                 if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
     577                 :            :                         return -EBUSY;
     578                 :            :         }
     579                 :            : 
     580                 :          0 :         ret = set_blocksize(bdev, n);
     581         [ #  # ]:          0 :         if (!(mode & FMODE_EXCL))
     582                 :          0 :                 blkdev_put(bdev, mode | FMODE_EXCL);
     583                 :            :         return ret;
     584                 :            : }
     585                 :            : 
     586                 :            : /*
     587                 :            :  * Common commands that are handled the same way on native and compat
     588                 :            :  * user space. Note the separate arg/argp parameters that are needed
     589                 :            :  * to deal with the compat_ptr() conversion.
     590                 :            :  */
     591                 :        312 : static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
     592                 :            :                                 unsigned cmd, unsigned long arg, void __user *argp)
     593                 :            : {
     594                 :        312 :         unsigned int max_sectors;
     595                 :            : 
     596   [ -  -  -  -  :        312 :         switch (cmd) {
          -  -  -  -  +  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
                -  +  - ]
     597                 :          0 :         case BLKFLSBUF:
     598                 :          0 :                 return blkdev_flushbuf(bdev, mode, cmd, arg);
     599                 :          0 :         case BLKROSET:
     600                 :          0 :                 return blkdev_roset(bdev, mode, cmd, arg);
     601                 :          0 :         case BLKDISCARD:
     602                 :          0 :                 return blk_ioctl_discard(bdev, mode, arg, 0);
     603                 :          0 :         case BLKSECDISCARD:
     604                 :          0 :                 return blk_ioctl_discard(bdev, mode, arg,
     605                 :            :                                 BLKDEV_DISCARD_SECURE);
     606                 :          0 :         case BLKZEROOUT:
     607                 :          0 :                 return blk_ioctl_zeroout(bdev, mode, arg);
     608                 :            :         case BLKREPORTZONE:
     609                 :            :                 return blkdev_report_zones_ioctl(bdev, mode, cmd, arg);
     610                 :            :         case BLKRESETZONE:
     611                 :            :         case BLKOPENZONE:
     612                 :            :         case BLKCLOSEZONE:
     613                 :            :         case BLKFINISHZONE:
     614                 :            :                 return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
     615                 :            :         case BLKGETZONESZ:
     616         [ #  # ]:          0 :                 return put_uint(argp, bdev_zone_sectors(bdev));
     617                 :          0 :         case BLKGETNRZONES:
     618                 :          0 :                 return put_uint(argp, blkdev_nr_zones(bdev->bd_disk));
     619                 :          0 :         case BLKROGET:
     620                 :          0 :                 return put_int(argp, bdev_read_only(bdev) != 0);
     621                 :            :         case BLKSSZGET: /* get block device logical block size */
     622         [ +  - ]:         78 :                 return put_int(argp, bdev_logical_block_size(bdev));
     623                 :            :         case BLKPBSZGET: /* get block device physical block size */
     624                 :          0 :                 return put_uint(argp, bdev_physical_block_size(bdev));
     625                 :            :         case BLKIOMIN:
     626                 :          0 :                 return put_uint(argp, bdev_io_min(bdev));
     627                 :            :         case BLKIOOPT:
     628                 :          0 :                 return put_uint(argp, bdev_io_opt(bdev));
     629                 :            :         case BLKALIGNOFF:
     630         [ #  # ]:          0 :                 return put_int(argp, bdev_alignment_offset(bdev));
     631                 :            :         case BLKDISCARDZEROES:
     632                 :          0 :                 return put_uint(argp, 0);
     633                 :          0 :         case BLKSECTGET:
     634                 :          0 :                 max_sectors = min_t(unsigned int, USHRT_MAX,
     635                 :            :                                     queue_max_sectors(bdev_get_queue(bdev)));
     636                 :          0 :                 return put_ushort(argp, max_sectors);
     637                 :          0 :         case BLKROTATIONAL:
     638                 :          0 :                 return put_ushort(argp, !blk_queue_nonrot(bdev_get_queue(bdev)));
     639                 :          0 :         case BLKRASET:
     640                 :            :         case BLKFRASET:
     641         [ #  # ]:          0 :                 if(!capable(CAP_SYS_ADMIN))
     642                 :            :                         return -EACCES;
     643                 :          0 :                 bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
     644                 :          0 :                 return 0;
     645                 :          0 :         case BLKRRPART:
     646                 :          0 :                 return blkdev_reread_part(bdev);
     647                 :          0 :         case BLKTRACESTART:
     648                 :            :         case BLKTRACESTOP:
     649                 :            :         case BLKTRACETEARDOWN:
     650                 :          0 :                 return blk_trace_ioctl(bdev, cmd, argp);
     651                 :          0 :         case IOC_PR_REGISTER:
     652                 :          0 :                 return blkdev_pr_register(bdev, argp);
     653                 :          0 :         case IOC_PR_RESERVE:
     654                 :          0 :                 return blkdev_pr_reserve(bdev, argp);
     655                 :          0 :         case IOC_PR_RELEASE:
     656                 :          0 :                 return blkdev_pr_release(bdev, argp);
     657                 :          0 :         case IOC_PR_PREEMPT:
     658                 :          0 :                 return blkdev_pr_preempt(bdev, argp, false);
     659                 :          0 :         case IOC_PR_PREEMPT_ABORT:
     660                 :          0 :                 return blkdev_pr_preempt(bdev, argp, true);
     661                 :          0 :         case IOC_PR_CLEAR:
     662                 :          0 :                 return blkdev_pr_clear(bdev, argp);
     663                 :        273 :         default:
     664                 :        273 :                 return -ENOIOCTLCMD;
     665                 :            :         }
     666                 :            : }
     667                 :            : 
     668                 :            : /*
     669                 :            :  * Always keep this in sync with compat_blkdev_ioctl()
     670                 :            :  * to handle all incompatible commands in both functions.
     671                 :            :  *
     672                 :            :  * New commands must be compatible and go into blkdev_common_ioctl
     673                 :            :  */
     674                 :        455 : int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
     675                 :            :                         unsigned long arg)
     676                 :            : {
     677                 :        455 :         int ret;
     678                 :        455 :         loff_t size;
     679                 :        455 :         void __user *argp = (void __user *)arg;
     680                 :            : 
     681   [ -  -  -  -  :        455 :         switch (cmd) {
             -  -  +  -  
                      + ]
     682                 :            :         /* These need separate implementations for the data structure */
     683                 :          0 :         case HDIO_GETGEO:
     684                 :          0 :                 return blkdev_getgeo(bdev, argp);
     685                 :          0 :         case BLKPG:
     686                 :          0 :                 return blkpg_ioctl(bdev, argp);
     687                 :            : 
     688                 :            :         /* Compat mode returns 32-bit data instead of 'long' */
     689                 :          0 :         case BLKRAGET:
     690                 :            :         case BLKFRAGET:
     691         [ #  # ]:          0 :                 if (!argp)
     692                 :            :                         return -EINVAL;
     693                 :          0 :                 return put_long(argp, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
     694                 :          0 :         case BLKGETSIZE:
     695                 :          0 :                 size = i_size_read(bdev->bd_inode);
     696                 :          0 :                 if ((size >> 9) > ~0UL)
     697                 :            :                         return -EFBIG;
     698                 :          0 :                 return put_ulong(argp, size >> 9);
     699                 :            : 
     700                 :            :         /* The data is compatible, but the command number is different */
     701                 :          0 :         case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
     702                 :          0 :                 return put_int(argp, block_size(bdev));
     703                 :          0 :         case BLKBSZSET:
     704                 :          0 :                 return blkdev_bszset(bdev, mode, argp);
     705                 :        143 :         case BLKGETSIZE64:
     706                 :        143 :                 return put_u64(argp, i_size_read(bdev->bd_inode));
     707                 :            : 
     708                 :            :         /* Incompatible alignment on i386 */
     709                 :          0 :         case BLKTRACESETUP:
     710                 :          0 :                 return blk_trace_ioctl(bdev, cmd, argp);
     711                 :            :         default:
     712                 :        312 :                 break;
     713                 :            :         }
     714                 :            : 
     715                 :        312 :         ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
     716         [ +  + ]:        312 :         if (ret == -ENOIOCTLCMD)
     717         [ +  - ]:        546 :                 return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
     718                 :            : 
     719                 :            :         return ret;
     720                 :            : }
     721                 :            : EXPORT_SYMBOL_GPL(blkdev_ioctl); /* for /dev/raw */
     722                 :            : 
     723                 :            : #ifdef CONFIG_COMPAT
     724                 :            : 
     725                 :            : #define BLKBSZGET_32            _IOR(0x12, 112, int)
     726                 :            : #define BLKBSZSET_32            _IOW(0x12, 113, int)
     727                 :            : #define BLKGETSIZE64_32         _IOR(0x12, 114, int)
     728                 :            : 
     729                 :            : /* Most of the generic ioctls are handled in the normal fallback path.
     730                 :            :    This assumes the blkdev's low level compat_ioctl always returns
     731                 :            :    ENOIOCTLCMD for unknown ioctls. */
     732                 :          0 : long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
     733                 :            : {
     734                 :          0 :         int ret;
     735         [ #  # ]:          0 :         void __user *argp = compat_ptr(arg);
     736                 :          0 :         struct inode *inode = file->f_mapping->host;
     737                 :          0 :         struct block_device *bdev = inode->i_bdev;
     738                 :          0 :         struct gendisk *disk = bdev->bd_disk;
     739                 :          0 :         fmode_t mode = file->f_mode;
     740                 :          0 :         loff_t size;
     741                 :            : 
     742                 :            :         /*
     743                 :            :          * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
     744                 :            :          * to updated it before every ioctl.
     745                 :            :          */
     746         [ #  # ]:          0 :         if (file->f_flags & O_NDELAY)
     747                 :          0 :                 mode |= FMODE_NDELAY;
     748                 :            :         else
     749                 :          0 :                 mode &= ~FMODE_NDELAY;
     750                 :            : 
     751   [ #  #  #  #  :          0 :         switch (cmd) {
             #  #  #  #  
                      # ]
     752                 :            :         /* These need separate implementations for the data structure */
     753                 :          0 :         case HDIO_GETGEO:
     754                 :          0 :                 return compat_hdio_getgeo(bdev, argp);
     755                 :          0 :         case BLKPG:
     756                 :          0 :                 return compat_blkpg_ioctl(bdev, argp);
     757                 :            : 
     758                 :            :         /* Compat mode returns 32-bit data instead of 'long' */
     759                 :          0 :         case BLKRAGET:
     760                 :            :         case BLKFRAGET:
     761         [ #  # ]:          0 :                 if (!argp)
     762                 :            :                         return -EINVAL;
     763                 :          0 :                 return compat_put_long(argp,
     764                 :          0 :                                (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
     765                 :          0 :         case BLKGETSIZE:
     766                 :          0 :                 size = i_size_read(bdev->bd_inode);
     767                 :          0 :                 if ((size >> 9) > ~0UL)
     768                 :            :                         return -EFBIG;
     769                 :          0 :                 return compat_put_ulong(argp, size >> 9);
     770                 :            : 
     771                 :            :         /* The data is compatible, but the command number is different */
     772                 :            :         case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
     773         [ #  # ]:          0 :                 return put_int(argp, bdev_logical_block_size(bdev));
     774                 :          0 :         case BLKBSZSET_32:
     775                 :          0 :                 return blkdev_bszset(bdev, mode, argp);
     776                 :          0 :         case BLKGETSIZE64_32:
     777                 :          0 :                 return put_u64(argp, i_size_read(bdev->bd_inode));
     778                 :            : 
     779                 :            :         /* Incompatible alignment on i386 */
     780                 :          0 :         case BLKTRACESETUP32:
     781                 :          0 :                 return blk_trace_ioctl(bdev, cmd, argp);
     782                 :            :         default:
     783                 :          0 :                 break;
     784                 :            :         }
     785                 :            : 
     786                 :          0 :         ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
     787   [ #  #  #  # ]:          0 :         if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
     788                 :          0 :                 ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
     789                 :            : 
     790                 :          0 :         return ret;
     791                 :            : }
     792                 :            : #endif

Generated by: LCOV version 1.14