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
This commit is contained in:
Коммит
fc7b3ff1ac
|
@ -76,7 +76,7 @@ static void prng_seed(int nbytes)
|
||||||
|
|
||||||
/* Add the entropy */
|
/* Add the entropy */
|
||||||
while (nbytes >= 8) {
|
while (nbytes >= 8) {
|
||||||
*((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
|
*((__u64 *)parm_block) ^= *((__u64 *)buf+i);
|
||||||
prng_add_entropy();
|
prng_add_entropy();
|
||||||
i += 8;
|
i += 8;
|
||||||
nbytes -= 8;
|
nbytes -= 8;
|
||||||
|
|
|
@ -48,10 +48,10 @@ sie_irq_handler:
|
||||||
tm __TI_flags+7(%r2),_TIF_EXIT_SIE
|
tm __TI_flags+7(%r2),_TIF_EXIT_SIE
|
||||||
jz 0f
|
jz 0f
|
||||||
larl %r2,sie_exit # work pending, leave sie
|
larl %r2,sie_exit # work pending, leave sie
|
||||||
stg %r2,__LC_RETURN_PSW+8
|
stg %r2,SPI_PSW+8(0,%r15)
|
||||||
br %r14
|
br %r14
|
||||||
0: larl %r2,sie_reenter # re-enter with guest id
|
0: larl %r2,sie_reenter # re-enter with guest id
|
||||||
stg %r2,__LC_RETURN_PSW+8
|
stg %r2,SPI_PSW+8(0,%r15)
|
||||||
1: br %r14
|
1: br %r14
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -558,9 +558,9 @@ static void pfault_interrupt(unsigned int ext_int_code,
|
||||||
* Get the token (= address of the task structure of the affected task).
|
* Get the token (= address of the task structure of the affected task).
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
tsk = *(struct task_struct **) param64;
|
tsk = (struct task_struct *) param64;
|
||||||
#else
|
#else
|
||||||
tsk = *(struct task_struct **) param32;
|
tsk = (struct task_struct *) param32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (subcode & 0x0080) {
|
if (subcode & 0x0080) {
|
||||||
|
|
|
@ -24,12 +24,13 @@ static void change_page_attr(unsigned long addr, int numpages,
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ptep = pte_offset_kernel(pmdp, addr + i * PAGE_SIZE);
|
ptep = pte_offset_kernel(pmdp, addr);
|
||||||
|
|
||||||
pte = *ptep;
|
pte = *ptep;
|
||||||
pte = set(pte);
|
pte = set(pte);
|
||||||
ptep_invalidate(&init_mm, addr + i * PAGE_SIZE, ptep);
|
ptep_invalidate(&init_mm, addr, ptep);
|
||||||
*ptep = pte;
|
*ptep = pte;
|
||||||
|
addr += PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2314,15 +2314,14 @@ static void dasd_flush_request_queue(struct dasd_block *block)
|
||||||
|
|
||||||
static int dasd_open(struct block_device *bdev, fmode_t mode)
|
static int dasd_open(struct block_device *bdev, fmode_t mode)
|
||||||
{
|
{
|
||||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
|
||||||
struct dasd_device *base;
|
struct dasd_device *base;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!block)
|
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||||
|
if (!base)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
base = block->base;
|
atomic_inc(&base->block->open_count);
|
||||||
atomic_inc(&block->open_count);
|
|
||||||
if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
|
if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
@ -2355,21 +2354,28 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dasd_put_device(base);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
module_put(base->discipline->owner);
|
module_put(base->discipline->owner);
|
||||||
unlock:
|
unlock:
|
||||||
atomic_dec(&block->open_count);
|
atomic_dec(&base->block->open_count);
|
||||||
|
dasd_put_device(base);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dasd_release(struct gendisk *disk, fmode_t mode)
|
static int dasd_release(struct gendisk *disk, fmode_t mode)
|
||||||
{
|
{
|
||||||
struct dasd_block *block = disk->private_data;
|
struct dasd_device *base;
|
||||||
|
|
||||||
atomic_dec(&block->open_count);
|
base = dasd_device_from_gendisk(disk);
|
||||||
module_put(block->base->discipline->owner);
|
if (!base)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
atomic_dec(&base->block->open_count);
|
||||||
|
module_put(base->discipline->owner);
|
||||||
|
dasd_put_device(base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2378,20 +2384,20 @@ static int dasd_release(struct gendisk *disk, fmode_t mode)
|
||||||
*/
|
*/
|
||||||
static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
||||||
{
|
{
|
||||||
struct dasd_block *block;
|
|
||||||
struct dasd_device *base;
|
struct dasd_device *base;
|
||||||
|
|
||||||
block = bdev->bd_disk->private_data;
|
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||||
if (!block)
|
if (!base)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
base = block->base;
|
|
||||||
|
|
||||||
if (!base->discipline ||
|
if (!base->discipline ||
|
||||||
!base->discipline->fill_geometry)
|
!base->discipline->fill_geometry) {
|
||||||
|
dasd_put_device(base);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
base->discipline->fill_geometry(block, geo);
|
base->discipline->fill_geometry(base->block, geo);
|
||||||
geo->start = get_start_sect(bdev) >> block->s2b_shift;
|
geo->start = get_start_sect(bdev) >> base->block->s2b_shift;
|
||||||
|
dasd_put_device(base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2528,7 +2534,6 @@ void dasd_generic_remove(struct ccw_device *cdev)
|
||||||
dasd_set_target_state(device, DASD_STATE_NEW);
|
dasd_set_target_state(device, DASD_STATE_NEW);
|
||||||
/* dasd_delete_device destroys the device reference. */
|
/* dasd_delete_device destroys the device reference. */
|
||||||
block = device->block;
|
block = device->block;
|
||||||
device->block = NULL;
|
|
||||||
dasd_delete_device(device);
|
dasd_delete_device(device);
|
||||||
/*
|
/*
|
||||||
* life cycle of block is bound to device, so delete it after
|
* 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)
|
||||||
dasd_set_target_state(device, DASD_STATE_NEW);
|
dasd_set_target_state(device, DASD_STATE_NEW);
|
||||||
/* dasd_delete_device destroys the device reference. */
|
/* dasd_delete_device destroys the device reference. */
|
||||||
block = device->block;
|
block = device->block;
|
||||||
device->block = NULL;
|
|
||||||
dasd_delete_device(device);
|
dasd_delete_device(device);
|
||||||
/*
|
/*
|
||||||
* life cycle of block is bound to device, so delete it after
|
* life cycle of block is bound to device, so delete it after
|
||||||
|
|
|
@ -674,6 +674,36 @@ dasd_device_from_cdev(struct ccw_device *cdev)
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device)
|
||||||
|
{
|
||||||
|
struct dasd_devmap *devmap;
|
||||||
|
|
||||||
|
devmap = dasd_find_busid(dev_name(&device->cdev->dev));
|
||||||
|
if (IS_ERR(devmap))
|
||||||
|
return;
|
||||||
|
spin_lock(&dasd_devmap_lock);
|
||||||
|
gdp->private_data = devmap;
|
||||||
|
spin_unlock(&dasd_devmap_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp)
|
||||||
|
{
|
||||||
|
struct dasd_device *device;
|
||||||
|
struct dasd_devmap *devmap;
|
||||||
|
|
||||||
|
if (!gdp->private_data)
|
||||||
|
return NULL;
|
||||||
|
device = NULL;
|
||||||
|
spin_lock(&dasd_devmap_lock);
|
||||||
|
devmap = gdp->private_data;
|
||||||
|
if (devmap && devmap->device) {
|
||||||
|
device = devmap->device;
|
||||||
|
dasd_get_device(device);
|
||||||
|
}
|
||||||
|
spin_unlock(&dasd_devmap_lock);
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SECTION: files in sysfs
|
* SECTION: files in sysfs
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2037,7 +2037,7 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* summary unit check */
|
/* summary unit check */
|
||||||
if ((sense[7] == 0x0D) &&
|
if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) &&
|
||||||
(scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
|
(scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
|
||||||
dasd_alias_handle_summary_unit_check(device, irb);
|
dasd_alias_handle_summary_unit_check(device, irb);
|
||||||
return;
|
return;
|
||||||
|
@ -2053,7 +2053,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device,
|
||||||
/* loss of device reservation is handled via base devices only
|
/* loss of device reservation is handled via base devices only
|
||||||
* as alias devices may be used with several bases
|
* as alias devices may be used with several bases
|
||||||
*/
|
*/
|
||||||
if (device->block && (sense[7] == 0x3F) &&
|
if (device->block && (sense[27] & DASD_SENSE_BIT_0) &&
|
||||||
|
(sense[7] == 0x3F) &&
|
||||||
(scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
|
(scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
|
||||||
test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) {
|
test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) {
|
||||||
if (device->features & DASD_FEATURE_FAILONSLCK)
|
if (device->features & DASD_FEATURE_FAILONSLCK)
|
||||||
|
|
|
@ -73,7 +73,7 @@ int dasd_gendisk_alloc(struct dasd_block *block)
|
||||||
if (base->features & DASD_FEATURE_READONLY ||
|
if (base->features & DASD_FEATURE_READONLY ||
|
||||||
test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
|
test_bit(DASD_FLAG_DEVICE_RO, &base->flags))
|
||||||
set_disk_ro(gdp, 1);
|
set_disk_ro(gdp, 1);
|
||||||
gdp->private_data = block;
|
dasd_add_link_to_gendisk(gdp, base);
|
||||||
gdp->queue = block->request_queue;
|
gdp->queue = block->request_queue;
|
||||||
block->gdp = gdp;
|
block->gdp = gdp;
|
||||||
set_capacity(block->gdp, 0);
|
set_capacity(block->gdp, 0);
|
||||||
|
|
|
@ -686,6 +686,9 @@ struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
|
||||||
struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
|
struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
|
||||||
struct dasd_device *dasd_device_from_devindex(int);
|
struct dasd_device *dasd_device_from_devindex(int);
|
||||||
|
|
||||||
|
void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *);
|
||||||
|
struct dasd_device *dasd_device_from_gendisk(struct gendisk *);
|
||||||
|
|
||||||
int dasd_parse(void);
|
int dasd_parse(void);
|
||||||
int dasd_busid_known(const char *);
|
int dasd_busid_known(const char *);
|
||||||
|
|
||||||
|
|
|
@ -42,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp)
|
||||||
static int
|
static int
|
||||||
dasd_ioctl_enable(struct block_device *bdev)
|
dasd_ioctl_enable(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
struct dasd_device *base;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
dasd_enable_device(block->base);
|
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||||
|
if (!base)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
dasd_enable_device(base);
|
||||||
/* Formatting the dasd device can change the capacity. */
|
/* Formatting the dasd device can change the capacity. */
|
||||||
mutex_lock(&bdev->bd_mutex);
|
mutex_lock(&bdev->bd_mutex);
|
||||||
i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
|
i_size_write(bdev->bd_inode,
|
||||||
|
(loff_t)get_capacity(base->block->gdp) << 9);
|
||||||
mutex_unlock(&bdev->bd_mutex);
|
mutex_unlock(&bdev->bd_mutex);
|
||||||
|
dasd_put_device(base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev)
|
||||||
static int
|
static int
|
||||||
dasd_ioctl_disable(struct block_device *bdev)
|
dasd_ioctl_disable(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
struct dasd_device *base;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||||
|
if (!base)
|
||||||
|
return -ENODEV;
|
||||||
/*
|
/*
|
||||||
* Man this is sick. We don't do a real disable but only downgrade
|
* Man this is sick. We don't do a real disable but only downgrade
|
||||||
* the device to DASD_STATE_BASIC. The reason is that dasdfmt uses
|
* the device to DASD_STATE_BASIC. The reason is that dasdfmt uses
|
||||||
|
@ -75,7 +84,7 @@ dasd_ioctl_disable(struct block_device *bdev)
|
||||||
* using the BIODASDFMT ioctl. Therefore the correct state for the
|
* using the BIODASDFMT ioctl. Therefore the correct state for the
|
||||||
* device is DASD_STATE_BASIC that allows to do basic i/o.
|
* device is DASD_STATE_BASIC that allows to do basic i/o.
|
||||||
*/
|
*/
|
||||||
dasd_set_target_state(block->base, DASD_STATE_BASIC);
|
dasd_set_target_state(base, DASD_STATE_BASIC);
|
||||||
/*
|
/*
|
||||||
* Set i_size to zero, since read, write, etc. check against this
|
* Set i_size to zero, since read, write, etc. check against this
|
||||||
* value.
|
* value.
|
||||||
|
@ -83,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev)
|
||||||
mutex_lock(&bdev->bd_mutex);
|
mutex_lock(&bdev->bd_mutex);
|
||||||
i_size_write(bdev->bd_inode, 0);
|
i_size_write(bdev->bd_inode, 0);
|
||||||
mutex_unlock(&bdev->bd_mutex);
|
mutex_unlock(&bdev->bd_mutex);
|
||||||
|
dasd_put_device(base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
|
||||||
static int
|
static int
|
||||||
dasd_ioctl_format(struct block_device *bdev, void __user *argp)
|
dasd_ioctl_format(struct block_device *bdev, void __user *argp)
|
||||||
{
|
{
|
||||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
struct dasd_device *base;
|
||||||
struct format_data_t fdata;
|
struct format_data_t fdata;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
if (!argp)
|
if (!argp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||||
if (block->base->features & DASD_FEATURE_READONLY ||
|
if (!base)
|
||||||
test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
|
return -ENODEV;
|
||||||
|
if (base->features & DASD_FEATURE_READONLY ||
|
||||||
|
test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
|
||||||
|
dasd_put_device(base);
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
|
}
|
||||||
|
if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) {
|
||||||
|
dasd_put_device(base);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
}
|
||||||
if (bdev != bdev->bd_contains) {
|
if (bdev != bdev->bd_contains) {
|
||||||
pr_warning("%s: The specified DASD is a partition and cannot "
|
pr_warning("%s: The specified DASD is a partition and cannot "
|
||||||
"be formatted\n",
|
"be formatted\n",
|
||||||
dev_name(&block->base->cdev->dev));
|
dev_name(&base->cdev->dev));
|
||||||
|
dasd_put_device(base);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return dasd_format(block, &fdata);
|
rc = dasd_format(base->block, &fdata);
|
||||||
|
dasd_put_device(base);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DASD_PROFILE
|
#ifdef CONFIG_DASD_PROFILE
|
||||||
|
@ -340,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block,
|
||||||
static int
|
static int
|
||||||
dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
|
dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
|
||||||
{
|
{
|
||||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
struct dasd_device *base;
|
||||||
int intval;
|
int intval, rc;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
@ -350,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (get_user(intval, (int __user *)argp))
|
if (get_user(intval, (int __user *)argp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
|
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||||
|
if (!base)
|
||||||
|
return -ENODEV;
|
||||||
|
if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
|
||||||
|
dasd_put_device(base);
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
|
}
|
||||||
set_disk_ro(bdev->bd_disk, intval);
|
set_disk_ro(bdev->bd_disk, intval);
|
||||||
return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
|
rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval);
|
||||||
|
dasd_put_device(base);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
|
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,
|
||||||
int dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
int dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
struct dasd_block *block;
|
||||||
|
struct dasd_device *base;
|
||||||
void __user *argp;
|
void __user *argp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (is_compat_task())
|
if (is_compat_task())
|
||||||
argp = compat_ptr(arg);
|
argp = compat_ptr(arg);
|
||||||
else
|
else
|
||||||
argp = (void __user *)arg;
|
argp = (void __user *)arg;
|
||||||
|
|
||||||
if (!block)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
|
if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
|
||||||
PRINT_DEBUG("empty data ptr");
|
PRINT_DEBUG("empty data ptr");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||||
|
if (!base)
|
||||||
|
return -ENODEV;
|
||||||
|
block = base->block;
|
||||||
|
rc = 0;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case BIODASDDISABLE:
|
case BIODASDDISABLE:
|
||||||
return dasd_ioctl_disable(bdev);
|
rc = dasd_ioctl_disable(bdev);
|
||||||
|
break;
|
||||||
case BIODASDENABLE:
|
case BIODASDENABLE:
|
||||||
return dasd_ioctl_enable(bdev);
|
rc = dasd_ioctl_enable(bdev);
|
||||||
|
break;
|
||||||
case BIODASDQUIESCE:
|
case BIODASDQUIESCE:
|
||||||
return dasd_ioctl_quiesce(block);
|
rc = dasd_ioctl_quiesce(block);
|
||||||
|
break;
|
||||||
case BIODASDRESUME:
|
case BIODASDRESUME:
|
||||||
return dasd_ioctl_resume(block);
|
rc = dasd_ioctl_resume(block);
|
||||||
|
break;
|
||||||
case BIODASDFMT:
|
case BIODASDFMT:
|
||||||
return dasd_ioctl_format(bdev, argp);
|
rc = dasd_ioctl_format(bdev, argp);
|
||||||
|
break;
|
||||||
case BIODASDINFO:
|
case BIODASDINFO:
|
||||||
return dasd_ioctl_information(block, cmd, argp);
|
rc = dasd_ioctl_information(block, cmd, argp);
|
||||||
|
break;
|
||||||
case BIODASDINFO2:
|
case BIODASDINFO2:
|
||||||
return dasd_ioctl_information(block, cmd, argp);
|
rc = dasd_ioctl_information(block, cmd, argp);
|
||||||
|
break;
|
||||||
case BIODASDPRRD:
|
case BIODASDPRRD:
|
||||||
return dasd_ioctl_read_profile(block, argp);
|
rc = dasd_ioctl_read_profile(block, argp);
|
||||||
|
break;
|
||||||
case BIODASDPRRST:
|
case BIODASDPRRST:
|
||||||
return dasd_ioctl_reset_profile(block);
|
rc = dasd_ioctl_reset_profile(block);
|
||||||
|
break;
|
||||||
case BLKROSET:
|
case BLKROSET:
|
||||||
return dasd_ioctl_set_ro(bdev, argp);
|
rc = dasd_ioctl_set_ro(bdev, argp);
|
||||||
|
break;
|
||||||
case DASDAPIVER:
|
case DASDAPIVER:
|
||||||
return dasd_ioctl_api_version(argp);
|
rc = dasd_ioctl_api_version(argp);
|
||||||
|
break;
|
||||||
case BIODASDCMFENABLE:
|
case BIODASDCMFENABLE:
|
||||||
return enable_cmf(block->base->cdev);
|
rc = enable_cmf(base->cdev);
|
||||||
|
break;
|
||||||
case BIODASDCMFDISABLE:
|
case BIODASDCMFDISABLE:
|
||||||
return disable_cmf(block->base->cdev);
|
rc = disable_cmf(base->cdev);
|
||||||
|
break;
|
||||||
case BIODASDREADALLCMB:
|
case BIODASDREADALLCMB:
|
||||||
return dasd_ioctl_readall_cmb(block, cmd, argp);
|
rc = dasd_ioctl_readall_cmb(block, cmd, argp);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* if the discipline has an ioctl method try it. */
|
/* if the discipline has an ioctl method try it. */
|
||||||
if (block->base->discipline->ioctl) {
|
if (base->discipline->ioctl) {
|
||||||
int rval = block->base->discipline->ioctl(block, cmd, argp);
|
rc = base->discipline->ioctl(block, cmd, argp);
|
||||||
if (rval != -ENOIOCTLCMD)
|
if (rc == -ENOIOCTLCMD)
|
||||||
return rval;
|
rc = -EINVAL;
|
||||||
}
|
} else
|
||||||
|
rc = -EINVAL;
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
dasd_put_device(base);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,8 +407,11 @@ static inline void account_sbals(struct qdio_q *q, int count)
|
||||||
q->q_stats.nr_sbals[pos]++;
|
q->q_stats.nr_sbals[pos]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void announce_buffer_error(struct qdio_q *q, int count)
|
static void process_buffer_error(struct qdio_q *q, int count)
|
||||||
{
|
{
|
||||||
|
unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT :
|
||||||
|
SLSB_P_OUTPUT_NOT_INIT;
|
||||||
|
|
||||||
q->qdio_error |= QDIO_ERROR_SLSB_STATE;
|
q->qdio_error |= QDIO_ERROR_SLSB_STATE;
|
||||||
|
|
||||||
/* special handling for no target buffer empty */
|
/* special handling for no target buffer empty */
|
||||||
|
@ -426,6 +429,12 @@ static void announce_buffer_error(struct qdio_q *q, int count)
|
||||||
DBF_ERROR("F14:%2x F15:%2x",
|
DBF_ERROR("F14:%2x F15:%2x",
|
||||||
q->sbal[q->first_to_check]->element[14].flags & 0xff,
|
q->sbal[q->first_to_check]->element[14].flags & 0xff,
|
||||||
q->sbal[q->first_to_check]->element[15].flags & 0xff);
|
q->sbal[q->first_to_check]->element[15].flags & 0xff);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupts may be avoided as long as the error is present
|
||||||
|
* so change the buffer state immediately to avoid starvation.
|
||||||
|
*/
|
||||||
|
set_buf_states(q, q->first_to_check, state, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void inbound_primed(struct qdio_q *q, int count)
|
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)
|
||||||
account_sbals(q, count);
|
account_sbals(q, count);
|
||||||
break;
|
break;
|
||||||
case SLSB_P_INPUT_ERROR:
|
case SLSB_P_INPUT_ERROR:
|
||||||
announce_buffer_error(q, count);
|
process_buffer_error(q, count);
|
||||||
/* process the buffer, the upper layer will take care of it */
|
|
||||||
q->first_to_check = add_buf(q->first_to_check, count);
|
q->first_to_check = add_buf(q->first_to_check, count);
|
||||||
atomic_sub(count, &q->nr_buf_used);
|
atomic_sub(count, &q->nr_buf_used);
|
||||||
if (q->irq_ptr->perf_stat_enabled)
|
if (q->irq_ptr->perf_stat_enabled)
|
||||||
|
@ -677,8 +685,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
|
||||||
account_sbals(q, count);
|
account_sbals(q, count);
|
||||||
break;
|
break;
|
||||||
case SLSB_P_OUTPUT_ERROR:
|
case SLSB_P_OUTPUT_ERROR:
|
||||||
announce_buffer_error(q, count);
|
process_buffer_error(q, count);
|
||||||
/* process the buffer, the upper layer will take care of it */
|
|
||||||
q->first_to_check = add_buf(q->first_to_check, count);
|
q->first_to_check = add_buf(q->first_to_check, count);
|
||||||
atomic_sub(count, &q->nr_buf_used);
|
atomic_sub(count, &q->nr_buf_used);
|
||||||
if (q->irq_ptr->perf_stat_enabled)
|
if (q->irq_ptr->perf_stat_enabled)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче