|
@@ -42,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp)
|
|
|
static int
|
|
|
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))
|
|
|
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. */
|
|
|
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);
|
|
|
+ dasd_put_device(base);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -62,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev)
|
|
|
static int
|
|
|
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))
|
|
|
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
|
|
|
* 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
|
|
|
* 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
|
|
|
* value.
|
|
@@ -83,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev)
|
|
|
mutex_lock(&bdev->bd_mutex);
|
|
|
i_size_write(bdev->bd_inode, 0);
|
|
|
mutex_unlock(&bdev->bd_mutex);
|
|
|
+ dasd_put_device(base);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -191,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
|
|
|
static int
|
|
|
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;
|
|
|
+ int rc;
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
return -EACCES;
|
|
|
if (!argp)
|
|
|
return -EINVAL;
|
|
|
-
|
|
|
- if (block->base->features & DASD_FEATURE_READONLY ||
|
|
|
- test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags))
|
|
|
+ base = dasd_device_from_gendisk(bdev->bd_disk);
|
|
|
+ if (!base)
|
|
|
+ return -ENODEV;
|
|
|
+ if (base->features & DASD_FEATURE_READONLY ||
|
|
|
+ test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) {
|
|
|
+ dasd_put_device(base);
|
|
|
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;
|
|
|
+ }
|
|
|
if (bdev != bdev->bd_contains) {
|
|
|
pr_warning("%s: The specified DASD is a partition and cannot "
|
|
|
"be formatted\n",
|
|
|
- dev_name(&block->base->cdev->dev));
|
|
|
+ dev_name(&base->cdev->dev));
|
|
|
+ dasd_put_device(base);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- return dasd_format(block, &fdata);
|
|
|
+ rc = dasd_format(base->block, &fdata);
|
|
|
+ dasd_put_device(base);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_DASD_PROFILE
|
|
@@ -340,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block,
|
|
|
static int
|
|
|
dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
|
|
|
{
|
|
|
- struct dasd_block *block = bdev->bd_disk->private_data;
|
|
|
- int intval;
|
|
|
+ struct dasd_device *base;
|
|
|
+ int intval, rc;
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
return -EACCES;
|
|
@@ -350,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
|
|
|
return -EINVAL;
|
|
|
if (get_user(intval, (int __user *)argp))
|
|
|
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;
|
|
|
+ }
|
|
|
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,
|
|
@@ -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,
|
|
|
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;
|
|
|
+ int rc;
|
|
|
|
|
|
if (is_compat_task())
|
|
|
argp = compat_ptr(arg);
|
|
|
else
|
|
|
argp = (void __user *)arg;
|
|
|
|
|
|
- if (!block)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
|
|
|
PRINT_DEBUG("empty data ptr");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ base = dasd_device_from_gendisk(bdev->bd_disk);
|
|
|
+ if (!base)
|
|
|
+ return -ENODEV;
|
|
|
+ block = base->block;
|
|
|
+ rc = 0;
|
|
|
switch (cmd) {
|
|
|
case BIODASDDISABLE:
|
|
|
- return dasd_ioctl_disable(bdev);
|
|
|
+ rc = dasd_ioctl_disable(bdev);
|
|
|
+ break;
|
|
|
case BIODASDENABLE:
|
|
|
- return dasd_ioctl_enable(bdev);
|
|
|
+ rc = dasd_ioctl_enable(bdev);
|
|
|
+ break;
|
|
|
case BIODASDQUIESCE:
|
|
|
- return dasd_ioctl_quiesce(block);
|
|
|
+ rc = dasd_ioctl_quiesce(block);
|
|
|
+ break;
|
|
|
case BIODASDRESUME:
|
|
|
- return dasd_ioctl_resume(block);
|
|
|
+ rc = dasd_ioctl_resume(block);
|
|
|
+ break;
|
|
|
case BIODASDFMT:
|
|
|
- return dasd_ioctl_format(bdev, argp);
|
|
|
+ rc = dasd_ioctl_format(bdev, argp);
|
|
|
+ break;
|
|
|
case BIODASDINFO:
|
|
|
- return dasd_ioctl_information(block, cmd, argp);
|
|
|
+ rc = dasd_ioctl_information(block, cmd, argp);
|
|
|
+ break;
|
|
|
case BIODASDINFO2:
|
|
|
- return dasd_ioctl_information(block, cmd, argp);
|
|
|
+ rc = dasd_ioctl_information(block, cmd, argp);
|
|
|
+ break;
|
|
|
case BIODASDPRRD:
|
|
|
- return dasd_ioctl_read_profile(block, argp);
|
|
|
+ rc = dasd_ioctl_read_profile(block, argp);
|
|
|
+ break;
|
|
|
case BIODASDPRRST:
|
|
|
- return dasd_ioctl_reset_profile(block);
|
|
|
+ rc = dasd_ioctl_reset_profile(block);
|
|
|
+ break;
|
|
|
case BLKROSET:
|
|
|
- return dasd_ioctl_set_ro(bdev, argp);
|
|
|
+ rc = dasd_ioctl_set_ro(bdev, argp);
|
|
|
+ break;
|
|
|
case DASDAPIVER:
|
|
|
- return dasd_ioctl_api_version(argp);
|
|
|
+ rc = dasd_ioctl_api_version(argp);
|
|
|
+ break;
|
|
|
case BIODASDCMFENABLE:
|
|
|
- return enable_cmf(block->base->cdev);
|
|
|
+ rc = enable_cmf(base->cdev);
|
|
|
+ break;
|
|
|
case BIODASDCMFDISABLE:
|
|
|
- return disable_cmf(block->base->cdev);
|
|
|
+ rc = disable_cmf(base->cdev);
|
|
|
+ break;
|
|
|
case BIODASDREADALLCMB:
|
|
|
- return dasd_ioctl_readall_cmb(block, cmd, argp);
|
|
|
+ rc = dasd_ioctl_readall_cmb(block, cmd, argp);
|
|
|
+ break;
|
|
|
default:
|
|
|
/* if the discipline has an ioctl method try it. */
|
|
|
- if (block->base->discipline->ioctl) {
|
|
|
- int rval = block->base->discipline->ioctl(block, cmd, argp);
|
|
|
- if (rval != -ENOIOCTLCMD)
|
|
|
- return rval;
|
|
|
- }
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
+ if (base->discipline->ioctl) {
|
|
|
+ rc = base->discipline->ioctl(block, cmd, argp);
|
|
|
+ if (rc == -ENOIOCTLCMD)
|
|
|
+ rc = -EINVAL;
|
|
|
+ } else
|
|
|
+ rc = -EINVAL;
|
|
|
}
|
|
|
+ dasd_put_device(base);
|
|
|
+ return rc;
|
|
|
}
|