diff options
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 362b50d092e2..a2dccfca03ba 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -941,6 +941,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, | |||
941 | struct global_cwq *gcwq; | 941 | struct global_cwq *gcwq; |
942 | struct cpu_workqueue_struct *cwq; | 942 | struct cpu_workqueue_struct *cwq; |
943 | struct list_head *worklist; | 943 | struct list_head *worklist; |
944 | unsigned int work_flags; | ||
944 | unsigned long flags; | 945 | unsigned long flags; |
945 | 946 | ||
946 | debug_work_activate(work); | 947 | debug_work_activate(work); |
@@ -990,14 +991,17 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, | |||
990 | BUG_ON(!list_empty(&work->entry)); | 991 | BUG_ON(!list_empty(&work->entry)); |
991 | 992 | ||
992 | cwq->nr_in_flight[cwq->work_color]++; | 993 | cwq->nr_in_flight[cwq->work_color]++; |
994 | work_flags = work_color_to_flags(cwq->work_color); | ||
993 | 995 | ||
994 | if (likely(cwq->nr_active < cwq->max_active)) { | 996 | if (likely(cwq->nr_active < cwq->max_active)) { |
995 | cwq->nr_active++; | 997 | cwq->nr_active++; |
996 | worklist = gcwq_determine_ins_pos(gcwq, cwq); | 998 | worklist = gcwq_determine_ins_pos(gcwq, cwq); |
997 | } else | 999 | } else { |
1000 | work_flags |= WORK_STRUCT_DELAYED; | ||
998 | worklist = &cwq->delayed_works; | 1001 | worklist = &cwq->delayed_works; |
1002 | } | ||
999 | 1003 | ||
1000 | insert_work(cwq, work, worklist, work_color_to_flags(cwq->work_color)); | 1004 | insert_work(cwq, work, worklist, work_flags); |
1001 | 1005 | ||
1002 | spin_unlock_irqrestore(&gcwq->lock, flags); | 1006 | spin_unlock_irqrestore(&gcwq->lock, flags); |
1003 | } | 1007 | } |
@@ -1666,6 +1670,7 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) | |||
1666 | struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq); | 1670 | struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq); |
1667 | 1671 | ||
1668 | move_linked_works(work, pos, NULL); | 1672 | move_linked_works(work, pos, NULL); |
1673 | __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work)); | ||
1669 | cwq->nr_active++; | 1674 | cwq->nr_active++; |
1670 | } | 1675 | } |
1671 | 1676 | ||
@@ -1673,6 +1678,7 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) | |||
1673 | * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight | 1678 | * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight |
1674 | * @cwq: cwq of interest | 1679 | * @cwq: cwq of interest |
1675 | * @color: color of work which left the queue | 1680 | * @color: color of work which left the queue |
1681 | * @delayed: for a delayed work | ||
1676 | * | 1682 | * |
1677 | * A work either has completed or is removed from pending queue, | 1683 | * A work either has completed or is removed from pending queue, |
1678 | * decrement nr_in_flight of its cwq and handle workqueue flushing. | 1684 | * decrement nr_in_flight of its cwq and handle workqueue flushing. |
@@ -1680,19 +1686,22 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) | |||
1680 | * CONTEXT: | 1686 | * CONTEXT: |
1681 | * spin_lock_irq(gcwq->lock). | 1687 | * spin_lock_irq(gcwq->lock). |
1682 | */ | 1688 | */ |
1683 | static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color) | 1689 | static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color, |
1690 | bool delayed) | ||
1684 | { | 1691 | { |
1685 | /* ignore uncolored works */ | 1692 | /* ignore uncolored works */ |
1686 | if (color == WORK_NO_COLOR) | 1693 | if (color == WORK_NO_COLOR) |
1687 | return; | 1694 | return; |
1688 | 1695 | ||
1689 | cwq->nr_in_flight[color]--; | 1696 | cwq->nr_in_flight[color]--; |
1690 | cwq->nr_active--; | ||
1691 | 1697 | ||
1692 | if (!list_empty(&cwq->delayed_works)) { | 1698 | if (!delayed) { |
1693 | /* one down, submit a delayed one */ | 1699 | cwq->nr_active--; |
1694 | if (cwq->nr_active < cwq->max_active) | 1700 | if (!list_empty(&cwq->delayed_works)) { |
1695 | cwq_activate_first_delayed(cwq); | 1701 | /* one down, submit a delayed one */ |
1702 | if (cwq->nr_active < cwq->max_active) | ||
1703 | cwq_activate_first_delayed(cwq); | ||
1704 | } | ||
1696 | } | 1705 | } |
1697 | 1706 | ||
1698 | /* is flush in progress and are we at the flushing tip? */ | 1707 | /* is flush in progress and are we at the flushing tip? */ |
@@ -1823,7 +1832,7 @@ __acquires(&gcwq->lock) | |||
1823 | hlist_del_init(&worker->hentry); | 1832 | hlist_del_init(&worker->hentry); |
1824 | worker->current_work = NULL; | 1833 | worker->current_work = NULL; |
1825 | worker->current_cwq = NULL; | 1834 | worker->current_cwq = NULL; |
1826 | cwq_dec_nr_in_flight(cwq, work_color); | 1835 | cwq_dec_nr_in_flight(cwq, work_color, false); |
1827 | } | 1836 | } |
1828 | 1837 | ||
1829 | /** | 1838 | /** |
@@ -2388,7 +2397,8 @@ static int try_to_grab_pending(struct work_struct *work) | |||
2388 | debug_work_deactivate(work); | 2397 | debug_work_deactivate(work); |
2389 | list_del_init(&work->entry); | 2398 | list_del_init(&work->entry); |
2390 | cwq_dec_nr_in_flight(get_work_cwq(work), | 2399 | cwq_dec_nr_in_flight(get_work_cwq(work), |
2391 | get_work_color(work)); | 2400 | get_work_color(work), |
2401 | *work_data_bits(work) & WORK_STRUCT_DELAYED); | ||
2392 | ret = 1; | 2402 | ret = 1; |
2393 | } | 2403 | } |
2394 | } | 2404 | } |