Skip to content

Commit 9bce8b2

Browse files
braunuMartin Schwidefsky
authored andcommitted
s390/qdio: avoid reschedule of outbound tasklet once killed
During qdio_shutdown the queue tasklets are killed for all inbound and outbound queues. The queue structures might be freed after qdio_shutdown. Thus it must be guaranteed that these queue tasklets are not rescheduled after that. In addition the outbound queue timers are deleted and it must be guaranteed that these timers are not restarted after qdio_shutdown processing. Timer deletion should make use of del_timer_sync() to make sure qdio_outbound_timer() is finished on other CPUs as well. Queue tasklets should be scheduled in state QDIO_IRQ_STATE_ACTIVE only. Signed-off-by: Ursula Braun <[email protected]> Reviewed-by: Benjamin Block <[email protected]> Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent 6e30c54 commit 9bce8b2

File tree

1 file changed

+25
-24
lines changed

1 file changed

+25
-24
lines changed

drivers/s390/cio/qdio_main.c

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,15 @@ static void qdio_kick_handler(struct qdio_q *q)
686686
q->qdio_error = 0;
687687
}
688688

689+
static inline int qdio_tasklet_schedule(struct qdio_q *q)
690+
{
691+
if (likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) {
692+
tasklet_schedule(&q->tasklet);
693+
return 0;
694+
}
695+
return -EPERM;
696+
}
697+
689698
static void __qdio_inbound_processing(struct qdio_q *q)
690699
{
691700
qperf_inc(q, tasklet_inbound);
@@ -698,10 +707,8 @@ static void __qdio_inbound_processing(struct qdio_q *q)
698707
if (!qdio_inbound_q_done(q)) {
699708
/* means poll time is not yet over */
700709
qperf_inc(q, tasklet_inbound_resched);
701-
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) {
702-
tasklet_schedule(&q->tasklet);
710+
if (!qdio_tasklet_schedule(q))
703711
return;
704-
}
705712
}
706713

707714
qdio_stop_polling(q);
@@ -711,8 +718,7 @@ static void __qdio_inbound_processing(struct qdio_q *q)
711718
*/
712719
if (!qdio_inbound_q_done(q)) {
713720
qperf_inc(q, tasklet_inbound_resched2);
714-
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
715-
tasklet_schedule(&q->tasklet);
721+
qdio_tasklet_schedule(q);
716722
}
717723
}
718724

@@ -869,16 +875,15 @@ static void __qdio_outbound_processing(struct qdio_q *q)
869875
* is noticed and outbound_handler is called after some time.
870876
*/
871877
if (qdio_outbound_q_done(q))
872-
del_timer(&q->u.out.timer);
878+
del_timer_sync(&q->u.out.timer);
873879
else
874-
if (!timer_pending(&q->u.out.timer))
880+
if (!timer_pending(&q->u.out.timer) &&
881+
likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE))
875882
mod_timer(&q->u.out.timer, jiffies + 10 * HZ);
876883
return;
877884

878885
sched:
879-
if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
880-
return;
881-
tasklet_schedule(&q->tasklet);
886+
qdio_tasklet_schedule(q);
882887
}
883888

884889
/* outbound tasklet */
@@ -892,9 +897,7 @@ void qdio_outbound_timer(unsigned long data)
892897
{
893898
struct qdio_q *q = (struct qdio_q *)data;
894899

895-
if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
896-
return;
897-
tasklet_schedule(&q->tasklet);
900+
qdio_tasklet_schedule(q);
898901
}
899902

900903
static inline void qdio_check_outbound_after_thinint(struct qdio_q *q)
@@ -907,7 +910,7 @@ static inline void qdio_check_outbound_after_thinint(struct qdio_q *q)
907910

908911
for_each_output_queue(q->irq_ptr, out, i)
909912
if (!qdio_outbound_q_done(out))
910-
tasklet_schedule(&out->tasklet);
913+
qdio_tasklet_schedule(out);
911914
}
912915

913916
static void __tiqdio_inbound_processing(struct qdio_q *q)
@@ -929,10 +932,8 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
929932

930933
if (!qdio_inbound_q_done(q)) {
931934
qperf_inc(q, tasklet_inbound_resched);
932-
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) {
933-
tasklet_schedule(&q->tasklet);
935+
if (!qdio_tasklet_schedule(q))
934936
return;
935-
}
936937
}
937938

938939
qdio_stop_polling(q);
@@ -942,8 +943,7 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
942943
*/
943944
if (!qdio_inbound_q_done(q)) {
944945
qperf_inc(q, tasklet_inbound_resched2);
945-
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
946-
tasklet_schedule(&q->tasklet);
946+
qdio_tasklet_schedule(q);
947947
}
948948
}
949949

@@ -977,7 +977,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
977977
int i;
978978
struct qdio_q *q;
979979

980-
if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
980+
if (unlikely(irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
981981
return;
982982

983983
for_each_input_queue(irq_ptr, q, i) {
@@ -1003,7 +1003,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
10031003
continue;
10041004
if (need_siga_sync(q) && need_siga_sync_out_after_pci(q))
10051005
qdio_siga_sync_q(q);
1006-
tasklet_schedule(&q->tasklet);
1006+
qdio_tasklet_schedule(q);
10071007
}
10081008
}
10091009

@@ -1145,7 +1145,7 @@ static void qdio_shutdown_queues(struct ccw_device *cdev)
11451145
tasklet_kill(&q->tasklet);
11461146

11471147
for_each_output_queue(irq_ptr, q, i) {
1148-
del_timer(&q->u.out.timer);
1148+
del_timer_sync(&q->u.out.timer);
11491149
tasklet_kill(&q->tasklet);
11501150
}
11511151
}
@@ -1585,10 +1585,11 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
15851585

15861586
/* in case of SIGA errors we must process the error immediately */
15871587
if (used >= q->u.out.scan_threshold || rc)
1588-
tasklet_schedule(&q->tasklet);
1588+
qdio_tasklet_schedule(q);
15891589
else
15901590
/* free the SBALs in case of no further traffic */
1591-
if (!timer_pending(&q->u.out.timer))
1591+
if (!timer_pending(&q->u.out.timer) &&
1592+
likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE))
15921593
mod_timer(&q->u.out.timer, jiffies + HZ);
15931594
return rc;
15941595
}

0 commit comments

Comments
 (0)