[PATCH] s390: dasd partition detection
DASD allows to open a device as soon as gendisk is registered, which means the device is a fake device (capacity=0) and we do know nothing about blocksize and partitions at that point of time. In case the device is opened by someone, the bdev and inode creation is done with the fake device info and the following partition detection code is just using the wrong data. To avoid this modify the DASD state machine to make sure that the open is rejected until the device analysis is either finished or an unformatted device was detected. Signed-off-by: Horst Hummel <horst.hummel@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
fbcae7eafc
commit
90f0094dc6
|
@ -215,9 +215,10 @@ dasd_state_basic_to_known(struct dasd_device * device)
|
||||||
* interrupt for this detection ccw uses the kernel event daemon to
|
* interrupt for this detection ccw uses the kernel event daemon to
|
||||||
* trigger the call to dasd_change_state. All this is done in the
|
* trigger the call to dasd_change_state. All this is done in the
|
||||||
* discipline code, see dasd_eckd.c.
|
* discipline code, see dasd_eckd.c.
|
||||||
* After the analysis ccw is done (do_analysis returned 0 or error)
|
* After the analysis ccw is done (do_analysis returned 0) the block
|
||||||
* the block device is setup. Either a fake disk is added to allow
|
* device is setup.
|
||||||
* formatting or a proper device request queue is created.
|
* In case the analysis returns an error, the device setup is stopped
|
||||||
|
* (a fake disk was already added to allow formatting).
|
||||||
*/
|
*/
|
||||||
static inline int
|
static inline int
|
||||||
dasd_state_basic_to_ready(struct dasd_device * device)
|
dasd_state_basic_to_ready(struct dasd_device * device)
|
||||||
|
@ -227,13 +228,19 @@ dasd_state_basic_to_ready(struct dasd_device * device)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if (device->discipline->do_analysis != NULL)
|
if (device->discipline->do_analysis != NULL)
|
||||||
rc = device->discipline->do_analysis(device);
|
rc = device->discipline->do_analysis(device);
|
||||||
if (rc)
|
if (rc) {
|
||||||
|
if (rc != -EAGAIN)
|
||||||
|
device->state = DASD_STATE_UNFMT;
|
||||||
return rc;
|
return rc;
|
||||||
|
}
|
||||||
|
/* make disk known with correct capacity */
|
||||||
dasd_setup_queue(device);
|
dasd_setup_queue(device);
|
||||||
|
set_capacity(device->gdp, device->blocks << device->s2b_shift);
|
||||||
device->state = DASD_STATE_READY;
|
device->state = DASD_STATE_READY;
|
||||||
if (dasd_scan_partitions(device) != 0)
|
rc = dasd_scan_partitions(device);
|
||||||
|
if (rc)
|
||||||
device->state = DASD_STATE_BASIC;
|
device->state = DASD_STATE_BASIC;
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -253,6 +260,15 @@ dasd_state_ready_to_basic(struct dasd_device * device)
|
||||||
device->state = DASD_STATE_BASIC;
|
device->state = DASD_STATE_BASIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Back to basic.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
dasd_state_unfmt_to_basic(struct dasd_device * device)
|
||||||
|
{
|
||||||
|
device->state = DASD_STATE_BASIC;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make the device online and schedule the bottom half to start
|
* Make the device online and schedule the bottom half to start
|
||||||
* the requeueing of requests from the linux request queue to the
|
* the requeueing of requests from the linux request queue to the
|
||||||
|
@ -320,6 +336,10 @@ dasd_decrease_state(struct dasd_device *device)
|
||||||
device->target <= DASD_STATE_BASIC)
|
device->target <= DASD_STATE_BASIC)
|
||||||
dasd_state_ready_to_basic(device);
|
dasd_state_ready_to_basic(device);
|
||||||
|
|
||||||
|
if (device->state == DASD_STATE_UNFMT &&
|
||||||
|
device->target <= DASD_STATE_BASIC)
|
||||||
|
dasd_state_unfmt_to_basic(device);
|
||||||
|
|
||||||
if (device->state == DASD_STATE_BASIC &&
|
if (device->state == DASD_STATE_BASIC &&
|
||||||
device->target <= DASD_STATE_KNOWN)
|
device->target <= DASD_STATE_KNOWN)
|
||||||
dasd_state_basic_to_known(device);
|
dasd_state_basic_to_known(device);
|
||||||
|
@ -1722,7 +1742,7 @@ dasd_open(struct inode *inp, struct file *filp)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->state < DASD_STATE_BASIC) {
|
if (device->state <= DASD_STATE_BASIC) {
|
||||||
DBF_DEV_EVENT(DBF_ERR, device, " %s",
|
DBF_DEV_EVENT(DBF_ERR, device, " %s",
|
||||||
" Cannot open unrecognized device");
|
" Cannot open unrecognized device");
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
|
|
|
@ -100,8 +100,6 @@ dasd_scan_partitions(struct dasd_device * device)
|
||||||
{
|
{
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
|
|
||||||
/* Make the disk known. */
|
|
||||||
set_capacity(device->gdp, device->blocks << device->s2b_shift);
|
|
||||||
bdev = bdget_disk(device->gdp, 0);
|
bdev = bdget_disk(device->gdp, 0);
|
||||||
if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
|
if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* new: the dasd_device structure is allocated.
|
* new: the dasd_device structure is allocated.
|
||||||
* known: the discipline for the device is identified.
|
* known: the discipline for the device is identified.
|
||||||
* basic: the device can do basic i/o.
|
* basic: the device can do basic i/o.
|
||||||
* accept: the device is analysed (format is known).
|
* unfmt: the device could not be analyzed (format is unknown).
|
||||||
* ready: partition detection is done and the device is can do block io.
|
* ready: partition detection is done and the device is can do block io.
|
||||||
* online: the device accepts requests from the block device queue.
|
* online: the device accepts requests from the block device queue.
|
||||||
*
|
*
|
||||||
|
@ -47,8 +47,9 @@
|
||||||
#define DASD_STATE_NEW 0
|
#define DASD_STATE_NEW 0
|
||||||
#define DASD_STATE_KNOWN 1
|
#define DASD_STATE_KNOWN 1
|
||||||
#define DASD_STATE_BASIC 2
|
#define DASD_STATE_BASIC 2
|
||||||
#define DASD_STATE_READY 3
|
#define DASD_STATE_UNFMT 3
|
||||||
#define DASD_STATE_ONLINE 4
|
#define DASD_STATE_READY 4
|
||||||
|
#define DASD_STATE_ONLINE 5
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
|
|
@ -93,6 +93,9 @@ dasd_devices_show(struct seq_file *m, void *v)
|
||||||
case DASD_STATE_BASIC:
|
case DASD_STATE_BASIC:
|
||||||
seq_printf(m, "basic");
|
seq_printf(m, "basic");
|
||||||
break;
|
break;
|
||||||
|
case DASD_STATE_UNFMT:
|
||||||
|
seq_printf(m, "unnformatted");
|
||||||
|
break;
|
||||||
case DASD_STATE_READY:
|
case DASD_STATE_READY:
|
||||||
case DASD_STATE_ONLINE:
|
case DASD_STATE_ONLINE:
|
||||||
seq_printf(m, "active ");
|
seq_printf(m, "active ");
|
||||||
|
|
|
@ -52,6 +52,7 @@ int
|
||||||
ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||||
{
|
{
|
||||||
int blocksize, offset, size;
|
int blocksize, offset, size;
|
||||||
|
loff_t i_size;
|
||||||
dasd_information_t *info;
|
dasd_information_t *info;
|
||||||
struct hd_geometry *geo;
|
struct hd_geometry *geo;
|
||||||
char type[5] = {0,};
|
char type[5] = {0,};
|
||||||
|
@ -63,6 +64,13 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
Sector sect;
|
Sector sect;
|
||||||
|
|
||||||
|
blocksize = bdev_hardsect_size(bdev);
|
||||||
|
if (blocksize <= 0)
|
||||||
|
return 0;
|
||||||
|
i_size = i_size_read(bdev->bd_inode);
|
||||||
|
if (i_size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
|
if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
|
||||||
goto out_noinfo;
|
goto out_noinfo;
|
||||||
if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
|
if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
|
||||||
|
@ -74,9 +82,6 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||||
ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
|
ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
|
||||||
goto out_noioctl;
|
goto out_noioctl;
|
||||||
|
|
||||||
if ((blocksize = bdev_hardsect_size(bdev)) <= 0)
|
|
||||||
goto out_badsect;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get volume label, extract name and type.
|
* Get volume label, extract name and type.
|
||||||
*/
|
*/
|
||||||
|
@ -111,7 +116,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||||
} else {
|
} else {
|
||||||
printk("CMS1/%8s:", name);
|
printk("CMS1/%8s:", name);
|
||||||
offset = (info->label_block + 1);
|
offset = (info->label_block + 1);
|
||||||
size = bdev->bd_inode->i_size >> 9;
|
size = i_size >> 9;
|
||||||
}
|
}
|
||||||
put_partition(state, 1, offset*(blocksize >> 9),
|
put_partition(state, 1, offset*(blocksize >> 9),
|
||||||
size-offset*(blocksize >> 9));
|
size-offset*(blocksize >> 9));
|
||||||
|
@ -168,7 +173,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||||
else
|
else
|
||||||
printk("(nonl)/%8s:", name);
|
printk("(nonl)/%8s:", name);
|
||||||
offset = (info->label_block + 1);
|
offset = (info->label_block + 1);
|
||||||
size = (bdev->bd_inode->i_size >> 9);
|
size = i_size >> 9;
|
||||||
put_partition(state, 1, offset*(blocksize >> 9),
|
put_partition(state, 1, offset*(blocksize >> 9),
|
||||||
size-offset*(blocksize >> 9));
|
size-offset*(blocksize >> 9));
|
||||||
}
|
}
|
||||||
|
@ -180,7 +185,6 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
out_readerr:
|
out_readerr:
|
||||||
out_badsect:
|
|
||||||
out_noioctl:
|
out_noioctl:
|
||||||
kfree(label);
|
kfree(label);
|
||||||
out_nolab:
|
out_nolab:
|
||||||
|
|
Loading…
Reference in New Issue