diff options
Diffstat (limited to 'kernel/softirq.c')
-rw-r--r-- | kernel/softirq.c | 63 |
1 files changed, 41 insertions, 22 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c index 31e9f2a47928..3c44956ee7e2 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
@@ -356,7 +356,8 @@ void open_softirq(int nr, void (*action)(struct softirq_action*), void *data) | |||
356 | /* Tasklets */ | 356 | /* Tasklets */ |
357 | struct tasklet_head | 357 | struct tasklet_head |
358 | { | 358 | { |
359 | struct tasklet_struct *list; | 359 | struct tasklet_struct *head; |
360 | struct tasklet_struct **tail; | ||
360 | }; | 361 | }; |
361 | 362 | ||
362 | /* Some compilers disobey section attribute on statics when not | 363 | /* Some compilers disobey section attribute on statics when not |
@@ -369,8 +370,9 @@ void __tasklet_schedule(struct tasklet_struct *t) | |||
369 | unsigned long flags; | 370 | unsigned long flags; |
370 | 371 | ||
371 | local_irq_save(flags); | 372 | local_irq_save(flags); |
372 | t->next = __get_cpu_var(tasklet_vec).list; | 373 | t->next = NULL; |
373 | __get_cpu_var(tasklet_vec).list = t; | 374 | *__get_cpu_var(tasklet_vec).tail = t; |
375 | __get_cpu_var(tasklet_vec).tail = &(t->next); | ||
374 | raise_softirq_irqoff(TASKLET_SOFTIRQ); | 376 | raise_softirq_irqoff(TASKLET_SOFTIRQ); |
375 | local_irq_restore(flags); | 377 | local_irq_restore(flags); |
376 | } | 378 | } |
@@ -382,8 +384,9 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) | |||
382 | unsigned long flags; | 384 | unsigned long flags; |
383 | 385 | ||
384 | local_irq_save(flags); | 386 | local_irq_save(flags); |
385 | t->next = __get_cpu_var(tasklet_hi_vec).list; | 387 | t->next = NULL; |
386 | __get_cpu_var(tasklet_hi_vec).list = t; | 388 | *__get_cpu_var(tasklet_hi_vec).tail = t; |
389 | __get_cpu_var(tasklet_hi_vec).tail = &(t->next); | ||
387 | raise_softirq_irqoff(HI_SOFTIRQ); | 390 | raise_softirq_irqoff(HI_SOFTIRQ); |
388 | local_irq_restore(flags); | 391 | local_irq_restore(flags); |
389 | } | 392 | } |
@@ -395,8 +398,9 @@ static void tasklet_action(struct softirq_action *a) | |||
395 | struct tasklet_struct *list; | 398 | struct tasklet_struct *list; |
396 | 399 | ||
397 | local_irq_disable(); | 400 | local_irq_disable(); |
398 | list = __get_cpu_var(tasklet_vec).list; | 401 | list = __get_cpu_var(tasklet_vec).head; |
399 | __get_cpu_var(tasklet_vec).list = NULL; | 402 | __get_cpu_var(tasklet_vec).head = NULL; |
403 | __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head; | ||
400 | local_irq_enable(); | 404 | local_irq_enable(); |
401 | 405 | ||
402 | while (list) { | 406 | while (list) { |
@@ -416,8 +420,9 @@ static void tasklet_action(struct softirq_action *a) | |||
416 | } | 420 | } |
417 | 421 | ||
418 | local_irq_disable(); | 422 | local_irq_disable(); |
419 | t->next = __get_cpu_var(tasklet_vec).list; | 423 | t->next = NULL; |
420 | __get_cpu_var(tasklet_vec).list = t; | 424 | *__get_cpu_var(tasklet_vec).tail = t; |
425 | __get_cpu_var(tasklet_vec).tail = &(t->next); | ||
421 | __raise_softirq_irqoff(TASKLET_SOFTIRQ); | 426 | __raise_softirq_irqoff(TASKLET_SOFTIRQ); |
422 | local_irq_enable(); | 427 | local_irq_enable(); |
423 | } | 428 | } |
@@ -428,8 +433,9 @@ static void tasklet_hi_action(struct softirq_action *a) | |||
428 | struct tasklet_struct *list; | 433 | struct tasklet_struct *list; |
429 | 434 | ||
430 | local_irq_disable(); | 435 | local_irq_disable(); |
431 | list = __get_cpu_var(tasklet_hi_vec).list; | 436 | list = __get_cpu_var(tasklet_hi_vec).head; |
432 | __get_cpu_var(tasklet_hi_vec).list = NULL; | 437 | __get_cpu_var(tasklet_hi_vec).head = NULL; |
438 | __get_cpu_var(tasklet_hi_vec).tail = &__get_cpu_var(tasklet_hi_vec).head; | ||
433 | local_irq_enable(); | 439 | local_irq_enable(); |
434 | 440 | ||
435 | while (list) { | 441 | while (list) { |
@@ -449,8 +455,9 @@ static void tasklet_hi_action(struct softirq_action *a) | |||
449 | } | 455 | } |
450 | 456 | ||
451 | local_irq_disable(); | 457 | local_irq_disable(); |
452 | t->next = __get_cpu_var(tasklet_hi_vec).list; | 458 | t->next = NULL; |
453 | __get_cpu_var(tasklet_hi_vec).list = t; | 459 | *__get_cpu_var(tasklet_hi_vec).tail = t; |
460 | __get_cpu_var(tasklet_hi_vec).tail = &(t->next); | ||
454 | __raise_softirq_irqoff(HI_SOFTIRQ); | 461 | __raise_softirq_irqoff(HI_SOFTIRQ); |
455 | local_irq_enable(); | 462 | local_irq_enable(); |
456 | } | 463 | } |
@@ -487,6 +494,15 @@ EXPORT_SYMBOL(tasklet_kill); | |||
487 | 494 | ||
488 | void __init softirq_init(void) | 495 | void __init softirq_init(void) |
489 | { | 496 | { |
497 | int cpu; | ||
498 | |||
499 | for_each_possible_cpu(cpu) { | ||
500 | per_cpu(tasklet_vec, cpu).tail = | ||
501 | &per_cpu(tasklet_vec, cpu).head; | ||
502 | per_cpu(tasklet_hi_vec, cpu).tail = | ||
503 | &per_cpu(tasklet_hi_vec, cpu).head; | ||
504 | } | ||
505 | |||
490 | open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); | 506 | open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); |
491 | open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); | 507 | open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); |
492 | } | 508 | } |
@@ -555,9 +571,12 @@ void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu) | |||
555 | return; | 571 | return; |
556 | 572 | ||
557 | /* CPU is dead, so no lock needed. */ | 573 | /* CPU is dead, so no lock needed. */ |
558 | for (i = &per_cpu(tasklet_vec, cpu).list; *i; i = &(*i)->next) { | 574 | for (i = &per_cpu(tasklet_vec, cpu).head; *i; i = &(*i)->next) { |
559 | if (*i == t) { | 575 | if (*i == t) { |
560 | *i = t->next; | 576 | *i = t->next; |
577 | /* If this was the tail element, move the tail ptr */ | ||
578 | if (*i == NULL) | ||
579 | per_cpu(tasklet_vec, cpu).tail = i; | ||
561 | return; | 580 | return; |
562 | } | 581 | } |
563 | } | 582 | } |
@@ -566,20 +585,20 @@ void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu) | |||
566 | 585 | ||
567 | static void takeover_tasklets(unsigned int cpu) | 586 | static void takeover_tasklets(unsigned int cpu) |
568 | { | 587 | { |
569 | struct tasklet_struct **i; | ||
570 | |||
571 | /* CPU is dead, so no lock needed. */ | 588 | /* CPU is dead, so no lock needed. */ |
572 | local_irq_disable(); | 589 | local_irq_disable(); |
573 | 590 | ||
574 | /* Find end, append list for that CPU. */ | 591 | /* Find end, append list for that CPU. */ |
575 | for (i = &__get_cpu_var(tasklet_vec).list; *i; i = &(*i)->next); | 592 | *__get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).head; |
576 | *i = per_cpu(tasklet_vec, cpu).list; | 593 | __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail; |
577 | per_cpu(tasklet_vec, cpu).list = NULL; | 594 | per_cpu(tasklet_vec, cpu).head = NULL; |
595 | per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head; | ||
578 | raise_softirq_irqoff(TASKLET_SOFTIRQ); | 596 | raise_softirq_irqoff(TASKLET_SOFTIRQ); |
579 | 597 | ||
580 | for (i = &__get_cpu_var(tasklet_hi_vec).list; *i; i = &(*i)->next); | 598 | *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head; |
581 | *i = per_cpu(tasklet_hi_vec, cpu).list; | 599 | __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail; |
582 | per_cpu(tasklet_hi_vec, cpu).list = NULL; | 600 | per_cpu(tasklet_hi_vec, cpu).head = NULL; |
601 | per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head; | ||
583 | raise_softirq_irqoff(HI_SOFTIRQ); | 602 | raise_softirq_irqoff(HI_SOFTIRQ); |
584 | 603 | ||
585 | local_irq_enable(); | 604 | local_irq_enable(); |