mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-18 02:04:05 +08:00
s390/qeth: serialize cmd reply with concurrent timeout
Callbacks for a cmd reply run outside the protection of card->lock, to allow for additional cmds to be issued & enqueued in parallel. When qeth_send_control_data() bails out for a cmd without having received a reply (eg. due to timeout), its callback may concurrently be processing a reply that just arrived. In this case, the callback potentially accesses a stale reply->reply_param area that eg. was on-stack and has already been released. To avoid this race, add some locking so that qeth_send_control_data() can (1) wait for a concurrently running callback, and (2) zap any pending callback that still wants to run. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
This commit is contained in:
parent
a1794de8b9
commit
072f794000
@ -629,6 +629,7 @@ struct qeth_seqno {
|
||||
struct qeth_reply {
|
||||
struct list_head list;
|
||||
struct completion received;
|
||||
spinlock_t lock;
|
||||
int (*callback)(struct qeth_card *, struct qeth_reply *,
|
||||
unsigned long);
|
||||
u32 seqno;
|
||||
|
@ -544,6 +544,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
|
||||
if (reply) {
|
||||
refcount_set(&reply->refcnt, 1);
|
||||
init_completion(&reply->received);
|
||||
spin_lock_init(&reply->lock);
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
@ -799,6 +800,13 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
|
||||
|
||||
if (!reply->callback) {
|
||||
rc = 0;
|
||||
goto no_callback;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&reply->lock, flags);
|
||||
if (reply->rc) {
|
||||
/* Bail out when the requestor has already left: */
|
||||
rc = reply->rc;
|
||||
} else {
|
||||
if (cmd) {
|
||||
reply->offset = (u16)((char *)cmd - (char *)iob->data);
|
||||
@ -807,7 +815,9 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
|
||||
rc = reply->callback(card, reply, (unsigned long)iob);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&reply->lock, flags);
|
||||
|
||||
no_callback:
|
||||
if (rc <= 0)
|
||||
qeth_notify_reply(reply, rc);
|
||||
qeth_put_reply(reply);
|
||||
@ -1749,6 +1759,16 @@ static int qeth_send_control_data(struct qeth_card *card,
|
||||
rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
|
||||
|
||||
qeth_dequeue_reply(card, reply);
|
||||
|
||||
if (reply_cb) {
|
||||
/* Wait until the callback for a late reply has completed: */
|
||||
spin_lock_irq(&reply->lock);
|
||||
if (rc)
|
||||
/* Zap any callback that's still pending: */
|
||||
reply->rc = rc;
|
||||
spin_unlock_irq(&reply->lock);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = reply->rc;
|
||||
qeth_put_reply(reply);
|
||||
|
Loading…
Reference in New Issue
Block a user