xref: /openbmc/linux/block/ioctl.c (revision d30a2605be9d5132d95944916e8f578fcfe4f976)
1c59ede7bSRandy.Dunlap #include <linux/capability.h>
23a65dfe8SJens Axboe #include <linux/blkdev.h>
33a65dfe8SJens Axboe #include <linux/blkpg.h>
4a885c8c4SChristoph Hellwig #include <linux/hdreg.h>
53a65dfe8SJens Axboe #include <linux/backing-dev.h>
63a65dfe8SJens Axboe #include <linux/buffer_head.h>
73a65dfe8SJens Axboe #include <linux/smp_lock.h>
82056a782SJens Axboe #include <linux/blktrace_api.h>
93a65dfe8SJens Axboe #include <asm/uaccess.h>
103a65dfe8SJens Axboe 
113a65dfe8SJens Axboe static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
123a65dfe8SJens Axboe {
133a65dfe8SJens Axboe 	struct block_device *bdevp;
143a65dfe8SJens Axboe 	struct gendisk *disk;
153a65dfe8SJens Axboe 	struct blkpg_ioctl_arg a;
163a65dfe8SJens Axboe 	struct blkpg_partition p;
173a65dfe8SJens Axboe 	long long start, length;
183a65dfe8SJens Axboe 	int part;
193a65dfe8SJens Axboe 	int i;
2004ebd4aeSAbdel Benamrouche 	int err;
213a65dfe8SJens Axboe 
223a65dfe8SJens Axboe 	if (!capable(CAP_SYS_ADMIN))
233a65dfe8SJens Axboe 		return -EACCES;
243a65dfe8SJens Axboe 	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
253a65dfe8SJens Axboe 		return -EFAULT;
263a65dfe8SJens Axboe 	if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
273a65dfe8SJens Axboe 		return -EFAULT;
283a65dfe8SJens Axboe 	disk = bdev->bd_disk;
293a65dfe8SJens Axboe 	if (bdev != bdev->bd_contains)
303a65dfe8SJens Axboe 		return -EINVAL;
313a65dfe8SJens Axboe 	part = p.pno;
323a65dfe8SJens Axboe 	if (part <= 0 || part >= disk->minors)
333a65dfe8SJens Axboe 		return -EINVAL;
343a65dfe8SJens Axboe 	switch (a.op) {
353a65dfe8SJens Axboe 		case BLKPG_ADD_PARTITION:
363a65dfe8SJens Axboe 			start = p.start >> 9;
373a65dfe8SJens Axboe 			length = p.length >> 9;
383a65dfe8SJens Axboe 			/* check for fit in a hd_struct */
393a65dfe8SJens Axboe 			if (sizeof(sector_t) == sizeof(long) &&
403a65dfe8SJens Axboe 			    sizeof(long long) > sizeof(long)) {
413a65dfe8SJens Axboe 				long pstart = start, plength = length;
423a65dfe8SJens Axboe 				if (pstart != start || plength != length
433a65dfe8SJens Axboe 				    || pstart < 0 || plength < 0)
443a65dfe8SJens Axboe 					return -EINVAL;
453a65dfe8SJens Axboe 			}
463a65dfe8SJens Axboe 			/* partition number in use? */
47c039e313SArjan van de Ven 			mutex_lock(&bdev->bd_mutex);
483a65dfe8SJens Axboe 			if (disk->part[part - 1]) {
49c039e313SArjan van de Ven 				mutex_unlock(&bdev->bd_mutex);
503a65dfe8SJens Axboe 				return -EBUSY;
513a65dfe8SJens Axboe 			}
523a65dfe8SJens Axboe 			/* overlap? */
533a65dfe8SJens Axboe 			for (i = 0; i < disk->minors - 1; i++) {
543a65dfe8SJens Axboe 				struct hd_struct *s = disk->part[i];
553a65dfe8SJens Axboe 
563a65dfe8SJens Axboe 				if (!s)
573a65dfe8SJens Axboe 					continue;
583a65dfe8SJens Axboe 				if (!(start+length <= s->start_sect ||
593a65dfe8SJens Axboe 				      start >= s->start_sect + s->nr_sects)) {
60c039e313SArjan van de Ven 					mutex_unlock(&bdev->bd_mutex);
613a65dfe8SJens Axboe 					return -EBUSY;
623a65dfe8SJens Axboe 				}
633a65dfe8SJens Axboe 			}
643a65dfe8SJens Axboe 			/* all seems OK */
6504ebd4aeSAbdel Benamrouche 			err = add_partition(disk, part, start, length, ADDPART_FLAG_NONE);
66c039e313SArjan van de Ven 			mutex_unlock(&bdev->bd_mutex);
6704ebd4aeSAbdel Benamrouche 			return err;
683a65dfe8SJens Axboe 		case BLKPG_DEL_PARTITION:
693a65dfe8SJens Axboe 			if (!disk->part[part-1])
703a65dfe8SJens Axboe 				return -ENXIO;
713a65dfe8SJens Axboe 			if (disk->part[part - 1]->nr_sects == 0)
723a65dfe8SJens Axboe 				return -ENXIO;
733a65dfe8SJens Axboe 			bdevp = bdget_disk(disk, part);
743a65dfe8SJens Axboe 			if (!bdevp)
753a65dfe8SJens Axboe 				return -ENOMEM;
762e7b651dSPeter Zijlstra 			mutex_lock(&bdevp->bd_mutex);
773a65dfe8SJens Axboe 			if (bdevp->bd_openers) {
78c039e313SArjan van de Ven 				mutex_unlock(&bdevp->bd_mutex);
793a65dfe8SJens Axboe 				bdput(bdevp);
803a65dfe8SJens Axboe 				return -EBUSY;
813a65dfe8SJens Axboe 			}
823a65dfe8SJens Axboe 			/* all seems OK */
833a65dfe8SJens Axboe 			fsync_bdev(bdevp);
84f98393a6SPeter Zijlstra 			invalidate_bdev(bdevp);
853a65dfe8SJens Axboe 
866d740cd5SPeter Zijlstra 			mutex_lock_nested(&bdev->bd_mutex, 1);
873a65dfe8SJens Axboe 			delete_partition(disk, part);
88c039e313SArjan van de Ven 			mutex_unlock(&bdev->bd_mutex);
89c039e313SArjan van de Ven 			mutex_unlock(&bdevp->bd_mutex);
903a65dfe8SJens Axboe 			bdput(bdevp);
913a65dfe8SJens Axboe 
923a65dfe8SJens Axboe 			return 0;
933a65dfe8SJens Axboe 		default:
943a65dfe8SJens Axboe 			return -EINVAL;
953a65dfe8SJens Axboe 	}
963a65dfe8SJens Axboe }
973a65dfe8SJens Axboe 
983a65dfe8SJens Axboe static int blkdev_reread_part(struct block_device *bdev)
993a65dfe8SJens Axboe {
1003a65dfe8SJens Axboe 	struct gendisk *disk = bdev->bd_disk;
1013a65dfe8SJens Axboe 	int res;
1023a65dfe8SJens Axboe 
1033a65dfe8SJens Axboe 	if (disk->minors == 1 || bdev != bdev->bd_contains)
1043a65dfe8SJens Axboe 		return -EINVAL;
1053a65dfe8SJens Axboe 	if (!capable(CAP_SYS_ADMIN))
1063a65dfe8SJens Axboe 		return -EACCES;
107c039e313SArjan van de Ven 	if (!mutex_trylock(&bdev->bd_mutex))
1083a65dfe8SJens Axboe 		return -EBUSY;
1093a65dfe8SJens Axboe 	res = rescan_partitions(disk, bdev);
110c039e313SArjan van de Ven 	mutex_unlock(&bdev->bd_mutex);
1113a65dfe8SJens Axboe 	return res;
1123a65dfe8SJens Axboe }
1133a65dfe8SJens Axboe 
114*d30a2605SDavid Woodhouse static void blk_ioc_discard_endio(struct bio *bio, int err)
115*d30a2605SDavid Woodhouse {
116*d30a2605SDavid Woodhouse 	if (err) {
117*d30a2605SDavid Woodhouse 		if (err == -EOPNOTSUPP)
118*d30a2605SDavid Woodhouse 			set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
119*d30a2605SDavid Woodhouse 		clear_bit(BIO_UPTODATE, &bio->bi_flags);
120*d30a2605SDavid Woodhouse 	}
121*d30a2605SDavid Woodhouse 	complete(bio->bi_private);
122*d30a2605SDavid Woodhouse }
123*d30a2605SDavid Woodhouse 
124*d30a2605SDavid Woodhouse static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
125*d30a2605SDavid Woodhouse 			     uint64_t len)
126*d30a2605SDavid Woodhouse {
127*d30a2605SDavid Woodhouse 	struct request_queue *q = bdev_get_queue(bdev);
128*d30a2605SDavid Woodhouse 	int ret = 0;
129*d30a2605SDavid Woodhouse 
130*d30a2605SDavid Woodhouse 	if (start & 511)
131*d30a2605SDavid Woodhouse 		return -EINVAL;
132*d30a2605SDavid Woodhouse 	if (len & 511)
133*d30a2605SDavid Woodhouse 		return -EINVAL;
134*d30a2605SDavid Woodhouse 	start >>= 9;
135*d30a2605SDavid Woodhouse 	len >>= 9;
136*d30a2605SDavid Woodhouse 
137*d30a2605SDavid Woodhouse 	if (start + len > (bdev->bd_inode->i_size >> 9))
138*d30a2605SDavid Woodhouse 		return -EINVAL;
139*d30a2605SDavid Woodhouse 
140*d30a2605SDavid Woodhouse 	if (!q->prepare_discard_fn)
141*d30a2605SDavid Woodhouse 		return -EOPNOTSUPP;
142*d30a2605SDavid Woodhouse 
143*d30a2605SDavid Woodhouse 	while (len && !ret) {
144*d30a2605SDavid Woodhouse 		DECLARE_COMPLETION_ONSTACK(wait);
145*d30a2605SDavid Woodhouse 		struct bio *bio;
146*d30a2605SDavid Woodhouse 
147*d30a2605SDavid Woodhouse 		bio = bio_alloc(GFP_KERNEL, 0);
148*d30a2605SDavid Woodhouse 		if (!bio)
149*d30a2605SDavid Woodhouse 			return -ENOMEM;
150*d30a2605SDavid Woodhouse 
151*d30a2605SDavid Woodhouse 		bio->bi_end_io = blk_ioc_discard_endio;
152*d30a2605SDavid Woodhouse 		bio->bi_bdev = bdev;
153*d30a2605SDavid Woodhouse 		bio->bi_private = &wait;
154*d30a2605SDavid Woodhouse 		bio->bi_sector = start;
155*d30a2605SDavid Woodhouse 
156*d30a2605SDavid Woodhouse 		if (len > q->max_hw_sectors) {
157*d30a2605SDavid Woodhouse 			bio->bi_size = q->max_hw_sectors << 9;
158*d30a2605SDavid Woodhouse 			len -= q->max_hw_sectors;
159*d30a2605SDavid Woodhouse 			start += q->max_hw_sectors;
160*d30a2605SDavid Woodhouse 		} else {
161*d30a2605SDavid Woodhouse 			bio->bi_size = len << 9;
162*d30a2605SDavid Woodhouse 			len = 0;
163*d30a2605SDavid Woodhouse 		}
164*d30a2605SDavid Woodhouse 		submit_bio(WRITE_DISCARD, bio);
165*d30a2605SDavid Woodhouse 
166*d30a2605SDavid Woodhouse 		wait_for_completion(&wait);
167*d30a2605SDavid Woodhouse 
168*d30a2605SDavid Woodhouse 		if (bio_flagged(bio, BIO_EOPNOTSUPP))
169*d30a2605SDavid Woodhouse 			ret = -EOPNOTSUPP;
170*d30a2605SDavid Woodhouse 		else if (!bio_flagged(bio, BIO_UPTODATE))
171*d30a2605SDavid Woodhouse 			ret = -EIO;
172*d30a2605SDavid Woodhouse 		bio_put(bio);
173*d30a2605SDavid Woodhouse 	}
174*d30a2605SDavid Woodhouse 	return ret;
175*d30a2605SDavid Woodhouse }
176*d30a2605SDavid Woodhouse 
1773a65dfe8SJens Axboe static int put_ushort(unsigned long arg, unsigned short val)
1783a65dfe8SJens Axboe {
1793a65dfe8SJens Axboe 	return put_user(val, (unsigned short __user *)arg);
1803a65dfe8SJens Axboe }
1813a65dfe8SJens Axboe 
1823a65dfe8SJens Axboe static int put_int(unsigned long arg, int val)
1833a65dfe8SJens Axboe {
1843a65dfe8SJens Axboe 	return put_user(val, (int __user *)arg);
1853a65dfe8SJens Axboe }
1863a65dfe8SJens Axboe 
1873a65dfe8SJens Axboe static int put_long(unsigned long arg, long val)
1883a65dfe8SJens Axboe {
1893a65dfe8SJens Axboe 	return put_user(val, (long __user *)arg);
1903a65dfe8SJens Axboe }
1913a65dfe8SJens Axboe 
1923a65dfe8SJens Axboe static int put_ulong(unsigned long arg, unsigned long val)
1933a65dfe8SJens Axboe {
1943a65dfe8SJens Axboe 	return put_user(val, (unsigned long __user *)arg);
1953a65dfe8SJens Axboe }
1963a65dfe8SJens Axboe 
1973a65dfe8SJens Axboe static int put_u64(unsigned long arg, u64 val)
1983a65dfe8SJens Axboe {
1993a65dfe8SJens Axboe 	return put_user(val, (u64 __user *)arg);
2003a65dfe8SJens Axboe }
2013a65dfe8SJens Axboe 
2023a65dfe8SJens Axboe static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev,
2033a65dfe8SJens Axboe 				unsigned cmd, unsigned long arg)
2043a65dfe8SJens Axboe {
2053a65dfe8SJens Axboe 	struct backing_dev_info *bdi;
2063a65dfe8SJens Axboe 	int ret, n;
2073a65dfe8SJens Axboe 
2083a65dfe8SJens Axboe 	switch (cmd) {
2093a65dfe8SJens Axboe 	case BLKRAGET:
2103a65dfe8SJens Axboe 	case BLKFRAGET:
2113a65dfe8SJens Axboe 		if (!arg)
2123a65dfe8SJens Axboe 			return -EINVAL;
2133a65dfe8SJens Axboe 		bdi = blk_get_backing_dev_info(bdev);
2143a65dfe8SJens Axboe 		if (bdi == NULL)
2153a65dfe8SJens Axboe 			return -ENOTTY;
2163a65dfe8SJens Axboe 		return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
2173a65dfe8SJens Axboe 	case BLKROGET:
2183a65dfe8SJens Axboe 		return put_int(arg, bdev_read_only(bdev) != 0);
2193a65dfe8SJens Axboe 	case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
2203a65dfe8SJens Axboe 		return put_int(arg, block_size(bdev));
2213a65dfe8SJens Axboe 	case BLKSSZGET: /* get block device hardware sector size */
2223a65dfe8SJens Axboe 		return put_int(arg, bdev_hardsect_size(bdev));
2233a65dfe8SJens Axboe 	case BLKSECTGET:
2243a65dfe8SJens Axboe 		return put_ushort(arg, bdev_get_queue(bdev)->max_sectors);
2253a65dfe8SJens Axboe 	case BLKRASET:
2263a65dfe8SJens Axboe 	case BLKFRASET:
2273a65dfe8SJens Axboe 		if(!capable(CAP_SYS_ADMIN))
2283a65dfe8SJens Axboe 			return -EACCES;
2293a65dfe8SJens Axboe 		bdi = blk_get_backing_dev_info(bdev);
2303a65dfe8SJens Axboe 		if (bdi == NULL)
2313a65dfe8SJens Axboe 			return -ENOTTY;
2323a65dfe8SJens Axboe 		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
2333a65dfe8SJens Axboe 		return 0;
2343a65dfe8SJens Axboe 	case BLKBSZSET:
2353a65dfe8SJens Axboe 		/* set the logical block size */
2363a65dfe8SJens Axboe 		if (!capable(CAP_SYS_ADMIN))
2373a65dfe8SJens Axboe 			return -EACCES;
2383a65dfe8SJens Axboe 		if (!arg)
2393a65dfe8SJens Axboe 			return -EINVAL;
2403a65dfe8SJens Axboe 		if (get_user(n, (int __user *) arg))
2413a65dfe8SJens Axboe 			return -EFAULT;
2423a65dfe8SJens Axboe 		if (bd_claim(bdev, file) < 0)
2433a65dfe8SJens Axboe 			return -EBUSY;
2443a65dfe8SJens Axboe 		ret = set_blocksize(bdev, n);
2453a65dfe8SJens Axboe 		bd_release(bdev);
2463a65dfe8SJens Axboe 		return ret;
2473a65dfe8SJens Axboe 	case BLKPG:
2483a65dfe8SJens Axboe 		return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
2493a65dfe8SJens Axboe 	case BLKRRPART:
2503a65dfe8SJens Axboe 		return blkdev_reread_part(bdev);
2513a65dfe8SJens Axboe 	case BLKGETSIZE:
2523a65dfe8SJens Axboe 		if ((bdev->bd_inode->i_size >> 9) > ~0UL)
2533a65dfe8SJens Axboe 			return -EFBIG;
2543a65dfe8SJens Axboe 		return put_ulong(arg, bdev->bd_inode->i_size >> 9);
2553a65dfe8SJens Axboe 	case BLKGETSIZE64:
2563a65dfe8SJens Axboe 		return put_u64(arg, bdev->bd_inode->i_size);
2572056a782SJens Axboe 	case BLKTRACESTART:
2582056a782SJens Axboe 	case BLKTRACESTOP:
2592056a782SJens Axboe 	case BLKTRACESETUP:
2602056a782SJens Axboe 	case BLKTRACETEARDOWN:
2612056a782SJens Axboe 		return blk_trace_ioctl(bdev, cmd, (char __user *) arg);
2623a65dfe8SJens Axboe 	}
2633a65dfe8SJens Axboe 	return -ENOIOCTLCMD;
2643a65dfe8SJens Axboe }
2653a65dfe8SJens Axboe 
2667006f6ecSAlasdair G Kergon int blkdev_driver_ioctl(struct inode *inode, struct file *file,
2673a65dfe8SJens Axboe 			struct gendisk *disk, unsigned cmd, unsigned long arg)
2683a65dfe8SJens Axboe {
2693a65dfe8SJens Axboe 	int ret;
2703a65dfe8SJens Axboe 	if (disk->fops->unlocked_ioctl)
2713a65dfe8SJens Axboe 		return disk->fops->unlocked_ioctl(file, cmd, arg);
2723a65dfe8SJens Axboe 
2733a65dfe8SJens Axboe 	if (disk->fops->ioctl) {
2743a65dfe8SJens Axboe 		lock_kernel();
2753a65dfe8SJens Axboe 		ret = disk->fops->ioctl(inode, file, cmd, arg);
2763a65dfe8SJens Axboe 		unlock_kernel();
2773a65dfe8SJens Axboe 		return ret;
2783a65dfe8SJens Axboe 	}
2793a65dfe8SJens Axboe 
2803a65dfe8SJens Axboe 	return -ENOTTY;
2813a65dfe8SJens Axboe }
2827006f6ecSAlasdair G Kergon EXPORT_SYMBOL_GPL(blkdev_driver_ioctl);
2833a65dfe8SJens Axboe 
284f58c4c0aSArnd Bergmann /*
285f58c4c0aSArnd Bergmann  * always keep this in sync with compat_blkdev_ioctl() and
286f58c4c0aSArnd Bergmann  * compat_blkdev_locked_ioctl()
287f58c4c0aSArnd Bergmann  */
2883a65dfe8SJens Axboe int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
2893a65dfe8SJens Axboe 			unsigned long arg)
2903a65dfe8SJens Axboe {
2913a65dfe8SJens Axboe 	struct block_device *bdev = inode->i_bdev;
2923a65dfe8SJens Axboe 	struct gendisk *disk = bdev->bd_disk;
2933a65dfe8SJens Axboe 	int ret, n;
2943a65dfe8SJens Axboe 
2953a65dfe8SJens Axboe 	switch(cmd) {
2963a65dfe8SJens Axboe 	case BLKFLSBUF:
2973a65dfe8SJens Axboe 		if (!capable(CAP_SYS_ADMIN))
2983a65dfe8SJens Axboe 			return -EACCES;
2993a65dfe8SJens Axboe 
3003a65dfe8SJens Axboe 		ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
3013a65dfe8SJens Axboe 		/* -EINVAL to handle old uncorrected drivers */
3023a65dfe8SJens Axboe 		if (ret != -EINVAL && ret != -ENOTTY)
3033a65dfe8SJens Axboe 			return ret;
3043a65dfe8SJens Axboe 
3053a65dfe8SJens Axboe 		lock_kernel();
3063a65dfe8SJens Axboe 		fsync_bdev(bdev);
307f98393a6SPeter Zijlstra 		invalidate_bdev(bdev);
3083a65dfe8SJens Axboe 		unlock_kernel();
3093a65dfe8SJens Axboe 		return 0;
3103a65dfe8SJens Axboe 
3113a65dfe8SJens Axboe 	case BLKROSET:
3123a65dfe8SJens Axboe 		ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
3133a65dfe8SJens Axboe 		/* -EINVAL to handle old uncorrected drivers */
3143a65dfe8SJens Axboe 		if (ret != -EINVAL && ret != -ENOTTY)
3153a65dfe8SJens Axboe 			return ret;
3163a65dfe8SJens Axboe 		if (!capable(CAP_SYS_ADMIN))
3173a65dfe8SJens Axboe 			return -EACCES;
3183a65dfe8SJens Axboe 		if (get_user(n, (int __user *)(arg)))
3193a65dfe8SJens Axboe 			return -EFAULT;
3203a65dfe8SJens Axboe 		lock_kernel();
3213a65dfe8SJens Axboe 		set_device_ro(bdev, n);
3223a65dfe8SJens Axboe 		unlock_kernel();
3233a65dfe8SJens Axboe 		return 0;
324*d30a2605SDavid Woodhouse 
325*d30a2605SDavid Woodhouse 	case BLKDISCARD: {
326*d30a2605SDavid Woodhouse 		uint64_t range[2];
327*d30a2605SDavid Woodhouse 
328*d30a2605SDavid Woodhouse 		if (!(file->f_mode & FMODE_WRITE))
329*d30a2605SDavid Woodhouse 			return -EBADF;
330*d30a2605SDavid Woodhouse 
331*d30a2605SDavid Woodhouse 		if (copy_from_user(range, (void __user *)arg, sizeof(range)))
332*d30a2605SDavid Woodhouse 			return -EFAULT;
333*d30a2605SDavid Woodhouse 
334*d30a2605SDavid Woodhouse 		return blk_ioctl_discard(bdev, range[0], range[1]);
335*d30a2605SDavid Woodhouse 	}
336*d30a2605SDavid Woodhouse 
337a885c8c4SChristoph Hellwig 	case HDIO_GETGEO: {
338a885c8c4SChristoph Hellwig 		struct hd_geometry geo;
339a885c8c4SChristoph Hellwig 
340a885c8c4SChristoph Hellwig 		if (!arg)
341a885c8c4SChristoph Hellwig 			return -EINVAL;
342a885c8c4SChristoph Hellwig 		if (!disk->fops->getgeo)
343a885c8c4SChristoph Hellwig 			return -ENOTTY;
344a885c8c4SChristoph Hellwig 
345a885c8c4SChristoph Hellwig 		/*
346a885c8c4SChristoph Hellwig 		 * We need to set the startsect first, the driver may
347a885c8c4SChristoph Hellwig 		 * want to override it.
348a885c8c4SChristoph Hellwig 		 */
349a885c8c4SChristoph Hellwig 		geo.start = get_start_sect(bdev);
350a885c8c4SChristoph Hellwig 		ret = disk->fops->getgeo(bdev, &geo);
351a885c8c4SChristoph Hellwig 		if (ret)
352a885c8c4SChristoph Hellwig 			return ret;
353a885c8c4SChristoph Hellwig 		if (copy_to_user((struct hd_geometry __user *)arg, &geo,
354a885c8c4SChristoph Hellwig 					sizeof(geo)))
355a885c8c4SChristoph Hellwig 			return -EFAULT;
356a885c8c4SChristoph Hellwig 		return 0;
357a885c8c4SChristoph Hellwig 	}
3583a65dfe8SJens Axboe 	}
3593a65dfe8SJens Axboe 
3603a65dfe8SJens Axboe 	lock_kernel();
3613a65dfe8SJens Axboe 	ret = blkdev_locked_ioctl(file, bdev, cmd, arg);
3623a65dfe8SJens Axboe 	unlock_kernel();
3633a65dfe8SJens Axboe 	if (ret != -ENOIOCTLCMD)
3643a65dfe8SJens Axboe 		return ret;
3653a65dfe8SJens Axboe 
3663a65dfe8SJens Axboe 	return blkdev_driver_ioctl(inode, file, disk, cmd, arg);
3673a65dfe8SJens Axboe }
3683a65dfe8SJens Axboe EXPORT_SYMBOL_GPL(blkdev_ioctl);
369