[PATCH 1/1] s390/dasd: remove ioctl_by_bdev from DASD driver

From: Stefan Haberland
Date: Thu Apr 30 2020 - 07:18:08 EST


Remove the calls to ioctl_by_bdev from the DASD partition detection code
to enable the removal of the specific code.

To do so reuse the gendisk private_data pointer and not only provide a
pointer to the devmap but provide a new structure containing a pointer
to the devmap as well as all required information for the partition
detection. This makes it independent from the dasd_information2_t
structure.

Suggested-by: Christoph Hellwig <hch@xxxxxx>
Signed-off-by: Stefan Haberland <sth@xxxxxxxxxxxxx>
Reviewed-by: Jan Hoeppner <hoeppner@xxxxxxxxxxxxx>
---
block/partitions/ibm.c | 67 ++++++++++++++++++--------------
drivers/s390/block/dasd_devmap.c | 17 +++++++-
drivers/s390/block/dasd_diag.c | 10 +++++
drivers/s390/block/dasd_eckd.c | 10 +++++
drivers/s390/block/dasd_fba.c | 8 ++++
drivers/s390/block/dasd_genhd.c | 1 +
drivers/s390/block/dasd_int.h | 10 +++++
7 files changed, 91 insertions(+), 32 deletions(-)

diff --git a/block/partitions/ibm.c b/block/partitions/ibm.c
index 073faa6a69b8..da72a990418d 100644
--- a/block/partitions/ibm.c
+++ b/block/partitions/ibm.c
@@ -23,6 +23,15 @@ union label_t {
struct vtoc_cms_label cms;
};

