Skip to content

Commit e73a99f

Browse files
hfreudeVasily Gorbik
authored andcommitted
s390/ap: Fix hanging ioctl caused by wrong msg counter
When a AP queue is switched to soft offline, all pending requests are purged out of the pending requests list and 'received' by the upper layer like zcrypt device drivers. This is also done for requests which are already enqueued into the firmware queue. A request in a firmware queue may eventually produce an response message, but there is no waiting process any more. However, the response was counted with the queue_counter and as this counter was reset to 0 with the offline switch, the pending response caused the queue_counter to get negative. The next request increased this counter to 0 (instead of 1) which caused the ap code to assume there is nothing to receive and so the response for this valid request was never tried to fetch from the firmware queue. This all caused a queue to not work properly after a switch offline/online and in the end processes to hang forever when trying to send a crypto request after an queue offline/online switch cicle. Fixed by a) making sure the counter does not drop below 0 and b) on a successful enqueue of a message has at least a value of 1. Additionally a warning is emitted, when a reply can't get assigned to a waiting process. This may be normal operation (process had timeout or has been killed) but may give a hint that something unexpected happened (like this odd behavior described above). Signed-off-by: Harald Freudenberger <[email protected]> Cc: [email protected] Signed-off-by: Vasily Gorbik <[email protected]>
1 parent 1874cb1 commit e73a99f

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

drivers/s390/crypto/ap_queue.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,13 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
135135
{
136136
struct ap_queue_status status;
137137
struct ap_message *ap_msg;
138+
bool found = false;
138139

139140
status = ap_dqap(aq->qid, &aq->reply->psmid,
140141
aq->reply->msg, aq->reply->len);
141142
switch (status.response_code) {
142143
case AP_RESPONSE_NORMAL:
143-
aq->queue_count--;
144+
aq->queue_count = max_t(int, 0, aq->queue_count - 1);
144145
if (aq->queue_count > 0)
145146
mod_timer(&aq->timeout,
146147
jiffies + aq->request_timeout);
@@ -150,8 +151,14 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq)
150151
list_del_init(&ap_msg->list);
151152
aq->pendingq_count--;
152153
ap_msg->receive(aq, ap_msg, aq->reply);
154+
found = true;
153155
break;
154156
}
157+
if (!found) {
158+
AP_DBF_WARN("%s unassociated reply psmid=0x%016llx on 0x%02x.%04x\n",
159+
__func__, aq->reply->psmid,
160+
AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
161+
}
155162
fallthrough;
156163
case AP_RESPONSE_NO_PENDING_REPLY:
157164
if (!status.queue_empty || aq->queue_count <= 0)
@@ -232,7 +239,7 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
232239
ap_msg->flags & AP_MSG_FLAG_SPECIAL);
233240
switch (status.response_code) {
234241
case AP_RESPONSE_NORMAL:
235-
aq->queue_count++;
242+
aq->queue_count = max_t(int, 1, aq->queue_count + 1);
236243
if (aq->queue_count == 1)
237244
mod_timer(&aq->timeout, jiffies + aq->request_timeout);
238245
list_move_tail(&ap_msg->list, &aq->pendingq);

0 commit comments

Comments
 (0)