diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-26 14:38:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-26 14:38:48 -0400 |
| commit | fc7b3ff1ac0ca3250628911ca6534882db9f2cb3 (patch) | |
| tree | 96972cb5ef0a54c5011b308497ee43de550c8b3d | |
| parent | 019793b7554b18818624e9cf7a2ee8ba8cf6bda0 (diff) | |
| parent | 9ff4cfb3fcfd48b49fdd9be7381b3be340853aa4 (diff) | |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6:
[S390] kvm-390: Let kernel exit SIE instruction on work
[S390] dasd: check sense type in device change handler
[S390] pfault: fix token handling
[S390] qdio: reset error states immediately
[S390] fix page table walk for changing page attributes
[S390] prng: prevent access beyond end of stack
[S390] dasd: fix race between open and offline
| -rw-r--r-- | arch/s390/crypto/prng.c | 2 | ||||
| -rw-r--r-- | arch/s390/kvm/sie64a.S | 4 | ||||
| -rw-r--r-- | arch/s390/mm/fault.c | 4 | ||||
| -rw-r--r-- | arch/s390/mm/pageattr.c | 5 | ||||
| -rw-r--r-- | drivers/s390/block/dasd.c | 40 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_devmap.c | 30 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_eckd.c | 5 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_genhd.c | 2 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_int.h | 3 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 128 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_main.c | 17 |
11 files changed, 166 insertions, 74 deletions
diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index 975e3ab13cb5..44bca3f994b0 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c | |||
| @@ -76,7 +76,7 @@ static void prng_seed(int nbytes) | |||
| 76 | 76 | ||
| 77 | /* Add the entropy */ | 77 | /* Add the entropy */ |
| 78 | while (nbytes >= 8) { | 78 | while (nbytes >= 8) { |
| 79 | *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8); | 79 | *((__u64 *)parm_block) ^= *((__u64 *)buf+i); |
| 80 | prng_add_entropy(); | 80 | prng_add_entropy(); |
| 81 | i += 8; | 81 | i += 8; |
| 82 | nbytes -= 8; | 82 | nbytes -= 8; |
diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S index 7e9d30d567b0..ab0e041ac54c 100644 --- a/arch/s390/kvm/sie64a.S +++ b/arch/s390/kvm/sie64a.S | |||
| @@ -48,10 +48,10 @@ sie_irq_handler: | |||
| 48 | tm __TI_flags+7(%r2),_TIF_EXIT_SIE | 48 | tm __TI_flags+7(%r2),_TIF_EXIT_SIE |
| 49 | jz 0f | 49 | jz 0f |
| 50 | larl %r2,sie_exit # work pending, leave sie | 50 | larl %r2,sie_exit # work pending, leave sie |
| 51 | stg %r2,__LC_RETURN_PSW+8 | 51 | stg %r2,SPI_PSW+8(0,%r15) |
| 52 | br %r14 | 52 | br %r14 |
| 53 | 0: larl %r2,sie_reenter # re-enter with guest id | 53 | 0: larl %r2,sie_reenter # re-enter with guest id |
| 54 | stg %r2,__LC_RETURN_PSW+8 | 54 | stg %r2,SPI_PSW+8(0,%r15) |
| 55 | 1: br %r14 | 55 | 1: br %r14 |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 9217e332b118..4cf85fef407c 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -558,9 +558,9 @@ static void pfault_interrupt(unsigned int ext_int_code, | |||
| 558 | * Get the token (= address of the task structure of the affected task). | 558 | * Get the token (= address of the task structure of the affected task). |
| 559 | */ | 559 | */ |
| 560 | #ifdef CONFIG_64BIT | 560 | #ifdef CONFIG_64BIT |
| 561 | tsk = *(struct task_struct **) param64; | 561 | tsk = (struct task_struct *) param64; |
| 562 | #else | 562 | #else |
| 563 | tsk = *(struct task_struct **) param32; | 563 | tsk = (struct task_struct *) param32; |
| 564 | #endif | 564 | #endif |
| 565 | 565 | ||
| 566 | if (subcode & 0x0080) { | 566 | if (subcode & 0x0080) { |
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 122ffbd08ce0..0607e4b14b27 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c | |||
| @@ -24,12 +24,13 @@ static void change_page_attr(unsigned long addr, int numpages, | |||
| 24 | WARN_ON_ONCE(1); | 24 | WARN_ON_ONCE(1); |
| 25 | continue; | 25 | continue; |
| 26 | } | 26 | } |
| 27 | ptep = pte_offset_kernel(pmdp, addr + i * PAGE_SIZE); | 27 | ptep = pte_offset_kernel(pmdp, addr); |
| 28 | 28 | ||
| 29 | pte = *ptep; | 29 | pte = *ptep; |
| 30 | pte = set(pte); | 30 | pte = set(pte); |
| 31 | ptep_invalidate(&init_mm, addr + i * PAGE_SIZE, ptep); | 31 | ptep_invalidate(&init_mm, addr, ptep); |
| 32 | *ptep = pte; | 32 | *ptep = pte; |
| 33 | addr += PAGE_SIZE; | ||
| 33 | } | 34 | } |
| 34 | } | 35 | } |
| 35 | 36 | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4d2df2f76ea0..475e603fc584 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -2314,15 +2314,14 @@ static void dasd_flush_request_queue(struct dasd_block *block) | |||
| 2314 | 2314 | ||
| 2315 | static int dasd_open(struct block_device *bdev, fmode_t mode) | 2315 | static int dasd_open(struct block_device *bdev, fmode_t mode) |
| 2316 | { | 2316 | { |
| 2317 | struct dasd_block *block = bdev->bd_disk->private_data; | ||
| 2318 | struct dasd_device *base; | 2317 | struct dasd_device *base; |
| 2319 | int rc; | 2318 | int rc; |
| 2320 | 2319 | ||
| 2321 | if (!block) | 2320 | base = dasd_device_from_gendisk(bdev->bd_disk); |
| 2321 | if (!base) | ||
| 2322 | return -ENODEV; | 2322 | return -ENODEV; |
| 2323 | 2323 | ||
| 2324 | base = block->base; | 2324 | atomic_inc(&base->block->open_count); |
| 2325 | atomic_inc(&block->open_count); | ||
| 2326 | if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { | 2325 | if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { |
| 2327 | rc = -ENODEV; | 2326 | rc = -ENODEV; |
| 2328 | goto unlock; | 2327 | goto unlock; |
| @@ -2355,21 +2354,28 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) | |||
| 2355 | goto out; | 2354 | goto out; |
| 2356 | } | 2355 | } |
| 2357 | 2356 | ||
| 2357 | dasd_put_device(base); | ||
| 2358 | return 0; | 2358 | return 0; |
| 2359 | 2359 | ||
| 2360 | out: | 2360 | out: |
| 2361 | module_put(base->discipline->owner); | 2361 | module_put(base->discipline->owner); |
| 2362 | unlock: | 2362 | unlock: |
| 2363 | atomic_dec(&block->open_count); | 2363 | atomic_dec(&base->block->open_count); |
| 2364 | dasd_put_device(base); | ||
| 2364 | return rc; | 2365 | return rc; |
| 2365 | } | 2366 | } |
| 2366 | 2367 | ||
| 2367 | static int dasd_release(struct gendisk *disk, fmode_t mode) | 2368 | static int dasd_release(struct gendisk *disk, fmode_t mode) |
| 2368 | { | 2369 | { |
| 2369 | struct dasd_block *block = disk->private_data; | 2370 | struct dasd_device *base; |
| 2370 | 2371 | ||
| 2371 | atomic_dec(&block->open_count); | 2372 | base = dasd_device_from_gendisk(disk); |
| 2372 | module_put(block->base->discipline->owner); | 2373 | if (!base) |
| 2374 | return -ENODEV; | ||
| 2375 | |||
| 2376 | atomic_dec(&base->block->open_count); | ||
| 2377 | module_put(base->discipline->owner); | ||
| 2378 | dasd_put_device(base); | ||
| 2373 | return 0; | 2379 | return 0; |
| 2374 | } | 2380 | } |
| 2375 | 2381 | ||
| @@ -2378,20 +2384,20 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) | |||
| 2378 | */ | 2384 | */ |
| 2379 | static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) | 2385 | static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
| 2380 | { | 2386 | { |
| 2381 | struct dasd_block *block; | ||
| 2382 | struct dasd_device *base; | 2387 | struct dasd_device *base; |
| 2383 | 2388 | ||
| 2384 | block = bdev->bd_disk->private_data; | 2389 | base = dasd_device_from_gendisk(bdev->bd_disk); |
| 2385 | if (!block) | 2390 | if (!base) |
| 2386 | return -ENODEV; | 2391 | return -ENODEV; |
| 2387 | base = block->base; | ||
| 2388 | 2392 | ||
| 2389 | if (!base->discipline || | 2393 | if (!base->discipline || |
| 2390 | !base->discipline->fill_geometry) | 2394 | !base->discipline->fill_geometry) { |
| 2395 | dasd_put_device(base); | ||
| 2391 | return -EINVAL; | 2396 | return -EINVAL; |
| 2392 | 2397 | } | |
| 2393 | base->discipline->fill_geometry(block, geo); | 2398 | base->discipline->fill_geometry(base->block, geo); |
| 2394 | geo->start = get_start_sect(bdev) >> block->s2b_shift; | 2399 | geo->start = get_start_sect(bdev) >> base->block->s2b_shift; |
| 2400 | dasd_put_device(base); | ||
| 2395 | return 0; | 2401 | return 0; |
| 2396 | } | 2402 | } |
| 2397 | 2403 | ||
| @@ -2528,7 +2534,6 @@ void dasd_generic_remove(struct ccw_device *cdev) | |||
| 2528 | dasd_set_target_state(device, DASD_STATE_NEW); | 2534 | dasd_set_target_state(device, DASD_STATE_NEW); |
| 2529 | /* dasd_delete_device destroys the device reference. */ | 2535 | /* dasd_delete_device destroys the device reference. */ |
| 2530 | block = device->block; | 2536 | block = device->block; |
| 2531 | device->block = NULL; | ||
| 2532 | dasd_delete_device(device); | 2537 | dasd_delete_device(device); |
| 2533 | /* | 2538 | /* |
| 2534 | * life cycle of block is bound to device, so delete it after | 2539 | * life cycle of block is bound to device, so delete it after |
| @@ -2650,7 +2655,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev) | |||
| 2650 | dasd_set_target_state(device, DASD_STATE_NEW); | 2655 | dasd_set_target_state(device, DASD_STATE_NEW); |
| 2651 | /* dasd_delete_device destroys the device reference. */ | 2656 | /* dasd_delete_device destroys the device reference. */ |
| 2652 | block = device->block; | 2657 | block = device->block; |
| 2653 | device->block = NULL; | ||
| 2654 | dasd_delete_device(device); | 2658 | dasd_delete_device(device); |
| 2655 | /* | 2659 | /* |
| 2656 | * life cycle of block is bound to device, so delete it after | 2660 | * life cycle of block is bound to device, so delete it after |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 42e1bf35f689..d71511c7850a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
| @@ -674,6 +674,36 @@ dasd_device_from_cdev(struct ccw_device *cdev) | |||
| 674 | return device; | 674 | return device; |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) | ||
| 678 | { | ||
| 679 | struct dasd_devmap *devmap; | ||
| 680 | |||
| 681 | devmap = dasd_find_busid(dev_name(&device->cdev->dev)); | ||
| 682 | if (IS_ERR(devmap)) | ||
| 683 | return; | ||
| 684 | spin_lock(&dasd_devmap_lock); | ||
| 685 | gdp->private_data = devmap; | ||
| 686 | spin_unlock(&dasd_devmap_lock); | ||
| 687 | } | ||
| 688 | |||
| 689 | struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) | ||
| 690 | { | ||
| 691 | struct dasd_device *device; | ||
| 692 | struct dasd_devmap *devmap; | ||
| 693 | |||
| 694 | if (!gdp->private_data) | ||
| 695 | return NULL; | ||
| 696 | device = NULL; | ||
| 697 | spin_lock(&dasd_devmap_lock); | ||
| 698 | devmap = gdp->private_data; | ||
| 699 | if (devmap && devmap->device) { | ||
| 700 | device = devmap->device; | ||
| 701 | dasd_get_device(device); | ||
| 702 | } | ||
| 703 | spin_unlock(&dasd_devmap_lock); | ||
| 704 | return device; | ||
| 705 | } | ||
| 706 | |||
| 677 | /* | 707 | /* |
| 678 | * SECTION: files in sysfs | 708 | * SECTION: files in sysfs |
| 679 | */ | 709 | */ |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index db8005d9f2fd..3ebdf5f92f8f 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -2037,7 +2037,7 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, | |||
| 2037 | return; | 2037 | return; |
| 2038 | 2038 | ||
| 2039 | /* summary unit check */ | 2039 | /* summary unit check */ |
| 2040 | if ((sense[7] == 0x0D) && | 2040 | if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) && |
| 2041 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { | 2041 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { |
| 2042 | dasd_alias_handle_summary_unit_check(device, irb); | 2042 | dasd_alias_handle_summary_unit_check(device, irb); |
| 2043 | return; | 2043 | return; |
| @@ -2053,7 +2053,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, | |||
| 2053 | /* loss of device reservation is handled via base devices only | 2053 | /* loss of device reservation is handled via base devices only |
| 2054 | * as alias devices may be used with several bases | 2054 | * as alias devices may be used with several bases |
| 2055 | */ | 2055 | */ |
| 2056 | if (device->block && (sense[7] == 0x3F) && | 2056 | if (device->block && (sense[27] & DASD_SENSE_BIT_0) && |
| 2057 | (sense[7] == 0x3F) && | ||
| 2057 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && | 2058 | (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && |
| 2058 | test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { | 2059 | test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { |
| 2059 | if (device->features & DASD_FEATURE_FAILONSLCK) | 2060 | if (device->features & DASD_FEATURE_FAILONSLCK) |
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 5505bc07e1e7..19a1ff03d65e 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c | |||
| @@ -73,7 +73,7 @@ int dasd_gendisk_alloc(struct dasd_block *block) | |||
| 73 | if (base->features & DASD_FEATURE_READONLY || | 73 | if (base->features & DASD_FEATURE_READONLY || |
| 74 | test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) | 74 | test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) |
| 75 | set_disk_ro(gdp, 1); | 75 | set_disk_ro(gdp, 1); |
| 76 | gdp->private_data = block; | 76 | dasd_add_link_to_gendisk(gdp, base); |
| 77 | gdp->queue = block->request_queue; | 77 | gdp->queue = block->request_queue; |
| 78 | block->gdp = gdp; | 78 | block->gdp = gdp; |
| 79 | set_capacity(block->gdp, 0); | 79 | set_capacity(block->gdp, 0); |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index df9f6999411d..d1e4f2c1264c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
| @@ -686,6 +686,9 @@ struct dasd_device *dasd_device_from_cdev(struct ccw_device *); | |||
| 686 | struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); | 686 | struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); |
| 687 | struct dasd_device *dasd_device_from_devindex(int); | 687 | struct dasd_device *dasd_device_from_devindex(int); |
| 688 | 688 | ||
| 689 | void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *); | ||
| 690 | struct dasd_device *dasd_device_from_gendisk(struct gendisk *); | ||
| 691 | |||
| 689 | int dasd_parse(void); | 692 | int dasd_parse(void); |
| 690 | int dasd_busid_known(const char *); | 693 | int dasd_busid_known(const char *); |
| 691 | 694 | ||
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 26075e95b1ba..72261e4c516d 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
| @@ -42,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp) | |||
| 42 | static int | 42 | static int |
| 43 | dasd_ioctl_enable(struct block_device *bdev) | 43 | dasd_ioctl_enable(struct block_device *bdev) |
| 44 | { | 44 | { |
| 45 | struct dasd_block *block = bdev->bd_disk->private_data; | 45 | struct dasd_device *base; |
| 46 | 46 | ||
| 47 | if (!capable(CAP_SYS_ADMIN)) | 47 | if (!capable(CAP_SYS_ADMIN)) |
| 48 | return -EACCES; | 48 | return -EACCES; |
| 49 | 49 | ||
| 50 | dasd_enable_device(block->base); | 50 | base = dasd_device_from_gendisk(bdev->bd_disk); |
| 51 | if (!base) | ||
| 52 | return -ENODEV; | ||
| 53 | |||
| 54 | dasd_enable_device(base); | ||
| 51 | /* Formatting the dasd device can change the capacity. */ | 55 | /* Formatting the dasd device can change the capacity. */ |
| 52 | mutex_lock(&bdev->bd_mutex); | 56 | mutex_lock(&bdev->bd_mutex); |
| 53 | i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9); | 57 | i_size_write(bdev->bd_inode, |
| 58 | (loff_t)get_capacity(base->block->gdp) << 9); | ||
| 54 | mutex_unlock(&bdev->bd_mutex); | 59 | mutex_unlock(&bdev->bd_mutex); |
| 60 | dasd_put_device(base); | ||
| 55 | return 0; | 61 | return 0; |
| 56 | } | 62 | } |
| 57 | 63 | ||
| @@ -62,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev) | |||
| 62 | static int | 68 | static int |
| 63 | dasd_ioctl_disable(struct block_device *bdev) | 69 | dasd_ioctl_disable(struct block_device *bdev) |
| 64 | { | 70 | { |
| 65 | struct dasd_block *block = bdev->bd_disk->private_data; | 71 | struct dasd_device *base; |
| 66 | 72 | ||
| 67 | if (!capable(CAP_SYS_ADMIN)) | 73 | if (!capable(CAP_SYS_ADMIN)) |
| 68 | return -EACCES; | 74 | return -EACCES; |
| 69 | 75 | ||
| 76 | base = dasd_device_from_gendisk(bdev->bd_disk); | ||
| 77 | if (!base) | ||
| 78 | return -ENODEV; | ||
| 70 | /* | 79 | /* |
| 71 | * Man this is sick. We don't do a real disable but only downgrade | 80 | * Man this is sick. We don't do a real disable but only downgrade |
| 72 | * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses | 81 | * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses |
| @@ -75,7 +84,7 @@ dasd_ioctl_disable(struct block_device *bdev) | |||
| 75 | * using the BIODASDFMT ioctl. Therefore the correct state for the | 84 | * using the BIODASDFMT ioctl. Therefore the correct state for the |
| 76 | * device is DASD_STATE_BASIC that allows to do basic i/o. | 85 | * device is DASD_STATE_BASIC that allows to do basic i/o. |
| 77 | */ | 86 | */ |
| 78 | dasd_set_target_state(block->base, DASD_STATE_BASIC); | 87 | dasd_set_target_state(base, DASD_STATE_BASIC); |
| 79 | /* | 88 | /* |
| 80 | * Set i_size to zero, since read, write, etc. check against this | 89 | * Set i_size to zero, since read, write, etc. check against this |
| 81 | * value. | 90 | * value. |
| @@ -83,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev) | |||
| 83 | mutex_lock(&bdev->bd_mutex); | 92 | mutex_lock(&bdev->bd_mutex); |
| 84 | i_size_write(bdev->bd_inode, 0); | 93 | i_size_write(bdev->bd_inode, 0); |
| 85 | mutex_unlock(&bdev->bd_mutex); | 94 | mutex_unlock(&bdev->bd_mutex); |
| 95 | dasd_put_device(base); | ||
| 86 | return 0; | 96 | return 0; |
| 87 | } | 97 | } |
| 88 | 98 | ||
| @@ -191,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) | |||
| 191 | static int | 201 | static int |
| 192 | dasd_ioctl_format(struct block_device *bdev, void __user *argp) | 202 | dasd_ioctl_format(struct block_device *bdev, void __user *argp) |
| 193 | { | 203 | { |
| 194 | struct dasd_block *block = bdev->bd_disk->private_data; | 204 | struct dasd_device *base; |
| 195 | struct format_data_t fdata; | 205 | struct format_data_t fdata; |
| 206 | int rc; | ||
| 196 | 207 | ||
| 197 | if (!capable(CAP_SYS_ADMIN)) | 208 | if (!capable(CAP_SYS_ADMIN)) |
| 198 | return -EACCES; | 209 | return -EACCES; |
| 199 | if (!argp) | 210 | if (!argp) |
| 200 | return -EINVAL; | 211 | return -EINVAL; |
| 201 | 212 | base = dasd_device_from_gendisk(bdev->bd_disk); | |
| 202 | if (block->base->features & DASD_FEATURE_READONLY || | 213 | if (!base) |
| 203 | test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) | 214 | return -ENODEV; |
| 215 | if (base->features & DASD_FEATURE_READONLY || | ||
| 216 | test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { | ||
| 217 | dasd_put_device(base); | ||
| 204 | return -EROFS; | 218 | return -EROFS; |
| 205 | if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) | 219 | } |
| 220 | if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) { | ||
| 221 | dasd_put_device(base); | ||
| 206 | return -EFAULT; | 222 | return -EFAULT; |
| 223 | } | ||
| 207 | if (bdev != bdev->bd_contains) { | 224 | if (bdev != bdev->bd_contains) { |
| 208 | pr_warning("%s: The specified DASD is a partition and cannot " | 225 | pr_warning("%s: The specified DASD is a partition and cannot " |
| 209 | "be formatted\n", | 226 | "be formatted\n", |
| 210 | dev_name(&block->base->cdev->dev)); | 227 | dev_name(&base->cdev->dev)); |
| 228 | dasd_put_device(base); | ||
| 211 | return -EINVAL; | 229 | return -EINVAL; |
| 212 | } | 230 | } |
| 213 | return dasd_format(block, &fdata); | 231 | rc = dasd_format(base->block, &fdata); |
| 232 | dasd_put_device(base); | ||
| 233 | return rc; | ||
| 214 | } | 234 | } |
| 215 | 235 | ||
| 216 | #ifdef CONFIG_DASD_PROFILE | 236 | #ifdef CONFIG_DASD_PROFILE |
| @@ -340,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block, | |||
| 340 | static int | 360 | static int |
| 341 | dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) | 361 | dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) |
| 342 | { | 362 | { |
| 343 | struct dasd_block *block = bdev->bd_disk->private_data; | 363 | struct dasd_device *base; |
| 344 | int intval; | 364 | int intval, rc; |
| 345 | 365 | ||
| 346 | if (!capable(CAP_SYS_ADMIN)) | 366 | if (!capable(CAP_SYS_ADMIN)) |
| 347 | return -EACCES; | 367 | return -EACCES; |
| @@ -350,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) | |||
| 350 | return -EINVAL; | 370 | return -EINVAL; |
| 351 | if (get_user(intval, (int __user *)argp)) | 371 | if (get_user(intval, (int __user *)argp)) |
| 352 | return -EFAULT; | 372 | return -EFAULT; |
| 353 | if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) | 373 | base = dasd_device_from_gendisk(bdev->bd_disk); |
| 374 | if (!base) | ||
| 375 | return -ENODEV; | ||
| 376 | if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { | ||
| 377 | dasd_put_device(base); | ||
| 354 | return -EROFS; | 378 | return -EROFS; |
| 379 | } | ||
| 355 | set_disk_ro(bdev->bd_disk, intval); | 380 | set_disk_ro(bdev->bd_disk, intval); |
| 356 | return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); | 381 | rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval); |
| 382 | dasd_put_device(base); | ||
| 383 | return rc; | ||
| 357 | } | 384 | } |
| 358 | 385 | ||
| 359 | static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, | 386 | static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, |
| @@ -372,59 +399,78 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, | |||
| 372 | int dasd_ioctl(struct block_device *bdev, fmode_t mode, | 399 | int dasd_ioctl(struct block_device *bdev, fmode_t mode, |
| 373 | unsigned int cmd, unsigned long arg) | 400 | unsigned int cmd, unsigned long arg) |
| 374 | { | 401 | { |
| 375 | struct dasd_block *block = bdev->bd_disk->private_data; | 402 | struct dasd_block *block; |
| 403 | struct dasd_device *base; | ||
| 376 | void __user *argp; | 404 | void __user *argp; |
| 405 | int rc; | ||
| 377 | 406 | ||
| 378 | if (is_compat_task()) | 407 | if (is_compat_task()) |
| 379 | argp = compat_ptr(arg); | 408 | argp = compat_ptr(arg); |
| 380 | else | 409 | else |
| 381 | argp = (void __user *)arg; | 410 | argp = (void __user *)arg; |
| 382 | 411 | ||
| 383 | if (!block) | ||
| 384 | return -ENODEV; | ||
| 385 | |||
| 386 | if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { | 412 | if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { |
| 387 | PRINT_DEBUG("empty data ptr"); | 413 | PRINT_DEBUG("empty data ptr"); |
| 388 | return -EINVAL; | 414 | return -EINVAL; |
| 389 | } | 415 | } |
| 390 | 416 | ||
| 417 | base = dasd_device_from_gendisk(bdev->bd_disk); | ||
| 418 | if (!base) | ||
| 419 | return -ENODEV; | ||
| 420 | block = base->block; | ||
| 421 | rc = 0; | ||
| 391 | switch (cmd) { | 422 | switch (cmd) { |
| 392 | case BIODASDDISABLE: | 423 | case BIODASDDISABLE: |
| 393 | return dasd_ioctl_disable(bdev); | 424 | rc = dasd_ioctl_disable(bdev); |
| 425 | break; | ||
| 394 | case BIODASDENABLE: | 426 | case BIODASDENABLE: |
| 395 | return dasd_ioctl_enable(bdev); | 427 | rc = dasd_ioctl_enable(bdev); |
| 428 | break; | ||
| 396 | case BIODASDQUIESCE: | 429 | case BIODASDQUIESCE: |
| 397 | return dasd_ioctl_quiesce(block); | 430 | rc = dasd_ioctl_quiesce(block); |
| 431 | break; | ||
| 398 | case BIODASDRESUME: | 432 | case BIODASDRESUME: |
| 399 | return dasd_ioctl_resume(block); | 433 | rc = dasd_ioctl_resume(block); |
| 434 | break; | ||
| 400 | case BIODASDFMT: | 435 | case BIODASDFMT: |
| 401 | return dasd_ioctl_format(bdev, argp); | 436 | rc = dasd_ioctl_format(bdev, argp); |
| 437 | break; | ||
| 402 | case BIODASDINFO: | 438 | case BIODASDINFO: |
| 403 | return dasd_ioctl_information(block, cmd, argp); | 439 | rc = dasd_ioctl_information(block, cmd, argp); |
| 440 | break; | ||
| 404 | case BIODASDINFO2: | 441 | case BIODASDINFO2: |
| 405 | return dasd_ioctl_information(block, cmd, argp); | 442 | rc = dasd_ioctl_information(block, cmd, argp); |
| 443 | break; | ||
| 406 | case BIODASDPRRD: | 444 | case BIODASDPRRD: |
| 407 | return dasd_ioctl_read_profile(block, argp); | 445 | rc = dasd_ioctl_read_profile(block, argp); |
| 446 | break; | ||
| 408 | case BIODASDPRRST: | 447 | case BIODASDPRRST: |
| 409 | return dasd_ioctl_reset_profile(block); | 448 | rc = dasd_ioctl_reset_profile(block); |
| 449 | break; | ||
| 410 | case BLKROSET: | 450 | case BLKROSET: |
| 411 | return dasd_ioctl_set_ro(bdev, argp); | 451 | rc = dasd_ioctl_set_ro(bdev, argp); |
| 452 | break; | ||
| 412 | case DASDAPIVER: | 453 | case DASDAPIVER: |
| 413 | return dasd_ioctl_api_version(argp); | 454 | rc = dasd_ioctl_api_version(argp); |
| 455 | break; | ||
| 414 | case BIODASDCMFENABLE: | 456 | case BIODASDCMFENABLE: |
| 415 | return enable_cmf(block->base->cdev); | 457 | rc = enable_cmf(base->cdev); |
| 458 | break; | ||
| 416 | case BIODASDCMFDISABLE: | 459 | case BIODASDCMFDISABLE: |
| 417 | return disable_cmf(block->base->cdev); | 460 | rc = disable_cmf(base->cdev); |
| 461 | break; | ||
| 418 | case BIODASDREADALLCMB: | 462 | case BIODASDREADALLCMB: |
| 419 | return dasd_ioctl_readall_cmb(block, cmd, argp); | 463 | rc = dasd_ioctl_readall_cmb(block, cmd, argp); |
| 464 | break; | ||
| 420 | default: | 465 | default: |
| 421 | /* if the discipline has an ioctl method try it. */ | 466 | /* if the discipline has an ioctl method try it. */ |
| 422 | if (block->base->discipline->ioctl) { | 467 | if (base->discipline->ioctl) { |
| 423 | int rval = block->base->discipline->ioctl(block, cmd, argp); | 468 | rc = base->discipline->ioctl(block, cmd, argp); |
| 424 | if (rval != -ENOIOCTLCMD) | 469 | if (rc == -ENOIOCTLCMD) |
| 425 | return rval; | 470 | rc = -EINVAL; |
| 426 | } | 471 | } else |
| 427 | 472 | rc = -EINVAL; | |
| 428 | return -EINVAL; | ||
| 429 | } | 473 | } |
| 474 | dasd_put_device(base); | ||
| 475 | return rc; | ||
| 430 | } | 476 | } |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index c532ba929ccd..e8f267eb8887 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
| @@ -407,8 +407,11 @@ static inline void account_sbals(struct qdio_q *q, int count) | |||
| 407 | q->q_stats.nr_sbals[pos]++; | 407 | q->q_stats.nr_sbals[pos]++; |
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | static void announce_buffer_error(struct qdio_q *q, int count) | 410 | static void process_buffer_error(struct qdio_q *q, int count) |
| 411 | { | 411 | { |
| 412 | unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : | ||
| 413 | SLSB_P_OUTPUT_NOT_INIT; | ||
| 414 | |||
| 412 | q->qdio_error |= QDIO_ERROR_SLSB_STATE; | 415 | q->qdio_error |= QDIO_ERROR_SLSB_STATE; |
| 413 | 416 | ||
| 414 | /* special handling for no target buffer empty */ | 417 | /* special handling for no target buffer empty */ |
| @@ -426,6 +429,12 @@ static void announce_buffer_error(struct qdio_q *q, int count) | |||
| 426 | DBF_ERROR("F14:%2x F15:%2x", | 429 | DBF_ERROR("F14:%2x F15:%2x", |
| 427 | q->sbal[q->first_to_check]->element[14].flags & 0xff, | 430 | q->sbal[q->first_to_check]->element[14].flags & 0xff, |
| 428 | q->sbal[q->first_to_check]->element[15].flags & 0xff); | 431 | q->sbal[q->first_to_check]->element[15].flags & 0xff); |
| 432 | |||
| 433 | /* | ||
| 434 | * Interrupts may be avoided as long as the error is present | ||
| 435 | * so change the buffer state immediately to avoid starvation. | ||
| 436 | */ | ||
| 437 | set_buf_states(q, q->first_to_check, state, count); | ||
| 429 | } | 438 | } |
| 430 | 439 | ||
| 431 | static inline void inbound_primed(struct qdio_q *q, int count) | 440 | static inline void inbound_primed(struct qdio_q *q, int count) |
| @@ -506,8 +515,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) | |||
| 506 | account_sbals(q, count); | 515 | account_sbals(q, count); |
| 507 | break; | 516 | break; |
| 508 | case SLSB_P_INPUT_ERROR: | 517 | case SLSB_P_INPUT_ERROR: |
| 509 | announce_buffer_error(q, count); | 518 | process_buffer_error(q, count); |
| 510 | /* process the buffer, the upper layer will take care of it */ | ||
| 511 | q->first_to_check = add_buf(q->first_to_check, count); | 519 | q->first_to_check = add_buf(q->first_to_check, count); |
| 512 | atomic_sub(count, &q->nr_buf_used); | 520 | atomic_sub(count, &q->nr_buf_used); |
| 513 | if (q->irq_ptr->perf_stat_enabled) | 521 | if (q->irq_ptr->perf_stat_enabled) |
| @@ -677,8 +685,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) | |||
| 677 | account_sbals(q, count); | 685 | account_sbals(q, count); |
| 678 | break; | 686 | break; |
| 679 | case SLSB_P_OUTPUT_ERROR: | 687 | case SLSB_P_OUTPUT_ERROR: |
| 680 | announce_buffer_error(q, count); | 688 | process_buffer_error(q, count); |
| 681 | /* process the buffer, the upper layer will take care of it */ | ||
| 682 | q->first_to_check = add_buf(q->first_to_check, count); | 689 | q->first_to_check = add_buf(q->first_to_check, count); |
| 683 | atomic_sub(count, &q->nr_buf_used); | 690 | atomic_sub(count, &q->nr_buf_used); |
| 684 | if (q->irq_ptr->perf_stat_enabled) | 691 | if (q->irq_ptr->perf_stat_enabled) |
