.. | .. |
---|
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); |
---|