aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/workqueue.h16
-rw-r--r--kernel/workqueue.c30
2 files changed, 29 insertions, 17 deletions
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index c959666eafca..f11100f96482 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -25,18 +25,20 @@ typedef void (*work_func_t)(struct work_struct *work);
25 25
26enum { 26enum {
27 WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */ 27 WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */
28 WORK_STRUCT_CWQ_BIT = 1, /* data points to cwq */ 28 WORK_STRUCT_DELAYED_BIT = 1, /* work item is delayed */
29 WORK_STRUCT_LINKED_BIT = 2, /* next work is linked to this one */ 29 WORK_STRUCT_CWQ_BIT = 2, /* data points to cwq */
30 WORK_STRUCT_LINKED_BIT = 3, /* next work is linked to this one */
30#ifdef CONFIG_DEBUG_OBJECTS_WORK 31#ifdef CONFIG_DEBUG_OBJECTS_WORK
31 WORK_STRUCT_STATIC_BIT = 3, /* static initializer (debugobjects) */ 32 WORK_STRUCT_STATIC_BIT = 4, /* static initializer (debugobjects) */
32 WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */ 33 WORK_STRUCT_COLOR_SHIFT = 5, /* color for workqueue flushing */
33#else 34#else
34 WORK_STRUCT_COLOR_SHIFT = 3, /* color for workqueue flushing */ 35 WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */
35#endif 36#endif
36 37
37 WORK_STRUCT_COLOR_BITS = 4, 38 WORK_STRUCT_COLOR_BITS = 4,
38 39
39 WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT, 40 WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT,
41 WORK_STRUCT_DELAYED = 1 << WORK_STRUCT_DELAYED_BIT,
40 WORK_STRUCT_CWQ = 1 << WORK_STRUCT_CWQ_BIT, 42 WORK_STRUCT_CWQ = 1 << WORK_STRUCT_CWQ_BIT,
41 WORK_STRUCT_LINKED = 1 << WORK_STRUCT_LINKED_BIT, 43 WORK_STRUCT_LINKED = 1 << WORK_STRUCT_LINKED_BIT,
42#ifdef CONFIG_DEBUG_OBJECTS_WORK 44#ifdef CONFIG_DEBUG_OBJECTS_WORK
@@ -59,8 +61,8 @@ enum {
59 61
60 /* 62 /*
61 * Reserve 7 bits off of cwq pointer w/ debugobjects turned 63 * Reserve 7 bits off of cwq pointer w/ debugobjects turned
62 * off. This makes cwqs aligned to 128 bytes which isn't too 64 * off. This makes cwqs aligned to 256 bytes and allows 15
63 * excessive while allowing 15 workqueue flush colors. 65 * workqueue flush colors.
64 */ 66 */
65 WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT + 67 WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT +
66 WORK_STRUCT_COLOR_BITS, 68 WORK_STRUCT_COLOR_BITS,
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 */
1683static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color) 1689static 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 }