Pull workqueue updates from Tejun Heo: "rcu_work addition and a couple trivial changes" * 'for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: workqueue: remove the comment about the old manager_arb mutex workqueue: fix the comments of nr_idle fs/aio: Use rcu_work instead of explicit rcu and work item cgroup: Use rcu_work instead of explicit rcu and work item RCU, workqueue: Implement rcu_work
Showing the changes to kernel/workqueue.c (1 of 5 files). Show all
Unified · Split
| @@ -153,10 +153,9 @@ struct worker_pool { · 152 unmodified lines | ||
| 153 | 153 | unsigned long watchdog_ts; /* L: watchdog timestamp */ |
| 154 | 154 | |
| 155 | 155 | struct list_head worklist; /* L: list of pending works */ |
| 156 | − int nr_workers; /* L: total number of workers */ | |
| 157 | 156 | |
| 158 | − /* nr_idle includes the ones off idle_list for rebinding */ | |
| 159 | − int nr_idle; /* L: currently idle ones */ | |
| 157 | + int nr_workers; /* L: total number of workers */ | |
| 158 | + int nr_idle; /* L: currently idle workers */ | |
| 160 | 159 | |
| 161 | 160 | struct list_head idle_list; /* X: list of idle workers */ |
| 162 | 161 | struct timer_list idle_timer; /* L: worker idle timeout */ |
| @@ -166,7 +165,6 @@ struct worker_pool { · 3 unmodified lines | ||
| 166 | 165 | DECLARE_HASHTABLE(busy_hash, BUSY_WORKER_HASH_ORDER); |
| 167 | 166 | /* L: hash of busy workers */ |
| 168 | 167 | |
| 169 | − /* see manage_workers() for details on the two manager mutexes */ | |
| 170 | 168 | struct worker *manager; /* L: purely informational */ |
| 171 | 169 | struct mutex attach_mutex; /* attach/detach exclusion */ |
| 172 | 170 | struct list_head workers; /* A: attached workers */ |
| @@ -1604,6 +1602,40 @@ bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq, · 1431 unmodified lines | ||
| 1604 | 1602 | } |
| 1605 | 1603 | EXPORT_SYMBOL_GPL(mod_delayed_work_on); |
| 1606 | 1604 | |
| 1605 | +static void rcu_work_rcufn(struct rcu_head *rcu) | |
| 1606 | +{ | |
| 1607 | + struct rcu_work *rwork = container_of(rcu, struct rcu_work, rcu); | |
| 1608 | + | |
| 1609 | + /* read the comment in __queue_work() */ | |
| 1610 | + local_irq_disable(); | |
| 1611 | + __queue_work(WORK_CPU_UNBOUND, rwork->wq, &rwork->work); | |
| 1612 | + local_irq_enable(); | |
| 1613 | +} | |
| 1614 | + | |
| 1615 | +/** | |
| 1616 | + * queue_rcu_work - queue work after a RCU grace period | |
| 1617 | + * @wq: workqueue to use | |
| 1618 | + * @rwork: work to queue | |
| 1619 | + * | |
| 1620 | + * Return: %false if @rwork was already pending, %true otherwise. Note | |
| 1621 | + * that a full RCU grace period is guaranteed only after a %true return. | |
| 1622 | + * While @rwork is guarnateed to be executed after a %false return, the | |
| 1623 | + * execution may happen before a full RCU grace period has passed. | |
| 1624 | + */ | |
| 1625 | +bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork) | |
| 1626 | +{ | |
| 1627 | + struct work_struct *work = &rwork->work; | |
| 1628 | + | |
| 1629 | + if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) { | |
| 1630 | + rwork->wq = wq; | |
| 1631 | + call_rcu(&rwork->rcu, rcu_work_rcufn); | |
| 1632 | + return true; | |
| 1633 | + } | |
| 1634 | + | |
| 1635 | + return false; | |
| 1636 | +} | |
| 1637 | +EXPORT_SYMBOL(queue_rcu_work); | |
| 1638 | + | |
| 1607 | 1639 | /** |
| 1608 | 1640 | * worker_enter_idle - enter idle state |
| 1609 | 1641 | * @worker: worker which is entering idle state |
| @@ -3001,6 +3033,26 @@ bool flush_delayed_work(struct delayed_work *dwork) · 1391 unmodified lines | ||
| 3001 | 3033 | } |
| 3002 | 3034 | EXPORT_SYMBOL(flush_delayed_work); |
| 3003 | 3035 | |
| 3036 | +/** | |
| 3037 | + * flush_rcu_work - wait for a rwork to finish executing the last queueing | |
| 3038 | + * @rwork: the rcu work to flush | |
| 3039 | + * | |
| 3040 | + * Return: | |
| 3041 | + * %true if flush_rcu_work() waited for the work to finish execution, | |
| 3042 | + * %false if it was already idle. | |
| 3043 | + */ | |
| 3044 | +bool flush_rcu_work(struct rcu_work *rwork) | |
| 3045 | +{ | |
| 3046 | + if (test_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&rwork->work))) { | |
| 3047 | + rcu_barrier(); | |
| 3048 | + flush_work(&rwork->work); | |
| 3049 | + return true; | |
| 3050 | + } else { | |
| 3051 | + return flush_work(&rwork->work); | |
| 3052 | + } | |
| 3053 | +} | |
| 3054 | +EXPORT_SYMBOL(flush_rcu_work); | |
| 3055 | + | |
| 3004 | 3056 | static bool __cancel_work(struct work_struct *work, bool is_dwork) |
| 3005 | 3057 | { |
| 3006 | 3058 | unsigned long flags; |