1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0 28b712842SChris Mason /* 38b712842SChris Mason * Copyright (C) 2007 Oracle. All rights reserved. 408a9ff32SQu Wenruo * Copyright (C) 2014 Fujitsu. All rights reserved. 58b712842SChris Mason */ 68b712842SChris Mason 78b712842SChris Mason #include <linux/kthread.h> 85a0e3ad6STejun Heo #include <linux/slab.h> 98b712842SChris Mason #include <linux/list.h> 108b712842SChris Mason #include <linux/spinlock.h> 118b712842SChris Mason #include <linux/freezer.h> 128b712842SChris Mason #include "async-thread.h" 1352483bc2SQu Wenruo #include "ctree.h" 148b712842SChris Mason 15f64ce7b8SDavid Sterba enum { 16f64ce7b8SDavid Sterba WORK_DONE_BIT, 17f64ce7b8SDavid Sterba WORK_ORDER_DONE_BIT, 18f64ce7b8SDavid Sterba WORK_HIGH_PRIO_BIT, 19f64ce7b8SDavid Sterba }; 204a69a410SChris Mason 210bd9289cSQu Wenruo #define NO_THRESHOLD (-1) 220bd9289cSQu Wenruo #define DFT_THRESHOLD (32) 230bd9289cSQu Wenruo 24d458b054SQu Wenruo struct __btrfs_workqueue { 2508a9ff32SQu Wenruo struct workqueue_struct *normal_wq; 26cb001095SJeff Mahoney 27cb001095SJeff Mahoney /* File system this workqueue services */ 28cb001095SJeff Mahoney struct btrfs_fs_info *fs_info; 29cb001095SJeff Mahoney 3008a9ff32SQu Wenruo /* List head pointing to ordered work list */ 3108a9ff32SQu Wenruo struct list_head ordered_list; 3208a9ff32SQu Wenruo 3308a9ff32SQu Wenruo /* Spinlock for ordered_list */ 3408a9ff32SQu Wenruo spinlock_t list_lock; 350bd9289cSQu Wenruo 360bd9289cSQu Wenruo /* Thresholding related variants */ 370bd9289cSQu Wenruo atomic_t pending; 38c6dd6ea5SQu Wenruo 39c6dd6ea5SQu Wenruo /* Up limit of concurrency workers */ 40c6dd6ea5SQu Wenruo int limit_active; 41c6dd6ea5SQu Wenruo 42c6dd6ea5SQu Wenruo /* Current number of concurrency workers */ 43c6dd6ea5SQu Wenruo int current_active; 44c6dd6ea5SQu Wenruo 45c6dd6ea5SQu Wenruo /* Threshold to change current_active */ 460bd9289cSQu Wenruo int thresh; 470bd9289cSQu Wenruo unsigned int count; 480bd9289cSQu Wenruo spinlock_t thres_lock; 4908a9ff32SQu Wenruo }; 5008a9ff32SQu Wenruo 51d458b054SQu Wenruo struct btrfs_workqueue { 52d458b054SQu Wenruo struct __btrfs_workqueue *normal; 53d458b054SQu Wenruo struct __btrfs_workqueue *high; 541ca08976SQu Wenruo }; 551ca08976SQu Wenruo 569e0af237SLiu Bo static void normal_work_helper(struct btrfs_work *work); 579e0af237SLiu Bo 589e0af237SLiu Bo #define BTRFS_WORK_HELPER(name) \ 596939f667SLiu Bo noinline_for_stack void btrfs_##name(struct work_struct *arg) \ 609e0af237SLiu Bo { \ 619e0af237SLiu Bo struct btrfs_work *work = container_of(arg, struct btrfs_work, \ 629e0af237SLiu Bo normal_work); \ 639e0af237SLiu Bo normal_work_helper(work); \ 649e0af237SLiu Bo } 659e0af237SLiu Bo 66cb001095SJeff Mahoney struct btrfs_fs_info * 679a35b637SJeff Mahoney btrfs_workqueue_owner(const struct __btrfs_workqueue *wq) 68cb001095SJeff Mahoney { 69cb001095SJeff Mahoney return wq->fs_info; 70cb001095SJeff Mahoney } 71cb001095SJeff Mahoney 72cb001095SJeff Mahoney struct btrfs_fs_info * 739a35b637SJeff Mahoney btrfs_work_owner(const struct btrfs_work *work) 74cb001095SJeff Mahoney { 75cb001095SJeff Mahoney return work->wq->fs_info; 76cb001095SJeff Mahoney } 77cb001095SJeff Mahoney 789a35b637SJeff Mahoney bool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq) 792939e1a8SMaxim Patlasov { 802939e1a8SMaxim Patlasov /* 812939e1a8SMaxim Patlasov * We could compare wq->normal->pending with num_online_cpus() 822939e1a8SMaxim Patlasov * to support "thresh == NO_THRESHOLD" case, but it requires 832939e1a8SMaxim Patlasov * moving up atomic_inc/dec in thresh_queue/exec_hook. Let's 842939e1a8SMaxim Patlasov * postpone it until someone needs the support of that case. 852939e1a8SMaxim Patlasov */ 862939e1a8SMaxim Patlasov if (wq->normal->thresh == NO_THRESHOLD) 872939e1a8SMaxim Patlasov return false; 882939e1a8SMaxim Patlasov 892939e1a8SMaxim Patlasov return atomic_read(&wq->normal->pending) > wq->normal->thresh * 2; 902939e1a8SMaxim Patlasov } 912939e1a8SMaxim Patlasov 929e0af237SLiu Bo BTRFS_WORK_HELPER(worker_helper); 939e0af237SLiu Bo BTRFS_WORK_HELPER(delalloc_helper); 949e0af237SLiu Bo BTRFS_WORK_HELPER(flush_delalloc_helper); 959e0af237SLiu Bo BTRFS_WORK_HELPER(cache_helper); 969e0af237SLiu Bo BTRFS_WORK_HELPER(submit_helper); 979e0af237SLiu Bo BTRFS_WORK_HELPER(fixup_helper); 989e0af237SLiu Bo BTRFS_WORK_HELPER(endio_helper); 999e0af237SLiu Bo BTRFS_WORK_HELPER(endio_meta_helper); 1009e0af237SLiu Bo BTRFS_WORK_HELPER(endio_meta_write_helper); 1019e0af237SLiu Bo BTRFS_WORK_HELPER(endio_raid56_helper); 1028b110e39SMiao Xie BTRFS_WORK_HELPER(endio_repair_helper); 1039e0af237SLiu Bo BTRFS_WORK_HELPER(rmw_helper); 1049e0af237SLiu Bo BTRFS_WORK_HELPER(endio_write_helper); 1059e0af237SLiu Bo BTRFS_WORK_HELPER(freespace_write_helper); 1069e0af237SLiu Bo BTRFS_WORK_HELPER(delayed_meta_helper); 1079e0af237SLiu Bo BTRFS_WORK_HELPER(readahead_helper); 1089e0af237SLiu Bo BTRFS_WORK_HELPER(qgroup_rescan_helper); 1099e0af237SLiu Bo BTRFS_WORK_HELPER(extent_refs_helper); 1109e0af237SLiu Bo BTRFS_WORK_HELPER(scrub_helper); 1119e0af237SLiu Bo BTRFS_WORK_HELPER(scrubwrc_helper); 1129e0af237SLiu Bo BTRFS_WORK_HELPER(scrubnc_helper); 11320b2e302SZhao Lei BTRFS_WORK_HELPER(scrubparity_helper); 1149e0af237SLiu Bo 1159e0af237SLiu Bo static struct __btrfs_workqueue * 116cb001095SJeff Mahoney __btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, const char *name, 117cb001095SJeff Mahoney unsigned int flags, int limit_active, int thresh) 11808a9ff32SQu Wenruo { 11961dd5ae6SDavid Sterba struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL); 12008a9ff32SQu Wenruo 1215d99a998SDavid Sterba if (!ret) 12208a9ff32SQu Wenruo return NULL; 12308a9ff32SQu Wenruo 124cb001095SJeff Mahoney ret->fs_info = fs_info; 125c6dd6ea5SQu Wenruo ret->limit_active = limit_active; 1260bd9289cSQu Wenruo atomic_set(&ret->pending, 0); 1270bd9289cSQu Wenruo if (thresh == 0) 1280bd9289cSQu Wenruo thresh = DFT_THRESHOLD; 1290bd9289cSQu Wenruo /* For low threshold, disabling threshold is a better choice */ 1300bd9289cSQu Wenruo if (thresh < DFT_THRESHOLD) { 131c6dd6ea5SQu Wenruo ret->current_active = limit_active; 1320bd9289cSQu Wenruo ret->thresh = NO_THRESHOLD; 1330bd9289cSQu Wenruo } else { 134c6dd6ea5SQu Wenruo /* 135c6dd6ea5SQu Wenruo * For threshold-able wq, let its concurrency grow on demand. 136c6dd6ea5SQu Wenruo * Use minimal max_active at alloc time to reduce resource 137c6dd6ea5SQu Wenruo * usage. 138c6dd6ea5SQu Wenruo */ 139c6dd6ea5SQu Wenruo ret->current_active = 1; 1400bd9289cSQu Wenruo ret->thresh = thresh; 1410bd9289cSQu Wenruo } 1420bd9289cSQu Wenruo 1431ca08976SQu Wenruo if (flags & WQ_HIGHPRI) 144ce3ded10SDavid Sterba ret->normal_wq = alloc_workqueue("btrfs-%s-high", flags, 145ce3ded10SDavid Sterba ret->current_active, name); 1461ca08976SQu Wenruo else 147ce3ded10SDavid Sterba ret->normal_wq = alloc_workqueue("btrfs-%s", flags, 148ce3ded10SDavid Sterba ret->current_active, name); 1495d99a998SDavid Sterba if (!ret->normal_wq) { 15008a9ff32SQu Wenruo kfree(ret); 15108a9ff32SQu Wenruo return NULL; 15208a9ff32SQu Wenruo } 15308a9ff32SQu Wenruo 15408a9ff32SQu Wenruo INIT_LIST_HEAD(&ret->ordered_list); 15508a9ff32SQu Wenruo spin_lock_init(&ret->list_lock); 1560bd9289cSQu Wenruo spin_lock_init(&ret->thres_lock); 157c3a46891SQu Wenruo trace_btrfs_workqueue_alloc(ret, name, flags & WQ_HIGHPRI); 15808a9ff32SQu Wenruo return ret; 15908a9ff32SQu Wenruo } 16008a9ff32SQu Wenruo 1611ca08976SQu Wenruo static inline void 162d458b054SQu Wenruo __btrfs_destroy_workqueue(struct __btrfs_workqueue *wq); 1631ca08976SQu Wenruo 164cb001095SJeff Mahoney struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, 165cb001095SJeff Mahoney const char *name, 1666f011058SDavid Sterba unsigned int flags, 167c6dd6ea5SQu Wenruo int limit_active, 1680bd9289cSQu Wenruo int thresh) 1691ca08976SQu Wenruo { 17061dd5ae6SDavid Sterba struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL); 1711ca08976SQu Wenruo 1725d99a998SDavid Sterba if (!ret) 1731ca08976SQu Wenruo return NULL; 1741ca08976SQu Wenruo 175cb001095SJeff Mahoney ret->normal = __btrfs_alloc_workqueue(fs_info, name, 176cb001095SJeff Mahoney flags & ~WQ_HIGHPRI, 177c6dd6ea5SQu Wenruo limit_active, thresh); 1785d99a998SDavid Sterba if (!ret->normal) { 1791ca08976SQu Wenruo kfree(ret); 1801ca08976SQu Wenruo return NULL; 1811ca08976SQu Wenruo } 1821ca08976SQu Wenruo 1831ca08976SQu Wenruo if (flags & WQ_HIGHPRI) { 184cb001095SJeff Mahoney ret->high = __btrfs_alloc_workqueue(fs_info, name, flags, 185cb001095SJeff Mahoney limit_active, thresh); 1865d99a998SDavid Sterba if (!ret->high) { 1871ca08976SQu Wenruo __btrfs_destroy_workqueue(ret->normal); 1881ca08976SQu Wenruo kfree(ret); 1891ca08976SQu Wenruo return NULL; 1901ca08976SQu Wenruo } 1911ca08976SQu Wenruo } 1921ca08976SQu Wenruo return ret; 1931ca08976SQu Wenruo } 1941ca08976SQu Wenruo 1950bd9289cSQu Wenruo /* 1960bd9289cSQu Wenruo * Hook for threshold which will be called in btrfs_queue_work. 1970bd9289cSQu Wenruo * This hook WILL be called in IRQ handler context, 1980bd9289cSQu Wenruo * so workqueue_set_max_active MUST NOT be called in this hook 1990bd9289cSQu Wenruo */ 200d458b054SQu Wenruo static inline void thresh_queue_hook(struct __btrfs_workqueue *wq) 2010bd9289cSQu Wenruo { 2020bd9289cSQu Wenruo if (wq->thresh == NO_THRESHOLD) 2030bd9289cSQu Wenruo return; 2040bd9289cSQu Wenruo atomic_inc(&wq->pending); 2050bd9289cSQu Wenruo } 2060bd9289cSQu Wenruo 2070bd9289cSQu Wenruo /* 2080bd9289cSQu Wenruo * Hook for threshold which will be called before executing the work, 2090bd9289cSQu Wenruo * This hook is called in kthread content. 2100bd9289cSQu Wenruo * So workqueue_set_max_active is called here. 2110bd9289cSQu Wenruo */ 212d458b054SQu Wenruo static inline void thresh_exec_hook(struct __btrfs_workqueue *wq) 2130bd9289cSQu Wenruo { 214c6dd6ea5SQu Wenruo int new_current_active; 2150bd9289cSQu Wenruo long pending; 2160bd9289cSQu Wenruo int need_change = 0; 2170bd9289cSQu Wenruo 2180bd9289cSQu Wenruo if (wq->thresh == NO_THRESHOLD) 2190bd9289cSQu Wenruo return; 2200bd9289cSQu Wenruo 2210bd9289cSQu Wenruo atomic_dec(&wq->pending); 2220bd9289cSQu Wenruo spin_lock(&wq->thres_lock); 2230bd9289cSQu Wenruo /* 2240bd9289cSQu Wenruo * Use wq->count to limit the calling frequency of 2250bd9289cSQu Wenruo * workqueue_set_max_active. 2260bd9289cSQu Wenruo */ 2270bd9289cSQu Wenruo wq->count++; 2280bd9289cSQu Wenruo wq->count %= (wq->thresh / 4); 2290bd9289cSQu Wenruo if (!wq->count) 2300bd9289cSQu Wenruo goto out; 231c6dd6ea5SQu Wenruo new_current_active = wq->current_active; 2320bd9289cSQu Wenruo 2330bd9289cSQu Wenruo /* 2340bd9289cSQu Wenruo * pending may be changed later, but it's OK since we really 2350bd9289cSQu Wenruo * don't need it so accurate to calculate new_max_active. 2360bd9289cSQu Wenruo */ 2370bd9289cSQu Wenruo pending = atomic_read(&wq->pending); 2380bd9289cSQu Wenruo if (pending > wq->thresh) 239c6dd6ea5SQu Wenruo new_current_active++; 2400bd9289cSQu Wenruo if (pending < wq->thresh / 2) 241c6dd6ea5SQu Wenruo new_current_active--; 242c6dd6ea5SQu Wenruo new_current_active = clamp_val(new_current_active, 1, wq->limit_active); 243c6dd6ea5SQu Wenruo if (new_current_active != wq->current_active) { 2440bd9289cSQu Wenruo need_change = 1; 245c6dd6ea5SQu Wenruo wq->current_active = new_current_active; 2460bd9289cSQu Wenruo } 2470bd9289cSQu Wenruo out: 2480bd9289cSQu Wenruo spin_unlock(&wq->thres_lock); 2490bd9289cSQu Wenruo 2500bd9289cSQu Wenruo if (need_change) { 251c6dd6ea5SQu Wenruo workqueue_set_max_active(wq->normal_wq, wq->current_active); 2520bd9289cSQu Wenruo } 2530bd9289cSQu Wenruo } 2540bd9289cSQu Wenruo 255d458b054SQu Wenruo static void run_ordered_work(struct __btrfs_workqueue *wq) 25608a9ff32SQu Wenruo { 25708a9ff32SQu Wenruo struct list_head *list = &wq->ordered_list; 258d458b054SQu Wenruo struct btrfs_work *work; 25908a9ff32SQu Wenruo spinlock_t *lock = &wq->list_lock; 26008a9ff32SQu Wenruo unsigned long flags; 26108a9ff32SQu Wenruo 26208a9ff32SQu Wenruo while (1) { 263ac0c7cf8SDavid Sterba void *wtag; 264ac0c7cf8SDavid Sterba 26508a9ff32SQu Wenruo spin_lock_irqsave(lock, flags); 26608a9ff32SQu Wenruo if (list_empty(list)) 26708a9ff32SQu Wenruo break; 268d458b054SQu Wenruo work = list_entry(list->next, struct btrfs_work, 26908a9ff32SQu Wenruo ordered_list); 27008a9ff32SQu Wenruo if (!test_bit(WORK_DONE_BIT, &work->flags)) 27108a9ff32SQu Wenruo break; 27208a9ff32SQu Wenruo 27308a9ff32SQu Wenruo /* 27408a9ff32SQu Wenruo * we are going to call the ordered done function, but 27508a9ff32SQu Wenruo * we leave the work item on the list as a barrier so 27608a9ff32SQu Wenruo * that later work items that are done don't have their 27708a9ff32SQu Wenruo * functions called before this one returns 27808a9ff32SQu Wenruo */ 27908a9ff32SQu Wenruo if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) 28008a9ff32SQu Wenruo break; 28152483bc2SQu Wenruo trace_btrfs_ordered_sched(work); 28208a9ff32SQu Wenruo spin_unlock_irqrestore(lock, flags); 28308a9ff32SQu Wenruo work->ordered_func(work); 28408a9ff32SQu Wenruo 28508a9ff32SQu Wenruo /* now take the lock again and drop our item from the list */ 28608a9ff32SQu Wenruo spin_lock_irqsave(lock, flags); 28708a9ff32SQu Wenruo list_del(&work->ordered_list); 28808a9ff32SQu Wenruo spin_unlock_irqrestore(lock, flags); 28908a9ff32SQu Wenruo 29008a9ff32SQu Wenruo /* 291ac0c7cf8SDavid Sterba * We don't want to call the ordered free functions with the 292ac0c7cf8SDavid Sterba * lock held though. Save the work as tag for the trace event, 293ac0c7cf8SDavid Sterba * because the callback could free the structure. 29408a9ff32SQu Wenruo */ 295ac0c7cf8SDavid Sterba wtag = work; 29608a9ff32SQu Wenruo work->ordered_free(work); 297ac0c7cf8SDavid Sterba trace_btrfs_all_work_done(wq->fs_info, wtag); 29808a9ff32SQu Wenruo } 29908a9ff32SQu Wenruo spin_unlock_irqrestore(lock, flags); 30008a9ff32SQu Wenruo } 30108a9ff32SQu Wenruo 3029e0af237SLiu Bo static void normal_work_helper(struct btrfs_work *work) 30308a9ff32SQu Wenruo { 304d458b054SQu Wenruo struct __btrfs_workqueue *wq; 305ac0c7cf8SDavid Sterba void *wtag; 30608a9ff32SQu Wenruo int need_order = 0; 30708a9ff32SQu Wenruo 30808a9ff32SQu Wenruo /* 30908a9ff32SQu Wenruo * We should not touch things inside work in the following cases: 31008a9ff32SQu Wenruo * 1) after work->func() if it has no ordered_free 31108a9ff32SQu Wenruo * Since the struct is freed in work->func(). 31208a9ff32SQu Wenruo * 2) after setting WORK_DONE_BIT 31308a9ff32SQu Wenruo * The work may be freed in other threads almost instantly. 31408a9ff32SQu Wenruo * So we save the needed things here. 31508a9ff32SQu Wenruo */ 31608a9ff32SQu Wenruo if (work->ordered_func) 31708a9ff32SQu Wenruo need_order = 1; 31808a9ff32SQu Wenruo wq = work->wq; 319ac0c7cf8SDavid Sterba /* Safe for tracepoints in case work gets freed by the callback */ 320ac0c7cf8SDavid Sterba wtag = work; 32108a9ff32SQu Wenruo 32252483bc2SQu Wenruo trace_btrfs_work_sched(work); 3230bd9289cSQu Wenruo thresh_exec_hook(wq); 32408a9ff32SQu Wenruo work->func(work); 32508a9ff32SQu Wenruo if (need_order) { 32608a9ff32SQu Wenruo set_bit(WORK_DONE_BIT, &work->flags); 32708a9ff32SQu Wenruo run_ordered_work(wq); 32808a9ff32SQu Wenruo } 32952483bc2SQu Wenruo if (!need_order) 330ac0c7cf8SDavid Sterba trace_btrfs_all_work_done(wq->fs_info, wtag); 33108a9ff32SQu Wenruo } 33208a9ff32SQu Wenruo 3339e0af237SLiu Bo void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t uniq_func, 3346db8914fSQu Wenruo btrfs_func_t func, 3356db8914fSQu Wenruo btrfs_func_t ordered_func, 3366db8914fSQu Wenruo btrfs_func_t ordered_free) 33708a9ff32SQu Wenruo { 33808a9ff32SQu Wenruo work->func = func; 33908a9ff32SQu Wenruo work->ordered_func = ordered_func; 34008a9ff32SQu Wenruo work->ordered_free = ordered_free; 3419e0af237SLiu Bo INIT_WORK(&work->normal_work, uniq_func); 34208a9ff32SQu Wenruo INIT_LIST_HEAD(&work->ordered_list); 34308a9ff32SQu Wenruo work->flags = 0; 34408a9ff32SQu Wenruo } 34508a9ff32SQu Wenruo 346d458b054SQu Wenruo static inline void __btrfs_queue_work(struct __btrfs_workqueue *wq, 347d458b054SQu Wenruo struct btrfs_work *work) 34808a9ff32SQu Wenruo { 34908a9ff32SQu Wenruo unsigned long flags; 35008a9ff32SQu Wenruo 35108a9ff32SQu Wenruo work->wq = wq; 3520bd9289cSQu Wenruo thresh_queue_hook(wq); 35308a9ff32SQu Wenruo if (work->ordered_func) { 35408a9ff32SQu Wenruo spin_lock_irqsave(&wq->list_lock, flags); 35508a9ff32SQu Wenruo list_add_tail(&work->ordered_list, &wq->ordered_list); 35608a9ff32SQu Wenruo spin_unlock_irqrestore(&wq->list_lock, flags); 35708a9ff32SQu Wenruo } 35852483bc2SQu Wenruo trace_btrfs_work_queued(work); 3590a95b851SQu Wenruo queue_work(wq->normal_wq, &work->normal_work); 36008a9ff32SQu Wenruo } 36108a9ff32SQu Wenruo 362d458b054SQu Wenruo void btrfs_queue_work(struct btrfs_workqueue *wq, 363d458b054SQu Wenruo struct btrfs_work *work) 3641ca08976SQu Wenruo { 365d458b054SQu Wenruo struct __btrfs_workqueue *dest_wq; 3661ca08976SQu Wenruo 3671ca08976SQu Wenruo if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags) && wq->high) 3681ca08976SQu Wenruo dest_wq = wq->high; 3691ca08976SQu Wenruo else 3701ca08976SQu Wenruo dest_wq = wq->normal; 3711ca08976SQu Wenruo __btrfs_queue_work(dest_wq, work); 3721ca08976SQu Wenruo } 3731ca08976SQu Wenruo 3741ca08976SQu Wenruo static inline void 375d458b054SQu Wenruo __btrfs_destroy_workqueue(struct __btrfs_workqueue *wq) 37608a9ff32SQu Wenruo { 37708a9ff32SQu Wenruo destroy_workqueue(wq->normal_wq); 378c3a46891SQu Wenruo trace_btrfs_workqueue_destroy(wq); 37908a9ff32SQu Wenruo kfree(wq); 38008a9ff32SQu Wenruo } 38108a9ff32SQu Wenruo 382d458b054SQu Wenruo void btrfs_destroy_workqueue(struct btrfs_workqueue *wq) 3831ca08976SQu Wenruo { 3841ca08976SQu Wenruo if (!wq) 3851ca08976SQu Wenruo return; 3861ca08976SQu Wenruo if (wq->high) 3871ca08976SQu Wenruo __btrfs_destroy_workqueue(wq->high); 3881ca08976SQu Wenruo __btrfs_destroy_workqueue(wq->normal); 389ef66af10SFilipe Manana kfree(wq); 3901ca08976SQu Wenruo } 3911ca08976SQu Wenruo 392c6dd6ea5SQu Wenruo void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int limit_active) 39308a9ff32SQu Wenruo { 394800ee224SSergei Trofimovich if (!wq) 395800ee224SSergei Trofimovich return; 396c6dd6ea5SQu Wenruo wq->normal->limit_active = limit_active; 3971ca08976SQu Wenruo if (wq->high) 398c6dd6ea5SQu Wenruo wq->high->limit_active = limit_active; 3991ca08976SQu Wenruo } 4001ca08976SQu Wenruo 401d458b054SQu Wenruo void btrfs_set_work_high_priority(struct btrfs_work *work) 4021ca08976SQu Wenruo { 4031ca08976SQu Wenruo set_bit(WORK_HIGH_PRIO_BIT, &work->flags); 40408a9ff32SQu Wenruo } 405