Commit d42e1712 authored by Stefan Haberland's avatar Stefan Haberland Committed by Martin Schwidefsky

s390/dasd: improve speed of dasdfmt

Reorganize format IO requests and enable usage of PAV.
Signed-off-by: default avatarStefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent e5dcf002
...@@ -246,7 +246,7 @@ static struct dentry *dasd_debugfs_setup(const char *name, ...@@ -246,7 +246,7 @@ static struct dentry *dasd_debugfs_setup(const char *name,
static int dasd_state_known_to_basic(struct dasd_device *device) static int dasd_state_known_to_basic(struct dasd_device *device)
{ {
struct dasd_block *block = device->block; struct dasd_block *block = device->block;
int rc; int rc = 0;
/* Allocate and register gendisk structure. */ /* Allocate and register gendisk structure. */
if (block) { if (block) {
...@@ -273,7 +273,8 @@ static int dasd_state_known_to_basic(struct dasd_device *device) ...@@ -273,7 +273,8 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created"); DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
device->state = DASD_STATE_BASIC; device->state = DASD_STATE_BASIC;
return 0;
return rc;
} }
/* /*
...@@ -282,6 +283,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device) ...@@ -282,6 +283,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
static int dasd_state_basic_to_known(struct dasd_device *device) static int dasd_state_basic_to_known(struct dasd_device *device)
{ {
int rc; int rc;
if (device->block) { if (device->block) {
dasd_profile_exit(&device->block->profile); dasd_profile_exit(&device->block->profile);
if (device->block->debugfs_dentry) if (device->block->debugfs_dentry)
...@@ -332,8 +334,10 @@ static int dasd_state_basic_to_ready(struct dasd_device *device) ...@@ -332,8 +334,10 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
if (block->base->discipline->do_analysis != NULL) if (block->base->discipline->do_analysis != NULL)
rc = block->base->discipline->do_analysis(block); rc = block->base->discipline->do_analysis(block);
if (rc) { if (rc) {
if (rc != -EAGAIN) if (rc != -EAGAIN) {
device->state = DASD_STATE_UNFMT; device->state = DASD_STATE_UNFMT;
goto out;
}
return rc; return rc;
} }
dasd_setup_queue(block); dasd_setup_queue(block);
...@@ -341,11 +345,16 @@ static int dasd_state_basic_to_ready(struct dasd_device *device) ...@@ -341,11 +345,16 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
block->blocks << block->s2b_shift); block->blocks << block->s2b_shift);
device->state = DASD_STATE_READY; device->state = DASD_STATE_READY;
rc = dasd_scan_partitions(block); rc = dasd_scan_partitions(block);
if (rc) if (rc) {
device->state = DASD_STATE_BASIC; device->state = DASD_STATE_BASIC;
return rc;
}
} else { } else {
device->state = DASD_STATE_READY; device->state = DASD_STATE_READY;
} }
out:
if (device->discipline->basic_to_ready)
rc = device->discipline->basic_to_ready(device);
return rc; return rc;
} }
...@@ -368,6 +377,11 @@ static int dasd_state_ready_to_basic(struct dasd_device *device) ...@@ -368,6 +377,11 @@ static int dasd_state_ready_to_basic(struct dasd_device *device)
{ {
int rc; int rc;
if (device->discipline->ready_to_basic) {
rc = device->discipline->ready_to_basic(device);
if (rc)
return rc;
}
device->state = DASD_STATE_BASIC; device->state = DASD_STATE_BASIC;
if (device->block) { if (device->block) {
struct dasd_block *block = device->block; struct dasd_block *block = device->block;
...@@ -402,16 +416,10 @@ static int dasd_state_unfmt_to_basic(struct dasd_device *device) ...@@ -402,16 +416,10 @@ static int dasd_state_unfmt_to_basic(struct dasd_device *device)
static int static int
dasd_state_ready_to_online(struct dasd_device * device) dasd_state_ready_to_online(struct dasd_device * device)
{ {
int rc;
struct gendisk *disk; struct gendisk *disk;
struct disk_part_iter piter; struct disk_part_iter piter;
struct hd_struct *part; struct hd_struct *part;
if (device->discipline->ready_to_online) {
rc = device->discipline->ready_to_online(device);
if (rc)
return rc;
}
device->state = DASD_STATE_ONLINE; device->state = DASD_STATE_ONLINE;
if (device->block) { if (device->block) {
dasd_schedule_block_bh(device->block); dasd_schedule_block_bh(device->block);
...@@ -444,6 +452,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device) ...@@ -444,6 +452,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
if (rc) if (rc)
return rc; return rc;
} }
device->state = DASD_STATE_READY; device->state = DASD_STATE_READY;
if (device->block && !(device->features & DASD_FEATURE_USERAW)) { if (device->block && !(device->features & DASD_FEATURE_USERAW)) {
disk = device->block->bdev->bd_disk; disk = device->block->bdev->bd_disk;
...@@ -2223,6 +2232,77 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) ...@@ -2223,6 +2232,77 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
return rc; return rc;
} }
static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
{
struct dasd_ccw_req *cqr;
list_for_each_entry(cqr, ccw_queue, blocklist) {
if (cqr->callback_data != DASD_SLEEPON_END_TAG)
return 0;
}
return 1;
}
static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
{
struct dasd_device *device;
int rc;
struct dasd_ccw_req *cqr, *n;
retry:
list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
device = cqr->startdev;
if (cqr->status != DASD_CQR_FILLED) /*could be failed*/
continue;
if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
!test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
cqr->status = DASD_CQR_FAILED;
cqr->intrc = -EPERM;
continue;
}
/*Non-temporary stop condition will trigger fail fast*/
if (device->stopped & ~DASD_STOPPED_PENDING &&
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
!dasd_eer_enabled(device)) {
cqr->status = DASD_CQR_FAILED;
cqr->intrc = -EAGAIN;
continue;
}
/*Don't try to start requests if device is stopped*/
if (interruptible) {
rc = wait_event_interruptible(
generic_waitq, !device->stopped);
if (rc == -ERESTARTSYS) {
cqr->status = DASD_CQR_FAILED;
cqr->intrc = rc;
continue;
}
} else
wait_event(generic_waitq, !(device->stopped));
if (!cqr->callback)
cqr->callback = dasd_wakeup_cb;
cqr->callback_data = DASD_SLEEPON_START_TAG;
dasd_add_request_tail(cqr);
}
wait_event(generic_waitq, _wait_for_wakeup_queue(ccw_queue));
rc = 0;
list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
if (__dasd_sleep_on_erp(cqr))
rc = 1;
}
if (rc)
goto retry;
return 0;
}
/* /*
* Queue a request to the tail of the device ccw_queue and wait for * Queue a request to the tail of the device ccw_queue and wait for
* it's completion. * it's completion.
...@@ -2232,6 +2312,15 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr) ...@@ -2232,6 +2312,15 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
return _dasd_sleep_on(cqr, 0); return _dasd_sleep_on(cqr, 0);
} }
/*
* Start requests from a ccw_queue and wait for their completion.
*/
int dasd_sleep_on_queue(struct list_head *ccw_queue)
{
return _dasd_sleep_on_queue(ccw_queue, 0);
}
EXPORT_SYMBOL(dasd_sleep_on_queue);
/* /*
* Queue a request to the tail of the device ccw_queue and wait * Queue a request to the tail of the device ccw_queue and wait
* interruptible for it's completion. * interruptible for it's completion.
......
This diff is collapsed.
...@@ -300,10 +300,11 @@ struct dasd_discipline { ...@@ -300,10 +300,11 @@ struct dasd_discipline {
* Last things to do when a device is set online, and first things * Last things to do when a device is set online, and first things
* when it is set offline. * when it is set offline.
*/ */
int (*ready_to_online) (struct dasd_device *); int (*basic_to_ready) (struct dasd_device *);
int (*online_to_ready) (struct dasd_device *); int (*online_to_ready) (struct dasd_device *);
int (*ready_to_basic) (struct dasd_device *);
/* /* (struct dasd_device *);
* Device operation functions. build_cp creates a ccw chain for * Device operation functions. build_cp creates a ccw chain for
* a block device request, start_io starts the request and * a block device request, start_io starts the request and
* term_IO cancels it (e.g. in case of a timeout). format_device * term_IO cancels it (e.g. in case of a timeout). format_device
...@@ -317,7 +318,7 @@ struct dasd_discipline { ...@@ -317,7 +318,7 @@ struct dasd_discipline {
int (*start_IO) (struct dasd_ccw_req *); int (*start_IO) (struct dasd_ccw_req *);
int (*term_IO) (struct dasd_ccw_req *); int (*term_IO) (struct dasd_ccw_req *);
void (*handle_terminated_request) (struct dasd_ccw_req *); void (*handle_terminated_request) (struct dasd_ccw_req *);
struct dasd_ccw_req *(*format_device) (struct dasd_device *, int (*format_device) (struct dasd_device *,
struct format_data_t *); struct format_data_t *);
int (*free_cp) (struct dasd_ccw_req *, struct request *); int (*free_cp) (struct dasd_ccw_req *, struct request *);
...@@ -672,6 +673,7 @@ int dasd_term_IO(struct dasd_ccw_req *); ...@@ -672,6 +673,7 @@ int dasd_term_IO(struct dasd_ccw_req *);
void dasd_schedule_device_bh(struct dasd_device *); void dasd_schedule_device_bh(struct dasd_device *);
void dasd_schedule_block_bh(struct dasd_block *); void dasd_schedule_block_bh(struct dasd_block *);
int dasd_sleep_on(struct dasd_ccw_req *); int dasd_sleep_on(struct dasd_ccw_req *);
int dasd_sleep_on_queue(struct list_head *);
int dasd_sleep_on_immediatly(struct dasd_ccw_req *); int dasd_sleep_on_immediatly(struct dasd_ccw_req *);
int dasd_sleep_on_interruptible(struct dasd_ccw_req *); int dasd_sleep_on_interruptible(struct dasd_ccw_req *);
void dasd_device_set_timer(struct dasd_device *, int); void dasd_device_set_timer(struct dasd_device *, int);
......
...@@ -143,12 +143,12 @@ static int dasd_ioctl_resume(struct dasd_block *block) ...@@ -143,12 +143,12 @@ static int dasd_ioctl_resume(struct dasd_block *block)
/* /*
* performs formatting of _device_ according to _fdata_ * performs formatting of _device_ according to _fdata_
* Note: The discipline's format_function is assumed to deliver formatting * Note: The discipline's format_function is assumed to deliver formatting
* commands to format a single unit of the device. In terms of the ECKD * commands to format multiple units of the device. In terms of the ECKD
* devices this means CCWs are generated to format a single track. * devices this means CCWs are generated to format multiple tracks.
*/ */
static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) static int
dasd_format(struct dasd_block *block, struct format_data_t *fdata)
{ {
struct dasd_ccw_req *cqr;
struct dasd_device *base; struct dasd_device *base;
int rc; int rc;
...@@ -157,8 +157,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) ...@@ -157,8 +157,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
return -EPERM; return -EPERM;
if (base->state != DASD_STATE_BASIC) { if (base->state != DASD_STATE_BASIC) {
pr_warning("%s: The DASD cannot be formatted while it is " pr_warn("%s: The DASD cannot be formatted while it is enabled\n",
"enabled\n", dev_name(&base->cdev->dev)); dev_name(&base->cdev->dev));
return -EBUSY; return -EBUSY;
} }
...@@ -178,21 +178,10 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) ...@@ -178,21 +178,10 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
bdput(bdev); bdput(bdev);
} }
while (fdata->start_unit <= fdata->stop_unit) { rc = base->discipline->format_device(base, fdata);
cqr = base->discipline->format_device(base, fdata); if (rc)
if (IS_ERR(cqr))
return PTR_ERR(cqr);
rc = dasd_sleep_on_interruptible(cqr);
dasd_sfree_request(cqr, cqr->memdev);
if (rc) {
if (rc != -ERESTARTSYS)
pr_err("%s: Formatting unit %d failed with "
"rc=%d\n", dev_name(&base->cdev->dev),
fdata->start_unit, rc);
return rc; return rc;
}
fdata->start_unit++;
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment