| .. | .. |
|---|
| 22 | 22 | #include <asm/schid.h> |
|---|
| 23 | 23 | #include <asm/cmb.h> |
|---|
| 24 | 24 | #include <linux/uaccess.h> |
|---|
| 25 | +#include <linux/dasd_mod.h> |
|---|
| 25 | 26 | |
|---|
| 26 | 27 | /* This is ugly... */ |
|---|
| 27 | 28 | #define PRINTK_HEADER "dasd_ioctl:" |
|---|
| .. | .. |
|---|
| 54 | 55 | |
|---|
| 55 | 56 | dasd_enable_device(base); |
|---|
| 56 | 57 | /* Formatting the dasd device can change the capacity. */ |
|---|
| 57 | | - mutex_lock(&bdev->bd_mutex); |
|---|
| 58 | | - i_size_write(bdev->bd_inode, |
|---|
| 59 | | - (loff_t)get_capacity(base->block->gdp) << 9); |
|---|
| 60 | | - mutex_unlock(&bdev->bd_mutex); |
|---|
| 58 | + bd_set_nr_sectors(bdev, get_capacity(base->block->gdp)); |
|---|
| 61 | 59 | dasd_put_device(base); |
|---|
| 62 | 60 | return 0; |
|---|
| 63 | 61 | } |
|---|
| .. | .. |
|---|
| 90 | 88 | * Set i_size to zero, since read, write, etc. check against this |
|---|
| 91 | 89 | * value. |
|---|
| 92 | 90 | */ |
|---|
| 93 | | - mutex_lock(&bdev->bd_mutex); |
|---|
| 94 | | - i_size_write(bdev->bd_inode, 0); |
|---|
| 95 | | - mutex_unlock(&bdev->bd_mutex); |
|---|
| 91 | + bd_set_nr_sectors(bdev, 0); |
|---|
| 96 | 92 | dasd_put_device(base); |
|---|
| 97 | 93 | return 0; |
|---|
| 98 | 94 | } |
|---|
| .. | .. |
|---|
| 281 | 277 | dasd_put_device(base); |
|---|
| 282 | 278 | return -EFAULT; |
|---|
| 283 | 279 | } |
|---|
| 284 | | - if (bdev != bdev->bd_contains) { |
|---|
| 280 | + if (bdev_is_partition(bdev)) { |
|---|
| 285 | 281 | pr_warn("%s: The specified DASD is a partition and cannot be formatted\n", |
|---|
| 286 | 282 | dev_name(&base->cdev->dev)); |
|---|
| 287 | 283 | dasd_put_device(base); |
|---|
| .. | .. |
|---|
| 308 | 304 | base = dasd_device_from_gendisk(bdev->bd_disk); |
|---|
| 309 | 305 | if (!base) |
|---|
| 310 | 306 | return -ENODEV; |
|---|
| 311 | | - if (bdev != bdev->bd_contains) { |
|---|
| 307 | + if (bdev_is_partition(bdev)) { |
|---|
| 312 | 308 | pr_warn("%s: The specified DASD is a partition and cannot be checked\n", |
|---|
| 313 | 309 | dev_name(&base->cdev->dev)); |
|---|
| 314 | 310 | rc = -EINVAL; |
|---|
| .. | .. |
|---|
| 326 | 322 | |
|---|
| 327 | 323 | if (copy_to_user(argp, &cdata, sizeof(cdata))) |
|---|
| 328 | 324 | rc = -EFAULT; |
|---|
| 325 | + |
|---|
| 326 | +out_err: |
|---|
| 327 | + dasd_put_device(base); |
|---|
| 328 | + |
|---|
| 329 | + return rc; |
|---|
| 330 | +} |
|---|
| 331 | + |
|---|
| 332 | +static int dasd_release_space(struct dasd_device *device, |
|---|
| 333 | + struct format_data_t *rdata) |
|---|
| 334 | +{ |
|---|
| 335 | + if (!device->discipline->is_ese && !device->discipline->is_ese(device)) |
|---|
| 336 | + return -ENOTSUPP; |
|---|
| 337 | + if (!device->discipline->release_space) |
|---|
| 338 | + return -ENOTSUPP; |
|---|
| 339 | + |
|---|
| 340 | + return device->discipline->release_space(device, rdata); |
|---|
| 341 | +} |
|---|
| 342 | + |
|---|
| 343 | +/* |
|---|
| 344 | + * Release allocated space |
|---|
| 345 | + */ |
|---|
| 346 | +static int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp) |
|---|
| 347 | +{ |
|---|
| 348 | + struct format_data_t rdata; |
|---|
| 349 | + struct dasd_device *base; |
|---|
| 350 | + int rc = 0; |
|---|
| 351 | + |
|---|
| 352 | + if (!capable(CAP_SYS_ADMIN)) |
|---|
| 353 | + return -EACCES; |
|---|
| 354 | + if (!argp) |
|---|
| 355 | + return -EINVAL; |
|---|
| 356 | + |
|---|
| 357 | + base = dasd_device_from_gendisk(bdev->bd_disk); |
|---|
| 358 | + if (!base) |
|---|
| 359 | + return -ENODEV; |
|---|
| 360 | + if (base->features & DASD_FEATURE_READONLY || |
|---|
| 361 | + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { |
|---|
| 362 | + rc = -EROFS; |
|---|
| 363 | + goto out_err; |
|---|
| 364 | + } |
|---|
| 365 | + if (bdev_is_partition(bdev)) { |
|---|
| 366 | + pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n", |
|---|
| 367 | + dev_name(&base->cdev->dev)); |
|---|
| 368 | + rc = -EINVAL; |
|---|
| 369 | + goto out_err; |
|---|
| 370 | + } |
|---|
| 371 | + |
|---|
| 372 | + if (copy_from_user(&rdata, argp, sizeof(rdata))) { |
|---|
| 373 | + rc = -EFAULT; |
|---|
| 374 | + goto out_err; |
|---|
| 375 | + } |
|---|
| 376 | + |
|---|
| 377 | + rc = dasd_release_space(base, &rdata); |
|---|
| 329 | 378 | |
|---|
| 330 | 379 | out_err: |
|---|
| 331 | 380 | dasd_put_device(base); |
|---|
| .. | .. |
|---|
| 404 | 453 | /* |
|---|
| 405 | 454 | * Return dasd information. Used for BIODASDINFO and BIODASDINFO2. |
|---|
| 406 | 455 | */ |
|---|
| 407 | | -static int dasd_ioctl_information(struct dasd_block *block, |
|---|
| 408 | | - unsigned int cmd, void __user *argp) |
|---|
| 456 | +static int __dasd_ioctl_information(struct dasd_block *block, |
|---|
| 457 | + struct dasd_information2_t *dasd_info) |
|---|
| 409 | 458 | { |
|---|
| 410 | | - struct dasd_information2_t *dasd_info; |
|---|
| 411 | 459 | struct subchannel_id sch_id; |
|---|
| 412 | 460 | struct ccw_dev_id dev_id; |
|---|
| 413 | 461 | struct dasd_device *base; |
|---|
| 414 | 462 | struct ccw_device *cdev; |
|---|
| 463 | + struct list_head *l; |
|---|
| 415 | 464 | unsigned long flags; |
|---|
| 416 | 465 | int rc; |
|---|
| 417 | 466 | |
|---|
| .. | .. |
|---|
| 419 | 468 | if (!base->discipline || !base->discipline->fill_info) |
|---|
| 420 | 469 | return -EINVAL; |
|---|
| 421 | 470 | |
|---|
| 422 | | - dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL); |
|---|
| 423 | | - if (dasd_info == NULL) |
|---|
| 424 | | - return -ENOMEM; |
|---|
| 425 | | - |
|---|
| 426 | 471 | rc = base->discipline->fill_info(base, dasd_info); |
|---|
| 427 | | - if (rc) { |
|---|
| 428 | | - kfree(dasd_info); |
|---|
| 472 | + if (rc) |
|---|
| 429 | 473 | return rc; |
|---|
| 430 | | - } |
|---|
| 431 | 474 | |
|---|
| 432 | 475 | cdev = base->cdev; |
|---|
| 433 | 476 | ccw_device_get_id(cdev, &dev_id); |
|---|
| .. | .. |
|---|
| 462 | 505 | |
|---|
| 463 | 506 | memcpy(dasd_info->type, base->discipline->name, 4); |
|---|
| 464 | 507 | |
|---|
| 465 | | - if (block->request_queue->request_fn) { |
|---|
| 466 | | - struct list_head *l; |
|---|
| 467 | | -#ifdef DASD_EXTENDED_PROFILING |
|---|
| 468 | | - { |
|---|
| 469 | | - struct list_head *l; |
|---|
| 470 | | - spin_lock_irqsave(&block->lock, flags); |
|---|
| 471 | | - list_for_each(l, &block->request_queue->queue_head) |
|---|
| 472 | | - dasd_info->req_queue_len++; |
|---|
| 473 | | - spin_unlock_irqrestore(&block->lock, flags); |
|---|
| 474 | | - } |
|---|
| 475 | | -#endif /* DASD_EXTENDED_PROFILING */ |
|---|
| 476 | | - spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); |
|---|
| 477 | | - list_for_each(l, &base->ccw_queue) |
|---|
| 478 | | - dasd_info->chanq_len++; |
|---|
| 479 | | - spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), |
|---|
| 480 | | - flags); |
|---|
| 481 | | - } |
|---|
| 508 | + spin_lock_irqsave(&block->queue_lock, flags); |
|---|
| 509 | + list_for_each(l, &base->ccw_queue) |
|---|
| 510 | + dasd_info->chanq_len++; |
|---|
| 511 | + spin_unlock_irqrestore(&block->queue_lock, flags); |
|---|
| 512 | + return 0; |
|---|
| 513 | +} |
|---|
| 482 | 514 | |
|---|
| 483 | | - rc = 0; |
|---|
| 484 | | - if (copy_to_user(argp, dasd_info, |
|---|
| 485 | | - ((cmd == (unsigned int) BIODASDINFO2) ? |
|---|
| 486 | | - sizeof(struct dasd_information2_t) : |
|---|
| 487 | | - sizeof(struct dasd_information_t)))) |
|---|
| 488 | | - rc = -EFAULT; |
|---|
| 515 | +static int dasd_ioctl_information(struct dasd_block *block, void __user *argp, |
|---|
| 516 | + size_t copy_size) |
|---|
| 517 | +{ |
|---|
| 518 | + struct dasd_information2_t *dasd_info; |
|---|
| 519 | + int error; |
|---|
| 520 | + |
|---|
| 521 | + dasd_info = kzalloc(sizeof(*dasd_info), GFP_KERNEL); |
|---|
| 522 | + if (!dasd_info) |
|---|
| 523 | + return -ENOMEM; |
|---|
| 524 | + |
|---|
| 525 | + error = __dasd_ioctl_information(block, dasd_info); |
|---|
| 526 | + if (!error && copy_to_user(argp, dasd_info, copy_size)) |
|---|
| 527 | + error = -EFAULT; |
|---|
| 489 | 528 | kfree(dasd_info); |
|---|
| 490 | | - return rc; |
|---|
| 529 | + return error; |
|---|
| 491 | 530 | } |
|---|
| 492 | 531 | |
|---|
| 493 | 532 | /* |
|---|
| .. | .. |
|---|
| 501 | 540 | |
|---|
| 502 | 541 | if (!capable(CAP_SYS_ADMIN)) |
|---|
| 503 | 542 | return -EACCES; |
|---|
| 504 | | - if (bdev != bdev->bd_contains) |
|---|
| 543 | + if (bdev_is_partition(bdev)) |
|---|
| 505 | 544 | // ro setting is not allowed for partitions |
|---|
| 506 | 545 | return -EINVAL; |
|---|
| 507 | 546 | if (get_user(intval, (int __user *)argp)) |
|---|
| .. | .. |
|---|
| 581 | 620 | rc = dasd_ioctl_check_format(bdev, argp); |
|---|
| 582 | 621 | break; |
|---|
| 583 | 622 | case BIODASDINFO: |
|---|
| 584 | | - rc = dasd_ioctl_information(block, cmd, argp); |
|---|
| 623 | + rc = dasd_ioctl_information(block, argp, |
|---|
| 624 | + sizeof(struct dasd_information_t)); |
|---|
| 585 | 625 | break; |
|---|
| 586 | 626 | case BIODASDINFO2: |
|---|
| 587 | | - rc = dasd_ioctl_information(block, cmd, argp); |
|---|
| 627 | + rc = dasd_ioctl_information(block, argp, |
|---|
| 628 | + sizeof(struct dasd_information2_t)); |
|---|
| 588 | 629 | break; |
|---|
| 589 | 630 | case BIODASDPRRD: |
|---|
| 590 | 631 | rc = dasd_ioctl_read_profile(block, argp); |
|---|
| .. | .. |
|---|
| 607 | 648 | case BIODASDREADALLCMB: |
|---|
| 608 | 649 | rc = dasd_ioctl_readall_cmb(block, cmd, argp); |
|---|
| 609 | 650 | break; |
|---|
| 651 | + case BIODASDRAS: |
|---|
| 652 | + rc = dasd_ioctl_release_space(bdev, argp); |
|---|
| 653 | + break; |
|---|
| 610 | 654 | default: |
|---|
| 611 | 655 | /* if the discipline has an ioctl method try it. */ |
|---|
| 612 | 656 | rc = -ENOTTY; |
|---|
| .. | .. |
|---|
| 616 | 660 | dasd_put_device(base); |
|---|
| 617 | 661 | return rc; |
|---|
| 618 | 662 | } |
|---|
| 663 | + |
|---|
| 664 | + |
|---|
| 665 | +/** |
|---|
| 666 | + * dasd_biodasdinfo() - fill out the dasd information structure |
|---|
| 667 | + * @disk [in]: pointer to gendisk structure that references a DASD |
|---|
| 668 | + * @info [out]: pointer to the dasd_information2_t structure |
|---|
| 669 | + * |
|---|
| 670 | + * Provide access to DASD specific information. |
|---|
| 671 | + * The gendisk structure is checked if it belongs to the DASD driver by |
|---|
| 672 | + * comparing the gendisk->fops pointer. |
|---|
| 673 | + * If it does not belong to the DASD driver -EINVAL is returned. |
|---|
| 674 | + * Otherwise the provided dasd_information2_t structure is filled out. |
|---|
| 675 | + * |
|---|
| 676 | + * Returns: |
|---|
| 677 | + * %0 on success and a negative error value on failure. |
|---|
| 678 | + */ |
|---|
| 679 | +int dasd_biodasdinfo(struct gendisk *disk, struct dasd_information2_t *info) |
|---|
| 680 | +{ |
|---|
| 681 | + struct dasd_device *base; |
|---|
| 682 | + int error; |
|---|
| 683 | + |
|---|
| 684 | + if (disk->fops != &dasd_device_operations) |
|---|
| 685 | + return -EINVAL; |
|---|
| 686 | + |
|---|
| 687 | + base = dasd_device_from_gendisk(disk); |
|---|
| 688 | + if (!base) |
|---|
| 689 | + return -ENODEV; |
|---|
| 690 | + error = __dasd_ioctl_information(base->block, info); |
|---|
| 691 | + dasd_put_device(base); |
|---|
| 692 | + return error; |
|---|
| 693 | +} |
|---|
| 694 | +/* export that symbol_get in partition detection is possible */ |
|---|
| 695 | +EXPORT_SYMBOL_GPL(dasd_biodasdinfo); |
|---|