[patch 05/10] s390: add missing validation for dasd discipline specific ioctls

From: Heiko Carstens
Date: Wed Feb 08 2006 - 07:35:21 EST


From: Horst Hummel <horst.hummel@xxxxxxxxxx>

Because of missing discipline validition dasd ioctls calls may not return
when called on a device handled by a different discipline.
(e.g calling ECKD specific BIODASDGATTR on an FBA device).
This addresses one of the issues Christoph has with the dasd driver.

Signed-off-by: Horst Hummel <horst.hummel@xxxxxxxxxx>
Signed-off-by: Heiko Carstens <heiko.carstens@xxxxxxxxxx>
---

drivers/s390/block/dasd.c | 8 ++++-
drivers/s390/block/dasd_eckd.c | 59 ++++++++++++++++++++++++++++-------------
drivers/s390/block/dasd_eer.c | 39 +++++++++++++++++++++------
3 files changed, 78 insertions(+), 28 deletions(-)

diff -urpN linux-2.6/drivers/s390/block/dasd.c linux-2.6-patched/drivers/s390/block/dasd.c
--- linux-2.6/drivers/s390/block/dasd.c 2006-02-08 10:48:22.000000000 +0100
+++ linux-2.6-patched/drivers/s390/block/dasd.c 2006-02-08 10:48:45.000000000 +0100
@@ -670,8 +670,10 @@ dasd_term_IO(struct dasd_ccw_req * cqr)

/* Check the cqr */
rc = dasd_check_cqr(cqr);
- if (rc)
+ if (rc) {
+ cqr->status = DASD_CQR_FAILED;
return rc;
+ }
retries = 0;
device = (struct dasd_device *) cqr->device;
while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
@@ -724,8 +726,10 @@ dasd_start_IO(struct dasd_ccw_req * cqr)

/* Check the cqr */
rc = dasd_check_cqr(cqr);
- if (rc)
+ if (rc) {
+ cqr->status = DASD_CQR_FAILED;
return rc;
+ }
device = (struct dasd_device *) cqr->device;
if (cqr->retries < 0) {
DEV_MESSAGE(KERN_DEBUG, device,
diff -urpN linux-2.6/drivers/s390/block/dasd_eckd.c linux-2.6-patched/drivers/s390/block/dasd_eckd.c
--- linux-2.6/drivers/s390/block/dasd_eckd.c 2006-02-08 10:48:22.000000000 +0100
+++ linux-2.6-patched/drivers/s390/block/dasd_eckd.c 2006-02-08 10:48:45.000000000 +0100
@@ -224,6 +224,28 @@ check_XRC (struct ccw1 *de_ccw,

} /* end check_XRC */

+/*
+ * Check if called ioctl is valid on this device type.
+ * Returns device if anything is fine, ERR_PTR otherwise.
+ */
+static inline struct dasd_device *
+dasd_eckd_validate_ioctl(struct block_device *bdev, int no)
+{
+ struct dasd_device *device;
+
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return ERR_PTR(-ENODEV);
+
+ if (strncmp((char *)&device->discipline->name, "ECKD", 4)) {
+ DEV_MESSAGE(KERN_WARNING, device,
+ "ioctl (%x) not supported for %.4s device.",
+ no, (char *)&device->discipline->name);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+ return device;
+}
+
static inline void
define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
int totrk, int cmd, struct dasd_device * device)
@@ -1236,9 +1258,9 @@ dasd_eckd_release(struct block_device *b
if (!capable(CAP_SYS_ADMIN))
return -EACCES;

- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+ device = dasd_eckd_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);

cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 32, device);
@@ -1281,9 +1303,9 @@ dasd_eckd_reserve(struct block_device *b
if (!capable(CAP_SYS_ADMIN))
return -EACCES;

- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+ device = dasd_eckd_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);

cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 32, device);
@@ -1325,9 +1347,9 @@ dasd_eckd_steal_lock(struct block_device
if (!capable(CAP_SYS_ADMIN))
return -EACCES;

- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+ device = dasd_eckd_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);

cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 32, device);
@@ -1367,9 +1389,9 @@ dasd_eckd_performance(struct block_devic
struct ccw1 *ccw;
int rc;

- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+ device = dasd_eckd_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);

cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1 /* PSF */ + 1 /* RSSD */ ,
@@ -1438,9 +1460,9 @@ dasd_eckd_get_attrib (struct block_devic
if (!args)
return -EINVAL;

- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+ device = dasd_eckd_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);

private = (struct dasd_eckd_private *) device->private;
attrib = private->attrib;
@@ -1467,9 +1489,10 @@ dasd_eckd_set_attrib(struct block_device
if (!args)
return -EINVAL;

- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+
+ device = dasd_eckd_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);

if (copy_from_user(&attrib, (void __user *) args,
sizeof (struct attrib_data_t))) {
diff -urpN linux-2.6/drivers/s390/block/dasd_eer.c linux-2.6-patched/drivers/s390/block/dasd_eer.c
--- linux-2.6/drivers/s390/block/dasd_eer.c 2006-02-08 10:48:22.000000000 +0100
+++ linux-2.6-patched/drivers/s390/block/dasd_eer.c 2006-02-08 10:48:45.000000000 +0100
@@ -109,6 +109,28 @@ static spinlock_t bufferlock = SPIN_LOCK
DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);

/*
+ * Check if called ioctl is valid on this device type.
+ * Returns device if anything is fine, ERR_PTR otherwise.
+ */
+static inline struct dasd_device *
+dasd_eer_validate_ioctl(struct block_device *bdev, int no)
+{
+ struct dasd_device *device;
+
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return ERR_PTR(-ENODEV);
+
+ if (strncmp((char *)&device->discipline->name, "ECKD", 4)) {
+ DEV_MESSAGE(KERN_WARNING, device,
+ "ioctl (%x) not supported for %.4s device.",
+ no, (char *)&device->discipline->name);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+ return device;
+}
+
+/*
* How many free bytes are available on the buffer.
* needs to be called with bufferlock held
*/
@@ -523,8 +545,7 @@ static int
dasd_eer_enable_on_device(struct dasd_device *device)
{
void *eer;
- if (!device)
- return -ENODEV;
+
if (device->eer)
return 0;
if (!try_module_get(THIS_MODULE)) {
@@ -575,9 +596,10 @@ dasd_ioctl_set_eer(struct block_device *
return -EINVAL;
if (get_user(intval, (int __user *) args))
return -EFAULT;
- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+
+ device = dasd_eer_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);

intval = (intval != 0);
DEV_MESSAGE (KERN_DEBUG, device,
@@ -597,9 +619,10 @@ dasd_ioctl_get_eer(struct block_device *
{
struct dasd_device *device;

- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
+ device = dasd_eer_validate_ioctl(bdev, no);
+ if (IS_ERR(device))
+ return PTR_ERR(device);
+
return put_user((device->eer != NULL), (int __user *) args);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/