Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: cleanup blkdev_ioctl

Split out helpers for all non-trivial ioctls to make this function simpler,
and also start passing around a pointer version of the argument, as that's
what most ioctl handlers actually need.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@fb.com>

authored by

Christoph Hellwig and committed by
Jens Axboe
d8e4bb81 ef658fc2

+128 -101
+128 -101
block/ioctl.c
··· 193 193 } 194 194 EXPORT_SYMBOL(blkdev_reread_part); 195 195 196 - static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, 197 - uint64_t len, int secure) 196 + static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, 197 + unsigned long arg, unsigned long flags) 198 198 { 199 - unsigned long flags = 0; 199 + uint64_t range[2]; 200 + uint64_t start, len; 201 + 202 + if (!(mode & FMODE_WRITE)) 203 + return -EBADF; 204 + 205 + if (copy_from_user(range, (void __user *)arg, sizeof(range))) 206 + return -EFAULT; 207 + 208 + start = range[0]; 209 + len = range[1]; 200 210 201 211 if (start & 511) 202 212 return -EINVAL; ··· 217 207 218 208 if (start + len > (i_size_read(bdev->bd_inode) >> 9)) 219 209 return -EINVAL; 220 - if (secure) 221 - flags |= BLKDEV_DISCARD_SECURE; 222 210 return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags); 223 211 } 224 212 225 - static int blk_ioctl_zeroout(struct block_device *bdev, uint64_t start, 226 - uint64_t len) 213 + static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode, 214 + unsigned long arg) 227 215 { 216 + uint64_t range[2]; 217 + uint64_t start, len; 218 + 219 + if (!(mode & FMODE_WRITE)) 220 + return -EBADF; 221 + 222 + if (copy_from_user(range, (void __user *)arg, sizeof(range))) 223 + return -EFAULT; 224 + 225 + start = range[0]; 226 + len = range[1]; 227 + 228 228 if (start & 511) 229 229 return -EINVAL; 230 230 if (len & 511) ··· 315 295 ret == -ENOIOCTLCMD; 316 296 } 317 297 298 + static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode, 299 + unsigned cmd, unsigned long arg) 300 + { 301 + int ret; 302 + 303 + if (!capable(CAP_SYS_ADMIN)) 304 + return -EACCES; 305 + 306 + ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); 307 + if (!is_unrecognized_ioctl(ret)) 308 + return ret; 309 + 310 + fsync_bdev(bdev); 311 + invalidate_bdev(bdev); 312 + return 0; 313 + } 314 + 315 + static int blkdev_roset(struct block_device *bdev, fmode_t mode, 316 + unsigned cmd, unsigned long arg) 317 + { 318 + int ret, n; 319 + 320 + ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); 321 + if (!is_unrecognized_ioctl(ret)) 322 + return ret; 323 + if (!capable(CAP_SYS_ADMIN)) 324 + return -EACCES; 325 + if (get_user(n, (int __user *)arg)) 326 + return -EFAULT; 327 + set_device_ro(bdev, n); 328 + return 0; 329 + } 330 + 331 + static int blkdev_getgeo(struct block_device *bdev, 332 + struct hd_geometry __user *argp) 333 + { 334 + struct gendisk *disk = bdev->bd_disk; 335 + struct hd_geometry geo; 336 + int ret; 337 + 338 + if (!argp) 339 + return -EINVAL; 340 + if (!disk->fops->getgeo) 341 + return -ENOTTY; 342 + 343 + /* 344 + * We need to set the startsect first, the driver may 345 + * want to override it. 346 + */ 347 + memset(&geo, 0, sizeof(geo)); 348 + geo.start = get_start_sect(bdev); 349 + ret = disk->fops->getgeo(bdev, &geo); 350 + if (ret) 351 + return ret; 352 + if (copy_to_user(argp, &geo, sizeof(geo))) 353 + return -EFAULT; 354 + return 0; 355 + } 356 + 357 + /* set the logical block size */ 358 + static int blkdev_bszset(struct block_device *bdev, fmode_t mode, 359 + int __user *argp) 360 + { 361 + int ret, n; 362 + 363 + if (!capable(CAP_SYS_ADMIN)) 364 + return -EACCES; 365 + if (!argp) 366 + return -EINVAL; 367 + if (get_user(n, argp)) 368 + return -EFAULT; 369 + 370 + if (!(mode & FMODE_EXCL)) { 371 + bdgrab(bdev); 372 + if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0) 373 + return -EBUSY; 374 + } 375 + 376 + ret = set_blocksize(bdev, n); 377 + if (!(mode & FMODE_EXCL)) 378 + blkdev_put(bdev, mode | FMODE_EXCL); 379 + return ret; 380 + } 381 + 318 382 /* 319 383 * always keep this in sync with compat_blkdev_ioctl() 320 384 */ 321 385 int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, 322 386 unsigned long arg) 323 387 { 324 - struct gendisk *disk = bdev->bd_disk; 325 388 struct backing_dev_info *bdi; 389 + void __user *argp = (void __user *)arg; 326 390 loff_t size; 327 - int ret, n; 328 391 unsigned int max_sectors; 329 392 330 - switch(cmd) { 393 + switch (cmd) { 331 394 case BLKFLSBUF: 332 - if (!capable(CAP_SYS_ADMIN)) 333 - return -EACCES; 334 - 335 - ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); 336 - if (!is_unrecognized_ioctl(ret)) 337 - return ret; 338 - 339 - fsync_bdev(bdev); 340 - invalidate_bdev(bdev); 341 - return 0; 342 - 395 + return blkdev_flushbuf(bdev, mode, cmd, arg); 343 396 case BLKROSET: 344 - ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); 345 - if (!is_unrecognized_ioctl(ret)) 346 - return ret; 347 - if (!capable(CAP_SYS_ADMIN)) 348 - return -EACCES; 349 - if (get_user(n, (int __user *)(arg))) 350 - return -EFAULT; 351 - set_device_ro(bdev, n); 352 - return 0; 353 - 397 + return blkdev_roset(bdev, mode, cmd, arg); 354 398 case BLKDISCARD: 355 - case BLKSECDISCARD: { 356 - uint64_t range[2]; 357 - 358 - if (!(mode & FMODE_WRITE)) 359 - return -EBADF; 360 - 361 - if (copy_from_user(range, (void __user *)arg, sizeof(range))) 362 - return -EFAULT; 363 - 364 - return blk_ioctl_discard(bdev, range[0], range[1], 365 - cmd == BLKSECDISCARD); 366 - } 367 - case BLKZEROOUT: { 368 - uint64_t range[2]; 369 - 370 - if (!(mode & FMODE_WRITE)) 371 - return -EBADF; 372 - 373 - if (copy_from_user(range, (void __user *)arg, sizeof(range))) 374 - return -EFAULT; 375 - 376 - return blk_ioctl_zeroout(bdev, range[0], range[1]); 377 - } 378 - 379 - case HDIO_GETGEO: { 380 - struct hd_geometry geo; 381 - 382 - if (!arg) 383 - return -EINVAL; 384 - if (!disk->fops->getgeo) 385 - return -ENOTTY; 386 - 387 - /* 388 - * We need to set the startsect first, the driver may 389 - * want to override it. 390 - */ 391 - memset(&geo, 0, sizeof(geo)); 392 - geo.start = get_start_sect(bdev); 393 - ret = disk->fops->getgeo(bdev, &geo); 394 - if (ret) 395 - return ret; 396 - if (copy_to_user((struct hd_geometry __user *)arg, &geo, 397 - sizeof(geo))) 398 - return -EFAULT; 399 - return 0; 400 - } 399 + return blk_ioctl_discard(bdev, mode, arg, 0); 400 + case BLKSECDISCARD: 401 + return blk_ioctl_discard(bdev, mode, arg, 402 + BLKDEV_DISCARD_SECURE); 403 + case BLKZEROOUT: 404 + return blk_ioctl_zeroout(bdev, mode, arg); 405 + case HDIO_GETGEO: 406 + return blkdev_getgeo(bdev, argp); 401 407 case BLKRAGET: 402 408 case BLKFRAGET: 403 409 if (!arg) ··· 460 414 bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE; 461 415 return 0; 462 416 case BLKBSZSET: 463 - /* set the logical block size */ 464 - if (!capable(CAP_SYS_ADMIN)) 465 - return -EACCES; 466 - if (!arg) 467 - return -EINVAL; 468 - if (get_user(n, (int __user *) arg)) 469 - return -EFAULT; 470 - if (!(mode & FMODE_EXCL)) { 471 - bdgrab(bdev); 472 - if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0) 473 - return -EBUSY; 474 - } 475 - ret = set_blocksize(bdev, n); 476 - if (!(mode & FMODE_EXCL)) 477 - blkdev_put(bdev, mode | FMODE_EXCL); 478 - return ret; 417 + return blkdev_bszset(bdev, mode, argp); 479 418 case BLKPG: 480 - ret = blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg); 481 - break; 419 + return blkpg_ioctl(bdev, argp); 482 420 case BLKRRPART: 483 - ret = blkdev_reread_part(bdev); 484 - break; 421 + return blkdev_reread_part(bdev); 485 422 case BLKGETSIZE: 486 423 size = i_size_read(bdev->bd_inode); 487 424 if ((size >> 9) > ~0UL) ··· 476 447 case BLKTRACESTOP: 477 448 case BLKTRACESETUP: 478 449 case BLKTRACETEARDOWN: 479 - ret = blk_trace_ioctl(bdev, cmd, (char __user *) arg); 480 - break; 450 + return blk_trace_ioctl(bdev, cmd, argp); 481 451 default: 482 - ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); 452 + return __blkdev_driver_ioctl(bdev, mode, cmd, arg); 483 453 } 484 - return ret; 485 454 } 486 455 EXPORT_SYMBOL_GPL(blkdev_ioctl);