| .. | .. |
|---|
| 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 | } |
|---|
| .. | .. |
|---|
| 137 | 133 | spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); |
|---|
| 138 | 134 | |
|---|
| 139 | 135 | dasd_schedule_block_bh(block); |
|---|
| 136 | + dasd_schedule_device_bh(base); |
|---|
| 140 | 137 | return 0; |
|---|
| 141 | 138 | } |
|---|
| 142 | 139 | |
|---|
| .. | .. |
|---|
| 281 | 278 | dasd_put_device(base); |
|---|
| 282 | 279 | return -EFAULT; |
|---|
| 283 | 280 | } |
|---|
| 284 | | - if (bdev != bdev->bd_contains) { |
|---|
| 281 | + if (bdev_is_partition(bdev)) { |
|---|
| 285 | 282 | pr_warn("%s: The specified DASD is a partition and cannot be formatted\n", |
|---|
| 286 | 283 | dev_name(&base->cdev->dev)); |
|---|
| 287 | 284 | dasd_put_device(base); |
|---|
| .. | .. |
|---|
| 308 | 305 | base = dasd_device_from_gendisk(bdev->bd_disk); |
|---|
| 309 | 306 | if (!base) |
|---|
| 310 | 307 | return -ENODEV; |
|---|
| 311 | | - if (bdev != bdev->bd_contains) { |
|---|
| 308 | + if (bdev_is_partition(bdev)) { |
|---|
| 312 | 309 | pr_warn("%s: The specified DASD is a partition and cannot be checked\n", |
|---|
| 313 | 310 | dev_name(&base->cdev->dev)); |
|---|
| 314 | 311 | rc = -EINVAL; |
|---|
| .. | .. |
|---|
| 326 | 323 | |
|---|
| 327 | 324 | if (copy_to_user(argp, &cdata, sizeof(cdata))) |
|---|
| 328 | 325 | rc = -EFAULT; |
|---|
| 326 | + |
|---|
| 327 | +out_err: |
|---|
| 328 | + dasd_put_device(base); |
|---|
| 329 | + |
|---|
| 330 | + return rc; |
|---|
| 331 | +} |
|---|
| 332 | + |
|---|
| 333 | +static int dasd_release_space(struct dasd_device *device, |
|---|
| 334 | + struct format_data_t *rdata) |
|---|
| 335 | +{ |
|---|
| 336 | + if (!device->discipline->is_ese && !device->discipline->is_ese(device)) |
|---|
| 337 | + return -ENOTSUPP; |
|---|
| 338 | + if (!device->discipline->release_space) |
|---|
| 339 | + return -ENOTSUPP; |
|---|
| 340 | + |
|---|
| 341 | + return device->discipline->release_space(device, rdata); |
|---|
| 342 | +} |
|---|
| 343 | + |
|---|
| 344 | +/* |
|---|
| 345 | + * Release allocated space |
|---|
| 346 | + */ |
|---|
| 347 | +static int dasd_ioctl_release_space(struct block_device *bdev, void __user *argp) |
|---|
| 348 | +{ |
|---|
| 349 | + struct format_data_t rdata; |
|---|
| 350 | + struct dasd_device *base; |
|---|
| 351 | + int rc = 0; |
|---|
| 352 | + |
|---|
| 353 | + if (!capable(CAP_SYS_ADMIN)) |
|---|
| 354 | + return -EACCES; |
|---|
| 355 | + if (!argp) |
|---|
| 356 | + return -EINVAL; |
|---|
| 357 | + |
|---|
| 358 | + base = dasd_device_from_gendisk(bdev->bd_disk); |
|---|
| 359 | + if (!base) |
|---|
| 360 | + return -ENODEV; |
|---|
| 361 | + if (base->features & DASD_FEATURE_READONLY || |
|---|
| 362 | + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { |
|---|
| 363 | + rc = -EROFS; |
|---|
| 364 | + goto out_err; |
|---|
| 365 | + } |
|---|
| 366 | + if (bdev_is_partition(bdev)) { |
|---|
| 367 | + pr_warn("%s: The specified DASD is a partition and tracks cannot be released\n", |
|---|
| 368 | + dev_name(&base->cdev->dev)); |
|---|
| 369 | + rc = -EINVAL; |
|---|
| 370 | + goto out_err; |
|---|
| 371 | + } |
|---|
| 372 | + |
|---|
| 373 | + if (copy_from_user(&rdata, argp, sizeof(rdata))) { |
|---|
| 374 | + rc = -EFAULT; |
|---|
| 375 | + goto out_err; |
|---|
| 376 | + } |
|---|
| 377 | + |
|---|
| 378 | + rc = dasd_release_space(base, &rdata); |
|---|
| 329 | 379 | |
|---|
| 330 | 380 | out_err: |
|---|
| 331 | 381 | dasd_put_device(base); |
|---|
| .. | .. |
|---|
| 404 | 454 | /* |
|---|
| 405 | 455 | * Return dasd information. Used for BIODASDINFO and BIODASDINFO2. |
|---|
| 406 | 456 | */ |
|---|
| 407 | | -static int dasd_ioctl_information(struct dasd_block *block, |
|---|
| 408 | | - unsigned int cmd, void __user *argp) |
|---|
| 457 | +static int __dasd_ioctl_information(struct dasd_block *block, |
|---|
| 458 | + struct dasd_information2_t *dasd_info) |
|---|
| 409 | 459 | { |
|---|
| 410 | | - struct dasd_information2_t *dasd_info; |
|---|
| 411 | 460 | struct subchannel_id sch_id; |
|---|
| 412 | 461 | struct ccw_dev_id dev_id; |
|---|
| 413 | 462 | struct dasd_device *base; |
|---|
| 414 | 463 | struct ccw_device *cdev; |
|---|
| 464 | + struct list_head *l; |
|---|
| 415 | 465 | unsigned long flags; |
|---|
| 416 | 466 | int rc; |
|---|
| 417 | 467 | |
|---|
| .. | .. |
|---|
| 419 | 469 | if (!base->discipline || !base->discipline->fill_info) |
|---|
| 420 | 470 | return -EINVAL; |
|---|
| 421 | 471 | |
|---|
| 422 | | - dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL); |
|---|
| 423 | | - if (dasd_info == NULL) |
|---|
| 424 | | - return -ENOMEM; |
|---|
| 425 | | - |
|---|
| 426 | 472 | rc = base->discipline->fill_info(base, dasd_info); |
|---|
| 427 | | - if (rc) { |
|---|
| 428 | | - kfree(dasd_info); |
|---|
| 473 | + if (rc) |
|---|
| 429 | 474 | return rc; |
|---|
| 430 | | - } |
|---|
| 431 | 475 | |
|---|
| 432 | 476 | cdev = base->cdev; |
|---|
| 433 | 477 | ccw_device_get_id(cdev, &dev_id); |
|---|
| .. | .. |
|---|
| 462 | 506 | |
|---|
| 463 | 507 | memcpy(dasd_info->type, base->discipline->name, 4); |
|---|
| 464 | 508 | |
|---|
| 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 | | - } |
|---|
| 509 | + spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); |
|---|
| 510 | + list_for_each(l, &base->ccw_queue) |
|---|
| 511 | + dasd_info->chanq_len++; |
|---|
| 512 | + spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); |
|---|
| 513 | + return 0; |
|---|
| 514 | +} |
|---|
| 482 | 515 | |
|---|
| 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; |
|---|
| 516 | +static int dasd_ioctl_information(struct dasd_block *block, void __user *argp, |
|---|
| 517 | + size_t copy_size) |
|---|
| 518 | +{ |
|---|
| 519 | + struct dasd_information2_t *dasd_info; |
|---|
| 520 | + int error; |
|---|
| 521 | + |
|---|
| 522 | + dasd_info = kzalloc(sizeof(*dasd_info), GFP_KERNEL); |
|---|
| 523 | + if (!dasd_info) |
|---|
| 524 | + return -ENOMEM; |
|---|
| 525 | + |
|---|
| 526 | + error = __dasd_ioctl_information(block, dasd_info); |
|---|
| 527 | + if (!error && copy_to_user(argp, dasd_info, copy_size)) |
|---|
| 528 | + error = -EFAULT; |
|---|
| 489 | 529 | kfree(dasd_info); |
|---|
| 490 | | - return rc; |
|---|
| 530 | + return error; |
|---|
| 491 | 531 | } |
|---|
| 492 | 532 | |
|---|
| 493 | 533 | /* |
|---|
| .. | .. |
|---|
| 501 | 541 | |
|---|
| 502 | 542 | if (!capable(CAP_SYS_ADMIN)) |
|---|
| 503 | 543 | return -EACCES; |
|---|
| 504 | | - if (bdev != bdev->bd_contains) |
|---|
| 544 | + if (bdev_is_partition(bdev)) |
|---|
| 505 | 545 | // ro setting is not allowed for partitions |
|---|
| 506 | 546 | return -EINVAL; |
|---|
| 507 | 547 | if (get_user(intval, (int __user *)argp)) |
|---|
| .. | .. |
|---|
| 581 | 621 | rc = dasd_ioctl_check_format(bdev, argp); |
|---|
| 582 | 622 | break; |
|---|
| 583 | 623 | case BIODASDINFO: |
|---|
| 584 | | - rc = dasd_ioctl_information(block, cmd, argp); |
|---|
| 624 | + rc = dasd_ioctl_information(block, argp, |
|---|
| 625 | + sizeof(struct dasd_information_t)); |
|---|
| 585 | 626 | break; |
|---|
| 586 | 627 | case BIODASDINFO2: |
|---|
| 587 | | - rc = dasd_ioctl_information(block, cmd, argp); |
|---|
| 628 | + rc = dasd_ioctl_information(block, argp, |
|---|
| 629 | + sizeof(struct dasd_information2_t)); |
|---|
| 588 | 630 | break; |
|---|
| 589 | 631 | case BIODASDPRRD: |
|---|
| 590 | 632 | rc = dasd_ioctl_read_profile(block, argp); |
|---|
| .. | .. |
|---|
| 607 | 649 | case BIODASDREADALLCMB: |
|---|
| 608 | 650 | rc = dasd_ioctl_readall_cmb(block, cmd, argp); |
|---|
| 609 | 651 | break; |
|---|
| 652 | + case BIODASDRAS: |
|---|
| 653 | + rc = dasd_ioctl_release_space(bdev, argp); |
|---|
| 654 | + break; |
|---|
| 610 | 655 | default: |
|---|
| 611 | 656 | /* if the discipline has an ioctl method try it. */ |
|---|
| 612 | 657 | rc = -ENOTTY; |
|---|
| .. | .. |
|---|
| 616 | 661 | dasd_put_device(base); |
|---|
| 617 | 662 | return rc; |
|---|
| 618 | 663 | } |
|---|
| 664 | + |
|---|
| 665 | + |
|---|
| 666 | +/** |
|---|
| 667 | + * dasd_biodasdinfo() - fill out the dasd information structure |
|---|
| 668 | + * @disk [in]: pointer to gendisk structure that references a DASD |
|---|
| 669 | + * @info [out]: pointer to the dasd_information2_t structure |
|---|
| 670 | + * |
|---|
| 671 | + * Provide access to DASD specific information. |
|---|
| 672 | + * The gendisk structure is checked if it belongs to the DASD driver by |
|---|
| 673 | + * comparing the gendisk->fops pointer. |
|---|
| 674 | + * If it does not belong to the DASD driver -EINVAL is returned. |
|---|
| 675 | + * Otherwise the provided dasd_information2_t structure is filled out. |
|---|
| 676 | + * |
|---|
| 677 | + * Returns: |
|---|
| 678 | + * %0 on success and a negative error value on failure. |
|---|
| 679 | + */ |
|---|
| 680 | +int dasd_biodasdinfo(struct gendisk *disk, struct dasd_information2_t *info) |
|---|
| 681 | +{ |
|---|
| 682 | + struct dasd_device *base; |
|---|
| 683 | + int error; |
|---|
| 684 | + |
|---|
| 685 | + if (disk->fops != &dasd_device_operations) |
|---|
| 686 | + return -EINVAL; |
|---|
| 687 | + |
|---|
| 688 | + base = dasd_device_from_gendisk(disk); |
|---|
| 689 | + if (!base) |
|---|
| 690 | + return -ENODEV; |
|---|
| 691 | + error = __dasd_ioctl_information(base->block, info); |
|---|
| 692 | + dasd_put_device(base); |
|---|
| 693 | + return error; |
|---|
| 694 | +} |
|---|
| 695 | +/* export that symbol_get in partition detection is possible */ |
|---|
| 696 | +EXPORT_SYMBOL_GPL(dasd_biodasdinfo); |
|---|