[S390] sclp: invalid handling of temporary 'not operational' status
Requests are aborted when the sclp interface reports 'not operational' even though they may still be active at the sclp, leading to concurrent writes to request memory by both the kernel and the sclp interface. Do not abort requests for which the sclp interface reports not operational status during request retry. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>5A Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
3b0b4af2c7
commit
dbd8ae6306
1 changed files with 50 additions and 22 deletions
|
@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
|
||||||
/* Internal state: is a request active at the sclp? */
|
/* Internal state: is a request active at the sclp? */
|
||||||
static volatile enum sclp_running_state_t {
|
static volatile enum sclp_running_state_t {
|
||||||
sclp_running_state_idle,
|
sclp_running_state_idle,
|
||||||
sclp_running_state_running
|
sclp_running_state_running,
|
||||||
|
sclp_running_state_reset_pending
|
||||||
} sclp_running_state = sclp_running_state_idle;
|
} sclp_running_state = sclp_running_state_idle;
|
||||||
|
|
||||||
/* Internal state: is a read request pending? */
|
/* Internal state: is a read request pending? */
|
||||||
|
@ -88,7 +89,7 @@ static volatile enum sclp_mask_state_t {
|
||||||
|
|
||||||
/* Timeout intervals in seconds.*/
|
/* Timeout intervals in seconds.*/
|
||||||
#define SCLP_BUSY_INTERVAL 10
|
#define SCLP_BUSY_INTERVAL 10
|
||||||
#define SCLP_RETRY_INTERVAL 15
|
#define SCLP_RETRY_INTERVAL 30
|
||||||
|
|
||||||
static void sclp_process_queue(void);
|
static void sclp_process_queue(void);
|
||||||
static int sclp_init_mask(int calculate);
|
static int sclp_init_mask(int calculate);
|
||||||
|
@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request timeout handler. Restart the request queue. If DATA is non-zero,
|
static inline void __sclp_make_read_req(void);
|
||||||
* force restart of running request. */
|
|
||||||
static void
|
|
||||||
sclp_request_timeout(unsigned long data)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (data) {
|
static void
|
||||||
spin_lock_irqsave(&sclp_lock, flags);
|
__sclp_queue_read_req(void)
|
||||||
sclp_running_state = sclp_running_state_idle;
|
{
|
||||||
spin_unlock_irqrestore(&sclp_lock, flags);
|
if (sclp_reading_state == sclp_reading_state_idle) {
|
||||||
|
sclp_reading_state = sclp_reading_state_reading;
|
||||||
|
__sclp_make_read_req();
|
||||||
|
/* Add request to head of queue */
|
||||||
|
list_add(&sclp_read_req.list, &sclp_req_queue);
|
||||||
}
|
}
|
||||||
sclp_process_queue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up request retry timer. Called while sclp_lock is locked. */
|
/* Set up request retry timer. Called while sclp_lock is locked. */
|
||||||
|
@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
|
||||||
add_timer(&sclp_request_timer);
|
add_timer(&sclp_request_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Request timeout handler. Restart the request queue. If DATA is non-zero,
|
||||||
|
* force restart of running request. */
|
||||||
|
static void
|
||||||
|
sclp_request_timeout(unsigned long data)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&sclp_lock, flags);
|
||||||
|
if (data) {
|
||||||
|
if (sclp_running_state == sclp_running_state_running) {
|
||||||
|
/* Break running state and queue NOP read event request
|
||||||
|
* to get a defined interface state. */
|
||||||
|
__sclp_queue_read_req();
|
||||||
|
sclp_running_state = sclp_running_state_idle;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
|
||||||
|
sclp_request_timeout, 0);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&sclp_lock, flags);
|
||||||
|
sclp_process_queue();
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to start a request. Return zero if the request was successfully
|
/* Try to start a request. Return zero if the request was successfully
|
||||||
* started or if it will be started at a later time. Return non-zero otherwise.
|
* started or if it will be started at a later time. Return non-zero otherwise.
|
||||||
* Called while sclp_lock is locked. */
|
* Called while sclp_lock is locked. */
|
||||||
|
@ -191,7 +213,15 @@ sclp_process_queue(void)
|
||||||
rc = __sclp_start_request(req);
|
rc = __sclp_start_request(req);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
break;
|
break;
|
||||||
/* Request failed. */
|
/* Request failed */
|
||||||
|
if (req->start_count > 1) {
|
||||||
|
/* Cannot abort already submitted request - could still
|
||||||
|
* be active at the SCLP */
|
||||||
|
__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
|
||||||
|
sclp_request_timeout, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Post-processing for aborted request */
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
if (req->callback) {
|
if (req->callback) {
|
||||||
spin_unlock_irqrestore(&sclp_lock, flags);
|
spin_unlock_irqrestore(&sclp_lock, flags);
|
||||||
|
@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req)
|
||||||
list_add_tail(&req->list, &sclp_req_queue);
|
list_add_tail(&req->list, &sclp_req_queue);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
/* Start if request is first in list */
|
/* Start if request is first in list */
|
||||||
if (req->list.prev == &sclp_req_queue) {
|
if (sclp_running_state == sclp_running_state_idle &&
|
||||||
|
req->list.prev == &sclp_req_queue) {
|
||||||
rc = __sclp_start_request(req);
|
rc = __sclp_start_request(req);
|
||||||
if (rc)
|
if (rc)
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
|
@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
|
||||||
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
||||||
evbuf_pending = S390_lowcore.ext_params & 0x3;
|
evbuf_pending = S390_lowcore.ext_params & 0x3;
|
||||||
if (finished_sccb) {
|
if (finished_sccb) {
|
||||||
|
del_timer(&sclp_request_timer);
|
||||||
|
sclp_running_state = sclp_running_state_reset_pending;
|
||||||
req = __sclp_find_req(finished_sccb);
|
req = __sclp_find_req(finished_sccb);
|
||||||
if (req) {
|
if (req) {
|
||||||
/* Request post-processing */
|
/* Request post-processing */
|
||||||
|
@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
|
||||||
sclp_running_state = sclp_running_state_idle;
|
sclp_running_state = sclp_running_state_idle;
|
||||||
}
|
}
|
||||||
if (evbuf_pending && sclp_receive_mask != 0 &&
|
if (evbuf_pending && sclp_receive_mask != 0 &&
|
||||||
sclp_reading_state == sclp_reading_state_idle &&
|
sclp_activation_state == sclp_activation_state_active)
|
||||||
sclp_activation_state == sclp_activation_state_active ) {
|
__sclp_queue_read_req();
|
||||||
sclp_reading_state = sclp_reading_state_reading;
|
|
||||||
__sclp_make_read_req();
|
|
||||||
/* Add request to head of queue */
|
|
||||||
list_add(&sclp_read_req.list, &sclp_req_queue);
|
|
||||||
}
|
|
||||||
spin_unlock(&sclp_lock);
|
spin_unlock(&sclp_lock);
|
||||||
sclp_process_queue();
|
sclp_process_queue();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue