Commit 65d8013c authored by Stefan Raspl's avatar Stefan Raspl Committed by David S. Miller

qeth: fix qeth_wait_for_threads() deadlock for OSN devices

Any recovery thread will deadlock when calling qeth_wait_for_threads(), most
notably when triggering a recovery on an OSN device.
This patch will store the recovery thread's task pointer on recovery
invocation and check in qeth_wait_for_threads() respectively to avoid
deadlocks.
Signed-off-by: default avatarStefan Raspl <raspl@linux.vnet.ibm.com>
Signed-off-by: default avatarFrank Blaschka <blaschka@linux.vnet.ibm.com>
Reviewed-by: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f9c41a62
...@@ -769,6 +769,7 @@ struct qeth_card { ...@@ -769,6 +769,7 @@ struct qeth_card {
unsigned long thread_start_mask; unsigned long thread_start_mask;
unsigned long thread_allowed_mask; unsigned long thread_allowed_mask;
unsigned long thread_running_mask; unsigned long thread_running_mask;
struct task_struct *recovery_task;
spinlock_t ip_lock; spinlock_t ip_lock;
struct list_head ip_list; struct list_head ip_list;
struct list_head *ip_tbd_list; struct list_head *ip_tbd_list;
...@@ -862,6 +863,8 @@ extern struct qeth_card_list_struct qeth_core_card_list; ...@@ -862,6 +863,8 @@ extern struct qeth_card_list_struct qeth_core_card_list;
extern struct kmem_cache *qeth_core_header_cache; extern struct kmem_cache *qeth_core_header_cache;
extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS]; extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS];
void qeth_set_recovery_task(struct qeth_card *);
void qeth_clear_recovery_task(struct qeth_card *);
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int); void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int);
int qeth_threads_running(struct qeth_card *, unsigned long); int qeth_threads_running(struct qeth_card *, unsigned long);
int qeth_wait_for_threads(struct qeth_card *, unsigned long); int qeth_wait_for_threads(struct qeth_card *, unsigned long);
......
...@@ -177,6 +177,23 @@ const char *qeth_get_cardname_short(struct qeth_card *card) ...@@ -177,6 +177,23 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
return "n/a"; return "n/a";
} }
void qeth_set_recovery_task(struct qeth_card *card)
{
card->recovery_task = current;
}
EXPORT_SYMBOL_GPL(qeth_set_recovery_task);
void qeth_clear_recovery_task(struct qeth_card *card)
{
card->recovery_task = NULL;
}
EXPORT_SYMBOL_GPL(qeth_clear_recovery_task);
static bool qeth_is_recovery_task(const struct qeth_card *card)
{
return card->recovery_task == current;
}
void qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads, void qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,
int clear_start_mask) int clear_start_mask)
{ {
...@@ -205,6 +222,8 @@ EXPORT_SYMBOL_GPL(qeth_threads_running); ...@@ -205,6 +222,8 @@ EXPORT_SYMBOL_GPL(qeth_threads_running);
int qeth_wait_for_threads(struct qeth_card *card, unsigned long threads) int qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
{ {
if (qeth_is_recovery_task(card))
return 0;
return wait_event_interruptible(card->wait_q, return wait_event_interruptible(card->wait_q,
qeth_threads_running(card, threads) == 0); qeth_threads_running(card, threads) == 0);
} }
......
...@@ -1143,6 +1143,7 @@ static int qeth_l2_recover(void *ptr) ...@@ -1143,6 +1143,7 @@ static int qeth_l2_recover(void *ptr)
QETH_CARD_TEXT(card, 2, "recover2"); QETH_CARD_TEXT(card, 2, "recover2");
dev_warn(&card->gdev->dev, dev_warn(&card->gdev->dev,
"A recovery process has been started for the device\n"); "A recovery process has been started for the device\n");
qeth_set_recovery_task(card);
__qeth_l2_set_offline(card->gdev, 1); __qeth_l2_set_offline(card->gdev, 1);
rc = __qeth_l2_set_online(card->gdev, 1); rc = __qeth_l2_set_online(card->gdev, 1);
if (!rc) if (!rc)
...@@ -1153,6 +1154,7 @@ static int qeth_l2_recover(void *ptr) ...@@ -1153,6 +1154,7 @@ static int qeth_l2_recover(void *ptr)
dev_warn(&card->gdev->dev, "The qeth device driver " dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n"); "failed to recover an error on the device\n");
} }
qeth_clear_recovery_task(card);
qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
return 0; return 0;
......
...@@ -3515,6 +3515,7 @@ static int qeth_l3_recover(void *ptr) ...@@ -3515,6 +3515,7 @@ static int qeth_l3_recover(void *ptr)
QETH_CARD_TEXT(card, 2, "recover2"); QETH_CARD_TEXT(card, 2, "recover2");
dev_warn(&card->gdev->dev, dev_warn(&card->gdev->dev,
"A recovery process has been started for the device\n"); "A recovery process has been started for the device\n");
qeth_set_recovery_task(card);
__qeth_l3_set_offline(card->gdev, 1); __qeth_l3_set_offline(card->gdev, 1);
rc = __qeth_l3_set_online(card->gdev, 1); rc = __qeth_l3_set_online(card->gdev, 1);
if (!rc) if (!rc)
...@@ -3525,6 +3526,7 @@ static int qeth_l3_recover(void *ptr) ...@@ -3525,6 +3526,7 @@ static int qeth_l3_recover(void *ptr)
dev_warn(&card->gdev->dev, "The qeth device driver " dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n"); "failed to recover an error on the device\n");
} }
qeth_clear_recovery_task(card);
qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
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