Rename pwq_set_max_active() to pwq_adjust_max_active() and move pool_workqueue->max_active synchronization and max_active determination logic into it. The new function should be called with workqueue_lock held for stable workqueue->saved_max_active, determines the current max_active value the target pool_workqueue should be using from @wq->saved_max_active and the state of the associated pool, and applies it with proper synchronization. The current two users - workqueue_set_max_active() and thaw_workqueues() - are updated accordingly. In addition, the manual freezing handling in __alloc_workqueue_key() and freeze_workqueues_begin() are replaced with calls to pwq_adjust_max_active(). This centralizes max_active handling so that it's less error-prone.
Showing the changes to kernel/workqueue.c (1 of 1 file). Show all
Unified · Split
| @@ -3726,23 +3726,38 @@ static void pwq_unbound_release_workfn(struct work_struct *work) · 3725 unmodified lines | ||
| 3726 | 3726 | } |
| 3727 | 3727 | |
| 3728 | 3728 | /** |
| 3729 | − * pwq_set_max_active - adjust max_active of a pwq | |
| 3729 | + * pwq_adjust_max_active - update a pwq's max_active to the current setting | |
| 3730 | 3730 | * @pwq: target pool_workqueue |
| 3731 | − * @max_active: new max_active value. | |
| 3732 | − * | |
| 3733 | − * Set @pwq->max_active to @max_active and activate delayed works if | |
| 3734 | − * increased. | |
| 3735 | 3731 | * |
| 3736 | − * CONTEXT: | |
| 3737 | − * spin_lock_irq(pool->lock). | |
| 3732 | + * If @pwq isn't freezing, set @pwq->max_active to the associated | |
| 3733 | + * workqueue's saved_max_active and activate delayed work items | |
| 3734 | + * accordingly. If @pwq is freezing, clear @pwq->max_active to zero. | |
| 3738 | 3735 | */ |
| 3739 | −static void pwq_set_max_active(struct pool_workqueue *pwq, int max_active) | |
| 3736 | +static void pwq_adjust_max_active(struct pool_workqueue *pwq) | |
| 3740 | 3737 | { |
| 3741 | − pwq->max_active = max_active; | |
| 3738 | + struct workqueue_struct *wq = pwq->wq; | |
| 3739 | + bool freezable = wq->flags & WQ_FREEZABLE; | |
| 3740 | + | |
| 3741 | + /* for @wq->saved_max_active */ | |
| 3742 | + lockdep_assert_held(&workqueue_lock); | |
| 3743 | + | |
| 3744 | + /* fast exit for non-freezable wqs */ | |
| 3745 | + if (!freezable && pwq->max_active == wq->saved_max_active) | |
| 3746 | + return; | |
| 3747 | + | |
| 3748 | + spin_lock(&pwq->pool->lock); | |
| 3749 | + | |
| 3750 | + if (!freezable || !(pwq->pool->flags & POOL_FREEZING)) { | |
| 3751 | + pwq->max_active = wq->saved_max_active; | |
| 3742 | 3752 | |
| 3743 | − while (!list_empty(&pwq->delayed_works) && | |
| 3744 | − pwq->nr_active < pwq->max_active) | |
| 3745 | − pwq_activate_first_delayed(pwq); | |
| 3753 | + while (!list_empty(&pwq->delayed_works) && | |
| 3754 | + pwq->nr_active < pwq->max_active) | |
| 3755 | + pwq_activate_first_delayed(pwq); | |
| 3756 | + } else { | |
| 3757 | + pwq->max_active = 0; | |
| 3758 | + } | |
| 3759 | + | |
| 3760 | + spin_unlock(&pwq->pool->lock); | |
| 3746 | 3761 | } |
| 3747 | 3762 | |
| 3748 | 3763 | static void init_and_link_pwq(struct pool_workqueue *pwq, |
| @@ -3932,15 +3947,14 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, · 183 unmodified lines | ||
| 3932 | 3947 | goto err_destroy; |
| 3933 | 3948 | |
| 3934 | 3949 | /* |
| 3935 | − * workqueue_lock protects global freeze state and workqueues | |
| 3936 | − * list. Grab it, set max_active accordingly and add the new | |
| 3937 | − * workqueue to workqueues list. | |
| 3950 | + * workqueue_lock protects global freeze state and workqueues list. | |
| 3951 | + * Grab it, adjust max_active and add the new workqueue to | |
| 3952 | + * workqueues list. | |
| 3938 | 3953 | */ |
| 3939 | 3954 | spin_lock_irq(&workqueue_lock); |
| 3940 | 3955 | |
| 3941 | − if (workqueue_freezing && wq->flags & WQ_FREEZABLE) | |
| 3942 | − for_each_pwq(pwq, wq) | |
| 3943 | − pwq->max_active = 0; | |
| 3956 | + for_each_pwq(pwq, wq) | |
| 3957 | + pwq_adjust_max_active(pwq); | |
| 3944 | 3958 | |
| 3945 | 3959 | list_add(&wq->list, &workqueues); |
| 3946 | 3960 | |
| @@ -4055,17 +4069,8 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) · 108 unmodified lines | ||
| 4055 | 4069 | |
| 4056 | 4070 | wq->saved_max_active = max_active; |
| 4057 | 4071 | |
| 4058 | − for_each_pwq(pwq, wq) { | |
| 4059 | − struct worker_pool *pool = pwq->pool; | |
| 4060 | − | |
| 4061 | − spin_lock(&pool->lock); | |
| 4062 | − | |
| 4063 | − if (!(wq->flags & WQ_FREEZABLE) || | |
| 4064 | − !(pool->flags & POOL_FREEZING)) | |
| 4065 | − pwq_set_max_active(pwq, max_active); | |
| 4066 | − | |
| 4067 | − spin_unlock(&pool->lock); | |
| 4068 | − } | |
| 4072 | + for_each_pwq(pwq, wq) | |
| 4073 | + pwq_adjust_max_active(pwq); | |
| 4069 | 4074 | |
| 4070 | 4075 | spin_unlock_irq(&workqueue_lock); |
| 4071 | 4076 | } |
| @@ -4358,14 +4363,8 @@ void freeze_workqueues_begin(void) · 286 unmodified lines | ||
| 4358 | 4363 | |
| 4359 | 4364 | /* suppress further executions by setting max_active to zero */ |
| 4360 | 4365 | list_for_each_entry(wq, &workqueues, list) { |
| 4361 | − if (!(wq->flags & WQ_FREEZABLE)) | |
| 4362 | − continue; | |
| 4363 | − | |
| 4364 | − for_each_pwq(pwq, wq) { | |
| 4365 | − spin_lock(&pwq->pool->lock); | |
| 4366 | − pwq->max_active = 0; | |
| 4367 | − spin_unlock(&pwq->pool->lock); | |
| 4368 | − } | |
| 4366 | + for_each_pwq(pwq, wq) | |
| 4367 | + pwq_adjust_max_active(pwq); | |
| 4369 | 4368 | } |
| 4370 | 4369 | |
| 4371 | 4370 | spin_unlock_irq(&workqueue_lock); |
| @@ -4445,14 +4444,8 @@ void thaw_workqueues(void) · 73 unmodified lines | ||
| 4445 | 4444 | |
| 4446 | 4445 | /* restore max_active and repopulate worklist */ |
| 4447 | 4446 | list_for_each_entry(wq, &workqueues, list) { |
| 4448 | − if (!(wq->flags & WQ_FREEZABLE)) | |
| 4449 | − continue; | |
| 4450 | − | |
| 4451 | − for_each_pwq(pwq, wq) { | |
| 4452 | − spin_lock(&pwq->pool->lock); | |
| 4453 | − pwq_set_max_active(pwq, wq->saved_max_active); | |
| 4454 | − spin_unlock(&pwq->pool->lock); | |
| 4455 | − } | |
| 4447 | + for_each_pwq(pwq, wq) | |
| 4448 | + pwq_adjust_max_active(pwq); | |
| 4456 | 4449 | } |
| 4457 | 4450 | |
| 4458 | 4451 | /* kick workers */ |