io-wq.h (5261B)
1#ifndef INTERNAL_IO_WQ_H 2#define INTERNAL_IO_WQ_H 3 4#include <linux/refcount.h> 5 6struct io_wq; 7 8enum { 9 IO_WQ_WORK_CANCEL = 1, 10 IO_WQ_WORK_HASHED = 2, 11 IO_WQ_WORK_UNBOUND = 4, 12 IO_WQ_WORK_CONCURRENT = 16, 13 14 IO_WQ_HASH_SHIFT = 24, /* upper 8 bits are used for hash key */ 15}; 16 17enum io_wq_cancel { 18 IO_WQ_CANCEL_OK, /* cancelled before started */ 19 IO_WQ_CANCEL_RUNNING, /* found, running, and attempted cancelled */ 20 IO_WQ_CANCEL_NOTFOUND, /* work not found */ 21}; 22 23struct io_wq_work_node { 24 struct io_wq_work_node *next; 25}; 26 27struct io_wq_work_list { 28 struct io_wq_work_node *first; 29 struct io_wq_work_node *last; 30}; 31 32#define wq_list_for_each(pos, prv, head) \ 33 for (pos = (head)->first, prv = NULL; pos; prv = pos, pos = (pos)->next) 34 35#define wq_list_for_each_resume(pos, prv) \ 36 for (; pos; prv = pos, pos = (pos)->next) 37 38#define wq_list_empty(list) (READ_ONCE((list)->first) == NULL) 39#define INIT_WQ_LIST(list) do { \ 40 (list)->first = NULL; \ 41} while (0) 42 43static inline void wq_list_add_after(struct io_wq_work_node *node, 44 struct io_wq_work_node *pos, 45 struct io_wq_work_list *list) 46{ 47 struct io_wq_work_node *next = pos->next; 48 49 pos->next = node; 50 node->next = next; 51 if (!next) 52 list->last = node; 53} 54 55/** 56 * wq_list_merge - merge the second list to the first one. 57 * @list0: the first list 58 * @list1: the second list 59 * Return the first node after mergence. 60 */ 61static inline struct io_wq_work_node *wq_list_merge(struct io_wq_work_list *list0, 62 struct io_wq_work_list *list1) 63{ 64 struct io_wq_work_node *ret; 65 66 if (!list0->first) { 67 ret = list1->first; 68 } else { 69 ret = list0->first; 70 list0->last->next = list1->first; 71 } 72 INIT_WQ_LIST(list0); 73 INIT_WQ_LIST(list1); 74 return ret; 75} 76 77static inline void wq_list_add_tail(struct io_wq_work_node *node, 78 struct io_wq_work_list *list) 79{ 80 node->next = NULL; 81 if (!list->first) { 82 list->last = node; 83 WRITE_ONCE(list->first, node); 84 } else { 85 list->last->next = node; 86 list->last = node; 87 } 88} 89 90static inline void wq_list_add_head(struct io_wq_work_node *node, 91 struct io_wq_work_list *list) 92{ 93 node->next = list->first; 94 if (!node->next) 95 list->last = node; 96 WRITE_ONCE(list->first, node); 97} 98 99static inline void wq_list_cut(struct io_wq_work_list *list, 100 struct io_wq_work_node *last, 101 struct io_wq_work_node *prev) 102{ 103 /* first in the list, if prev==NULL */ 104 if (!prev) 105 WRITE_ONCE(list->first, last->next); 106 else 107 prev->next = last->next; 108 109 if (last == list->last) 110 list->last = prev; 111 last->next = NULL; 112} 113 114static inline void __wq_list_splice(struct io_wq_work_list *list, 115 struct io_wq_work_node *to) 116{ 117 list->last->next = to->next; 118 to->next = list->first; 119 INIT_WQ_LIST(list); 120} 121 122static inline bool wq_list_splice(struct io_wq_work_list *list, 123 struct io_wq_work_node *to) 124{ 125 if (!wq_list_empty(list)) { 126 __wq_list_splice(list, to); 127 return true; 128 } 129 return false; 130} 131 132static inline void wq_stack_add_head(struct io_wq_work_node *node, 133 struct io_wq_work_node *stack) 134{ 135 node->next = stack->next; 136 stack->next = node; 137} 138 139static inline void wq_list_del(struct io_wq_work_list *list, 140 struct io_wq_work_node *node, 141 struct io_wq_work_node *prev) 142{ 143 wq_list_cut(list, node, prev); 144} 145 146static inline 147struct io_wq_work_node *wq_stack_extract(struct io_wq_work_node *stack) 148{ 149 struct io_wq_work_node *node = stack->next; 150 151 stack->next = node->next; 152 return node; 153} 154 155struct io_wq_work { 156 struct io_wq_work_node list; 157 unsigned flags; 158 int cancel_seq; 159}; 160 161static inline struct io_wq_work *wq_next_work(struct io_wq_work *work) 162{ 163 if (!work->list.next) 164 return NULL; 165 166 return container_of(work->list.next, struct io_wq_work, list); 167} 168 169typedef struct io_wq_work *(free_work_fn)(struct io_wq_work *); 170typedef void (io_wq_work_fn)(struct io_wq_work *); 171 172struct io_wq_hash { 173 refcount_t refs; 174 unsigned long map; 175 struct wait_queue_head wait; 176}; 177 178static inline void io_wq_put_hash(struct io_wq_hash *hash) 179{ 180 if (refcount_dec_and_test(&hash->refs)) 181 kfree(hash); 182} 183 184struct io_wq_data { 185 struct io_wq_hash *hash; 186 struct task_struct *task; 187 io_wq_work_fn *do_work; 188 free_work_fn *free_work; 189}; 190 191struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data); 192void io_wq_exit_start(struct io_wq *wq); 193void io_wq_put_and_exit(struct io_wq *wq); 194 195void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work); 196void io_wq_hash_work(struct io_wq_work *work, void *val); 197 198int io_wq_cpu_affinity(struct io_wq *wq, cpumask_var_t mask); 199int io_wq_max_workers(struct io_wq *wq, int *new_count); 200 201static inline bool io_wq_is_hashed(struct io_wq_work *work) 202{ 203 return work->flags & IO_WQ_WORK_HASHED; 204} 205 206typedef bool (work_cancel_fn)(struct io_wq_work *, void *); 207 208enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel, 209 void *data, bool cancel_all); 210 211#if defined(CONFIG_IO_WQ) 212extern void io_wq_worker_sleeping(struct task_struct *); 213extern void io_wq_worker_running(struct task_struct *); 214#else 215static inline void io_wq_worker_sleeping(struct task_struct *tsk) 216{ 217} 218static inline void io_wq_worker_running(struct task_struct *tsk) 219{ 220} 221#endif 222 223static inline bool io_wq_current_is_worker(void) 224{ 225 return in_task() && (current->flags & PF_IO_WORKER) && 226 current->worker_private; 227} 228#endif