+struct dasd_gd_private {
+ void *devmap;
+ unsigned int cu_type;
+ unsigned int dev_type;
+ unsigned int label_block;
+ unsigned int format;
+ char type[4];
+};
+
/*
* compute the block number from a
* cyl-cyl-head-head structure
@@ -61,7 +70,7 @@ static sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo)
}

static int find_label(struct parsed_partitions *state,
- dasd_information2_t *info,
+ struct dasd_gd_private *gd_priv,
struct hd_geometry *geo,
int blocksize,
sector_t *labelsect,
@@ -81,15 +90,16 @@ static int find_label(struct parsed_partitions *state,
* - on an FBA disk it's block 1
* - on an CMS formatted FBA disk it is sector 1, even if the block size
* is larger than 512 bytes (possible if the DIAG discipline is used)
- * If we have a valid info structure, then we know exactly which case we
- * have, otherwise we just search through all possebilities.
+ * If we have a valid dasd_gd_private structure, then we know exactly
+ * which case we have, otherwise we just search through all
+ * possibilities.
*/
- if (info) {
- if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
- (info->cu_type == 0x3880 && info->dev_type == 0x3370))
- testsect[0] = info->label_block;
+ if (gd_priv) {
+ if ((gd_priv->cu_type == 0x6310 && gd_priv->dev_type == 0x9336) ||
+ (gd_priv->cu_type == 0x3880 && gd_priv->dev_type == 0x3370))
+ testsect[0] = gd_priv->label_block;
else
- testsect[0] = info->label_block * (blocksize >> 9);
+ testsect[0] = gd_priv->label_block * (blocksize >> 9);
testcount = 1;
} else {
testsect[0] = 1;
@@ -198,7 +208,7 @@ static int find_lnx1_partitions(struct parsed_partitions *state,
union label_t *label,
sector_t labelsect,
loff_t i_size,
- dasd_information2_t *info)
+ struct dasd_gd_private *gd_priv)
{
loff_t offset, geo_size, size;
char tmp[64];
@@ -221,11 +231,11 @@ static int find_lnx1_partitions(struct parsed_partitions *state,
* geo->sectors * secperblk;
size = i_size >> 9;
if (size != geo_size) {
- if (!info) {
+ if (!gd_priv) {
strlcat(state->pp_buf, "\n", PAGE_SIZE);
return 1;
}
- if (!strcmp(info->type, "ECKD"))
+ if (!strcmp(gd_priv->type, "ECKD"))
if (geo_size < size)
size = geo_size;
/* else keep size based on i_size */
@@ -289,9 +299,10 @@ static int find_cms1_partitions(struct parsed_partitions *state,
int ibm_partition(struct parsed_partitions *state)
{
struct block_device *bdev = state->bdev;
+ struct dasd_gd_private *gd_priv = NULL;
+ struct gendisk *disk = bdev->bd_disk;
int blocksize, res;
loff_t i_size, offset, size;
- dasd_information2_t *info;
struct hd_geometry *geo;
char type[5] = {0,};
char name[7] = {0,};
@@ -305,23 +316,21 @@ int ibm_partition(struct parsed_partitions *state)
i_size = i_size_read(bdev->bd_inode);
if (i_size == 0)
goto out_exit;
- info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
- if (info == NULL)
- goto out_exit;
- geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
+ geo = kzalloc(sizeof(struct hd_geometry), GFP_KERNEL);
if (geo == NULL)
- goto out_nogeo;
+ goto out_exit;
label = kmalloc(sizeof(union label_t), GFP_KERNEL);
if (label == NULL)
goto out_nolab;
- if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
+ geo->start = get_start_sect(bdev);
+ if (!disk->fops->getgeo || disk->fops->getgeo(bdev, geo))
goto out_freeall;
- if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0) {
- kfree(info);
- info = NULL;
- }

- if (find_label(state, info, geo, blocksize, &labelsect, name, type,
+ /* gd_priv pointer is only valid for DASD devices */
+ if (disk && disk->major == DASD_MAJOR)
+ gd_priv = disk->private_data;
+
+ if (find_label(state, gd_priv, geo, blocksize, &labelsect, name, type,
label)) {
if (!strncmp(type, "VOL1", 4)) {
res = find_vol1_partitions(state, geo, blocksize, name,
@@ -329,24 +338,24 @@ int ibm_partition(struct parsed_partitions *state)
} else if (!strncmp(type, "LNX1", 4)) {
res = find_lnx1_partitions(state, geo, blocksize, name,
label, labelsect, i_size,
- info);
+ gd_priv);
} else if (!strncmp(type, "CMS1", 4)) {
res = find_cms1_partitions(state, geo, blocksize, name,
label, labelsect);
}
- } else if (info) {
+ } else if (gd_priv) {
/*
* ugly but needed for backward compatibility:
- * If the block device is a DASD (i.e. BIODASDINFO2 works),
+ * If the block device is a DASD (i.e. valid gd_priv),
* then we claim it in any case, even though it has no valid
* label. If it has the LDL format, then we simply define a
* partition as if it had an LNX1 label.
*/
res = 1;
- if (info->format == DASD_FORMAT_LDL) {
+ if (gd_priv->format == DASD_FORMAT_LDL) {
strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
size = i_size >> 9;
- offset = (info->label_block + 1) * (blocksize >> 9);
+ offset = (gd_priv->label_block + 1) * (blocksize >> 9);
put_partition(state, 1, offset, size-offset);
strlcat(state->pp_buf, "\n", PAGE_SIZE);
}
@@ -357,8 +366,6 @@ int ibm_partition(struct parsed_partitions *state)
kfree(label);
out_nolab:
kfree(geo);
-out_nogeo:
- kfree(info);
out_exit:
return res;
}
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 32fc51341d99..63e48bf9cadc 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -677,18 +677,30 @@ dasd_device_from_cdev(struct ccw_device *cdev)

void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device)
{
+ struct dasd_gd_private *gd_priv;
struct dasd_devmap *devmap;
+ struct ccw_device *cdev;

+ gd_priv = kzalloc(sizeof(struct dasd_gd_private), GFP_KERNEL);
+ if (!gd_priv)
+ return;
devmap = dasd_find_busid(dev_name(&device->cdev->dev));
if (IS_ERR(devmap))
return;
+ cdev = device->cdev;
spin_lock(&dasd_devmap_lock);
- gdp->private_data = devmap;
+ gd_priv->devmap = devmap;
+ gd_priv->cu_type = cdev->id.cu_type;
+ gd_priv->dev_type = cdev->id.dev_type;
+ memcpy(gd_priv->type, device->discipline->name, sizeof(gd_priv->type));
+ device->discipline->fill_gd_priv(gd_priv, device);
+ gdp->private_data = gd_priv;
spin_unlock(&dasd_devmap_lock);
}

struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp)
{
+ struct dasd_gd_private *gd_priv;
struct dasd_device *device;
struct dasd_devmap *devmap;

@@ -696,7 +708,8 @@ struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp)
return NULL;
device = NULL;
spin_lock(&dasd_devmap_lock);
- devmap = gdp->private_data;
+ gd_priv = gdp->private_data;
+ devmap = gd_priv->devmap;
if (devmap && devmap->device) {
device = devmap->device;
dasd_get_device(device);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index facb588d09e4..38d20744df26 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -607,6 +607,15 @@ dasd_diag_fill_info(struct dasd_device * device,
return 0;
}

+static void dasd_diag_fill_gd_priv(struct dasd_gd_private *gd_priv,
+ struct dasd_device *device)
+{
+ struct dasd_diag_private *private = device->private;
+
+ gd_priv->label_block = (unsigned int) private->pt_block;
+ gd_priv->format = DASD_FORMAT_LDL;
+}
+
static void
dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
struct irb *stat)
@@ -652,6 +661,7 @@ static struct dasd_discipline dasd_diag_discipline = {
.free_cp = dasd_diag_free_cp,
.dump_sense = dasd_diag_dump_sense,
.fill_info = dasd_diag_fill_info,
+ .fill_gd_priv = dasd_diag_fill_gd_priv,
};

static int __init
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index ad44d22e8859..edaa7d1577a9 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -4901,6 +4901,15 @@ dasd_eckd_fill_info(struct dasd_device * device,
return 0;
}

+static void dasd_eckd_fill_gd_priv(struct dasd_gd_private *gd_priv,
+ struct dasd_device *device)
+{
+ struct dasd_eckd_private *private = device->private;
+
+ gd_priv->label_block = 2;
+ gd_priv->format = private->uses_cdl ? DASD_FORMAT_CDL : DASD_FORMAT_LDL;
+}
+
/*
* SECTION: ioctl functions for eckd devices.
*/
@@ -6727,6 +6736,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
.ext_pool_exhaust = dasd_eckd_ext_pool_exhaust,
.ese_format = dasd_eckd_ese_format,
.ese_read = dasd_eckd_ese_read,
+ .fill_gd_priv = dasd_eckd_fill_gd_priv,
};

static int __init
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index cbb770824226..6abbffdffb5f 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -642,6 +642,13 @@ dasd_fba_fill_info(struct dasd_device * device,
return 0;
}

+static void dasd_fba_fill_gd_priv(struct dasd_gd_private *gd_priv,
+ struct dasd_device *device)
+{
+ gd_priv->label_block = 1;
+ gd_priv->format = DASD_FORMAT_LDL;
+}
+
static void
dasd_fba_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
char *reason)
@@ -822,6 +829,7 @@ static struct dasd_discipline dasd_fba_discipline = {
.dump_sense = dasd_fba_dump_sense,
.dump_sense_dbf = dasd_fba_dump_sense_dbf,
.fill_info = dasd_fba_fill_info,
+ .fill_gd_priv = dasd_fba_fill_gd_priv,
};

static int __init
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index af5b0ecb8f89..d6ef85936526 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -87,6 +87,7 @@ void dasd_gendisk_free(struct dasd_block *block)
{
if (block->gdp) {
del_gendisk(block->gdp);
+ kfree(block->gdp->private_data);
block->gdp->private_data = NULL;
put_disk(block->gdp);
block->gdp = NULL;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index fa552f9f1666..31d12a62b28b 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -259,6 +259,15 @@ struct dasd_uid {
char vduit[33];
};

+struct dasd_gd_private {
+ struct dasd_devmap *devmap;
+ unsigned int cu_type;
+ unsigned int dev_type;
+ unsigned int label_block;
+ unsigned int format;
+ char type[4];
+};
+
/*
* the struct dasd_discipline is
* sth like a table of virtual functions, if you think of dasd_eckd
@@ -391,6 +400,7 @@ struct dasd_discipline {
struct dasd_ccw_req *(*ese_format)(struct dasd_device *,
struct dasd_ccw_req *, struct irb *);
int (*ese_read)(struct dasd_ccw_req *, struct irb *);
+ void (*fill_gd_priv)(struct dasd_gd_private *, struct dasd_device *);
};

extern struct dasd_discipline *dasd_diag_discipline_pointer;
--
2.17.1