18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Oracle. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (C) 2014 Fujitsu. All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kthread.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/list.h> 108c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 118c2ecf20Sopenharmony_ci#include <linux/freezer.h> 128c2ecf20Sopenharmony_ci#include "async-thread.h" 138c2ecf20Sopenharmony_ci#include "ctree.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cienum { 168c2ecf20Sopenharmony_ci WORK_DONE_BIT, 178c2ecf20Sopenharmony_ci WORK_ORDER_DONE_BIT, 188c2ecf20Sopenharmony_ci WORK_HIGH_PRIO_BIT, 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define NO_THRESHOLD (-1) 228c2ecf20Sopenharmony_ci#define DFT_THRESHOLD (32) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct __btrfs_workqueue { 258c2ecf20Sopenharmony_ci struct workqueue_struct *normal_wq; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* File system this workqueue services */ 288c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* List head pointing to ordered work list */ 318c2ecf20Sopenharmony_ci struct list_head ordered_list; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* Spinlock for ordered_list */ 348c2ecf20Sopenharmony_ci spinlock_t list_lock; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* Thresholding related variants */ 378c2ecf20Sopenharmony_ci atomic_t pending; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* Up limit of concurrency workers */ 408c2ecf20Sopenharmony_ci int limit_active; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* Current number of concurrency workers */ 438c2ecf20Sopenharmony_ci int current_active; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* Threshold to change current_active */ 468c2ecf20Sopenharmony_ci int thresh; 478c2ecf20Sopenharmony_ci unsigned int count; 488c2ecf20Sopenharmony_ci spinlock_t thres_lock; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct btrfs_workqueue { 528c2ecf20Sopenharmony_ci struct __btrfs_workqueue *normal; 538c2ecf20Sopenharmony_ci struct __btrfs_workqueue *high; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct btrfs_fs_info * __pure btrfs_workqueue_owner(const struct __btrfs_workqueue *wq) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return wq->fs_info; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct btrfs_fs_info * __pure btrfs_work_owner(const struct btrfs_work *work) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return work->wq->fs_info; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cibool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci /* 698c2ecf20Sopenharmony_ci * We could compare wq->normal->pending with num_online_cpus() 708c2ecf20Sopenharmony_ci * to support "thresh == NO_THRESHOLD" case, but it requires 718c2ecf20Sopenharmony_ci * moving up atomic_inc/dec in thresh_queue/exec_hook. Let's 728c2ecf20Sopenharmony_ci * postpone it until someone needs the support of that case. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci if (wq->normal->thresh == NO_THRESHOLD) 758c2ecf20Sopenharmony_ci return false; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return atomic_read(&wq->normal->pending) > wq->normal->thresh * 2; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic struct __btrfs_workqueue * 818c2ecf20Sopenharmony_ci__btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, const char *name, 828c2ecf20Sopenharmony_ci unsigned int flags, int limit_active, int thresh) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!ret) 878c2ecf20Sopenharmony_ci return NULL; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ret->fs_info = fs_info; 908c2ecf20Sopenharmony_ci ret->limit_active = limit_active; 918c2ecf20Sopenharmony_ci atomic_set(&ret->pending, 0); 928c2ecf20Sopenharmony_ci if (thresh == 0) 938c2ecf20Sopenharmony_ci thresh = DFT_THRESHOLD; 948c2ecf20Sopenharmony_ci /* For low threshold, disabling threshold is a better choice */ 958c2ecf20Sopenharmony_ci if (thresh < DFT_THRESHOLD) { 968c2ecf20Sopenharmony_ci ret->current_active = limit_active; 978c2ecf20Sopenharmony_ci ret->thresh = NO_THRESHOLD; 988c2ecf20Sopenharmony_ci } else { 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * For threshold-able wq, let its concurrency grow on demand. 1018c2ecf20Sopenharmony_ci * Use minimal max_active at alloc time to reduce resource 1028c2ecf20Sopenharmony_ci * usage. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci ret->current_active = 1; 1058c2ecf20Sopenharmony_ci ret->thresh = thresh; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (flags & WQ_HIGHPRI) 1098c2ecf20Sopenharmony_ci ret->normal_wq = alloc_workqueue("btrfs-%s-high", flags, 1108c2ecf20Sopenharmony_ci ret->current_active, name); 1118c2ecf20Sopenharmony_ci else 1128c2ecf20Sopenharmony_ci ret->normal_wq = alloc_workqueue("btrfs-%s", flags, 1138c2ecf20Sopenharmony_ci ret->current_active, name); 1148c2ecf20Sopenharmony_ci if (!ret->normal_wq) { 1158c2ecf20Sopenharmony_ci kfree(ret); 1168c2ecf20Sopenharmony_ci return NULL; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ret->ordered_list); 1208c2ecf20Sopenharmony_ci spin_lock_init(&ret->list_lock); 1218c2ecf20Sopenharmony_ci spin_lock_init(&ret->thres_lock); 1228c2ecf20Sopenharmony_ci trace_btrfs_workqueue_alloc(ret, name, flags & WQ_HIGHPRI); 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic inline void 1278c2ecf20Sopenharmony_ci__btrfs_destroy_workqueue(struct __btrfs_workqueue *wq); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistruct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, 1308c2ecf20Sopenharmony_ci const char *name, 1318c2ecf20Sopenharmony_ci unsigned int flags, 1328c2ecf20Sopenharmony_ci int limit_active, 1338c2ecf20Sopenharmony_ci int thresh) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (!ret) 1388c2ecf20Sopenharmony_ci return NULL; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci ret->normal = __btrfs_alloc_workqueue(fs_info, name, 1418c2ecf20Sopenharmony_ci flags & ~WQ_HIGHPRI, 1428c2ecf20Sopenharmony_ci limit_active, thresh); 1438c2ecf20Sopenharmony_ci if (!ret->normal) { 1448c2ecf20Sopenharmony_ci kfree(ret); 1458c2ecf20Sopenharmony_ci return NULL; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (flags & WQ_HIGHPRI) { 1498c2ecf20Sopenharmony_ci ret->high = __btrfs_alloc_workqueue(fs_info, name, flags, 1508c2ecf20Sopenharmony_ci limit_active, thresh); 1518c2ecf20Sopenharmony_ci if (!ret->high) { 1528c2ecf20Sopenharmony_ci __btrfs_destroy_workqueue(ret->normal); 1538c2ecf20Sopenharmony_ci kfree(ret); 1548c2ecf20Sopenharmony_ci return NULL; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* 1618c2ecf20Sopenharmony_ci * Hook for threshold which will be called in btrfs_queue_work. 1628c2ecf20Sopenharmony_ci * This hook WILL be called in IRQ handler context, 1638c2ecf20Sopenharmony_ci * so workqueue_set_max_active MUST NOT be called in this hook 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_cistatic inline void thresh_queue_hook(struct __btrfs_workqueue *wq) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci if (wq->thresh == NO_THRESHOLD) 1688c2ecf20Sopenharmony_ci return; 1698c2ecf20Sopenharmony_ci atomic_inc(&wq->pending); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * Hook for threshold which will be called before executing the work, 1748c2ecf20Sopenharmony_ci * This hook is called in kthread content. 1758c2ecf20Sopenharmony_ci * So workqueue_set_max_active is called here. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_cistatic inline void thresh_exec_hook(struct __btrfs_workqueue *wq) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int new_current_active; 1808c2ecf20Sopenharmony_ci long pending; 1818c2ecf20Sopenharmony_ci int need_change = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (wq->thresh == NO_THRESHOLD) 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci atomic_dec(&wq->pending); 1878c2ecf20Sopenharmony_ci spin_lock(&wq->thres_lock); 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * Use wq->count to limit the calling frequency of 1908c2ecf20Sopenharmony_ci * workqueue_set_max_active. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci wq->count++; 1938c2ecf20Sopenharmony_ci wq->count %= (wq->thresh / 4); 1948c2ecf20Sopenharmony_ci if (!wq->count) 1958c2ecf20Sopenharmony_ci goto out; 1968c2ecf20Sopenharmony_ci new_current_active = wq->current_active; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * pending may be changed later, but it's OK since we really 2008c2ecf20Sopenharmony_ci * don't need it so accurate to calculate new_max_active. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci pending = atomic_read(&wq->pending); 2038c2ecf20Sopenharmony_ci if (pending > wq->thresh) 2048c2ecf20Sopenharmony_ci new_current_active++; 2058c2ecf20Sopenharmony_ci if (pending < wq->thresh / 2) 2068c2ecf20Sopenharmony_ci new_current_active--; 2078c2ecf20Sopenharmony_ci new_current_active = clamp_val(new_current_active, 1, wq->limit_active); 2088c2ecf20Sopenharmony_ci if (new_current_active != wq->current_active) { 2098c2ecf20Sopenharmony_ci need_change = 1; 2108c2ecf20Sopenharmony_ci wq->current_active = new_current_active; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ciout: 2138c2ecf20Sopenharmony_ci spin_unlock(&wq->thres_lock); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (need_change) { 2168c2ecf20Sopenharmony_ci workqueue_set_max_active(wq->normal_wq, wq->current_active); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void run_ordered_work(struct __btrfs_workqueue *wq, 2218c2ecf20Sopenharmony_ci struct btrfs_work *self) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct list_head *list = &wq->ordered_list; 2248c2ecf20Sopenharmony_ci struct btrfs_work *work; 2258c2ecf20Sopenharmony_ci spinlock_t *lock = &wq->list_lock; 2268c2ecf20Sopenharmony_ci unsigned long flags; 2278c2ecf20Sopenharmony_ci bool free_self = false; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci while (1) { 2308c2ecf20Sopenharmony_ci spin_lock_irqsave(lock, flags); 2318c2ecf20Sopenharmony_ci if (list_empty(list)) 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci work = list_entry(list->next, struct btrfs_work, 2348c2ecf20Sopenharmony_ci ordered_list); 2358c2ecf20Sopenharmony_ci if (!test_bit(WORK_DONE_BIT, &work->flags)) 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * Orders all subsequent loads after reading WORK_DONE_BIT, 2398c2ecf20Sopenharmony_ci * paired with the smp_mb__before_atomic in btrfs_work_helper 2408c2ecf20Sopenharmony_ci * this guarantees that the ordered function will see all 2418c2ecf20Sopenharmony_ci * updates from ordinary work function. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci smp_rmb(); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* 2468c2ecf20Sopenharmony_ci * we are going to call the ordered done function, but 2478c2ecf20Sopenharmony_ci * we leave the work item on the list as a barrier so 2488c2ecf20Sopenharmony_ci * that later work items that are done don't have their 2498c2ecf20Sopenharmony_ci * functions called before this one returns 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci trace_btrfs_ordered_sched(work); 2548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(lock, flags); 2558c2ecf20Sopenharmony_ci work->ordered_func(work); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* now take the lock again and drop our item from the list */ 2588c2ecf20Sopenharmony_ci spin_lock_irqsave(lock, flags); 2598c2ecf20Sopenharmony_ci list_del(&work->ordered_list); 2608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(lock, flags); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (work == self) { 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * This is the work item that the worker is currently 2658c2ecf20Sopenharmony_ci * executing. 2668c2ecf20Sopenharmony_ci * 2678c2ecf20Sopenharmony_ci * The kernel workqueue code guarantees non-reentrancy 2688c2ecf20Sopenharmony_ci * of work items. I.e., if a work item with the same 2698c2ecf20Sopenharmony_ci * address and work function is queued twice, the second 2708c2ecf20Sopenharmony_ci * execution is blocked until the first one finishes. A 2718c2ecf20Sopenharmony_ci * work item may be freed and recycled with the same 2728c2ecf20Sopenharmony_ci * work function; the workqueue code assumes that the 2738c2ecf20Sopenharmony_ci * original work item cannot depend on the recycled work 2748c2ecf20Sopenharmony_ci * item in that case (see find_worker_executing_work()). 2758c2ecf20Sopenharmony_ci * 2768c2ecf20Sopenharmony_ci * Note that different types of Btrfs work can depend on 2778c2ecf20Sopenharmony_ci * each other, and one type of work on one Btrfs 2788c2ecf20Sopenharmony_ci * filesystem may even depend on the same type of work 2798c2ecf20Sopenharmony_ci * on another Btrfs filesystem via, e.g., a loop device. 2808c2ecf20Sopenharmony_ci * Therefore, we must not allow the current work item to 2818c2ecf20Sopenharmony_ci * be recycled until we are really done, otherwise we 2828c2ecf20Sopenharmony_ci * break the above assumption and can deadlock. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci free_self = true; 2858c2ecf20Sopenharmony_ci } else { 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * We don't want to call the ordered free functions with 2888c2ecf20Sopenharmony_ci * the lock held. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci work->ordered_free(work); 2918c2ecf20Sopenharmony_ci /* NB: work must not be dereferenced past this point. */ 2928c2ecf20Sopenharmony_ci trace_btrfs_all_work_done(wq->fs_info, work); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(lock, flags); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (free_self) { 2988c2ecf20Sopenharmony_ci self->ordered_free(self); 2998c2ecf20Sopenharmony_ci /* NB: self must not be dereferenced past this point. */ 3008c2ecf20Sopenharmony_ci trace_btrfs_all_work_done(wq->fs_info, self); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void btrfs_work_helper(struct work_struct *normal_work) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct btrfs_work *work = container_of(normal_work, struct btrfs_work, 3078c2ecf20Sopenharmony_ci normal_work); 3088c2ecf20Sopenharmony_ci struct __btrfs_workqueue *wq; 3098c2ecf20Sopenharmony_ci int need_order = 0; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * We should not touch things inside work in the following cases: 3138c2ecf20Sopenharmony_ci * 1) after work->func() if it has no ordered_free 3148c2ecf20Sopenharmony_ci * Since the struct is freed in work->func(). 3158c2ecf20Sopenharmony_ci * 2) after setting WORK_DONE_BIT 3168c2ecf20Sopenharmony_ci * The work may be freed in other threads almost instantly. 3178c2ecf20Sopenharmony_ci * So we save the needed things here. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_ci if (work->ordered_func) 3208c2ecf20Sopenharmony_ci need_order = 1; 3218c2ecf20Sopenharmony_ci wq = work->wq; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci trace_btrfs_work_sched(work); 3248c2ecf20Sopenharmony_ci thresh_exec_hook(wq); 3258c2ecf20Sopenharmony_ci work->func(work); 3268c2ecf20Sopenharmony_ci if (need_order) { 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * Ensures all memory accesses done in the work function are 3298c2ecf20Sopenharmony_ci * ordered before setting the WORK_DONE_BIT. Ensuring the thread 3308c2ecf20Sopenharmony_ci * which is going to executed the ordered work sees them. 3318c2ecf20Sopenharmony_ci * Pairs with the smp_rmb in run_ordered_work. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 3348c2ecf20Sopenharmony_ci set_bit(WORK_DONE_BIT, &work->flags); 3358c2ecf20Sopenharmony_ci run_ordered_work(wq, work); 3368c2ecf20Sopenharmony_ci } else { 3378c2ecf20Sopenharmony_ci /* NB: work must not be dereferenced past this point. */ 3388c2ecf20Sopenharmony_ci trace_btrfs_all_work_done(wq->fs_info, work); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_civoid btrfs_init_work(struct btrfs_work *work, btrfs_func_t func, 3438c2ecf20Sopenharmony_ci btrfs_func_t ordered_func, btrfs_func_t ordered_free) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci work->func = func; 3468c2ecf20Sopenharmony_ci work->ordered_func = ordered_func; 3478c2ecf20Sopenharmony_ci work->ordered_free = ordered_free; 3488c2ecf20Sopenharmony_ci INIT_WORK(&work->normal_work, btrfs_work_helper); 3498c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&work->ordered_list); 3508c2ecf20Sopenharmony_ci work->flags = 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic inline void __btrfs_queue_work(struct __btrfs_workqueue *wq, 3548c2ecf20Sopenharmony_ci struct btrfs_work *work) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci unsigned long flags; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci work->wq = wq; 3598c2ecf20Sopenharmony_ci thresh_queue_hook(wq); 3608c2ecf20Sopenharmony_ci if (work->ordered_func) { 3618c2ecf20Sopenharmony_ci spin_lock_irqsave(&wq->list_lock, flags); 3628c2ecf20Sopenharmony_ci list_add_tail(&work->ordered_list, &wq->ordered_list); 3638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wq->list_lock, flags); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci trace_btrfs_work_queued(work); 3668c2ecf20Sopenharmony_ci queue_work(wq->normal_wq, &work->normal_work); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_civoid btrfs_queue_work(struct btrfs_workqueue *wq, 3708c2ecf20Sopenharmony_ci struct btrfs_work *work) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct __btrfs_workqueue *dest_wq; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags) && wq->high) 3758c2ecf20Sopenharmony_ci dest_wq = wq->high; 3768c2ecf20Sopenharmony_ci else 3778c2ecf20Sopenharmony_ci dest_wq = wq->normal; 3788c2ecf20Sopenharmony_ci __btrfs_queue_work(dest_wq, work); 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic inline void 3828c2ecf20Sopenharmony_ci__btrfs_destroy_workqueue(struct __btrfs_workqueue *wq) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci destroy_workqueue(wq->normal_wq); 3858c2ecf20Sopenharmony_ci trace_btrfs_workqueue_destroy(wq); 3868c2ecf20Sopenharmony_ci kfree(wq); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_civoid btrfs_destroy_workqueue(struct btrfs_workqueue *wq) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci if (!wq) 3928c2ecf20Sopenharmony_ci return; 3938c2ecf20Sopenharmony_ci if (wq->high) 3948c2ecf20Sopenharmony_ci __btrfs_destroy_workqueue(wq->high); 3958c2ecf20Sopenharmony_ci __btrfs_destroy_workqueue(wq->normal); 3968c2ecf20Sopenharmony_ci kfree(wq); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_civoid btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int limit_active) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci if (!wq) 4028c2ecf20Sopenharmony_ci return; 4038c2ecf20Sopenharmony_ci wq->normal->limit_active = limit_active; 4048c2ecf20Sopenharmony_ci if (wq->high) 4058c2ecf20Sopenharmony_ci wq->high->limit_active = limit_active; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_civoid btrfs_set_work_high_priority(struct btrfs_work *work) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci set_bit(WORK_HIGH_PRIO_BIT, &work->flags); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_civoid btrfs_flush_workqueue(struct btrfs_workqueue *wq) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci if (wq->high) 4168c2ecf20Sopenharmony_ci flush_workqueue(wq->high->normal_wq); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci flush_workqueue(wq->normal->normal_wq); 4198c2ecf20Sopenharmony_ci} 420