cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ioctl.c (16828B)


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