diff options
| author | Chris Mason <chris.mason@oracle.com> | 2009-08-07 09:27:38 -0400 |
|---|---|---|
| committer | Chris Mason <chris.mason@oracle.com> | 2009-09-11 13:31:04 -0400 |
| commit | 4f878e8475a465ddbd951e06a23317303f1b5b30 (patch) | |
| tree | 7e1811794d3f6eaf455a3e26afd49ba06a0db554 /fs | |
| parent | 4e3f9c5042b43301d70781aee4a164a20878066b (diff) | |
Btrfs: reduce worker thread spin_lock_irq hold times
This changes the btrfs worker threads to batch work items
into a local list. It allows us to pull work items in
large chunks and significantly reduces the number of times we
need to take the worker thread spinlock.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/btrfs/async-thread.c | 74 |
1 files changed, 60 insertions, 14 deletions
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 4b4372df3b6d..6ea5cd0a595f 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
| @@ -196,31 +196,73 @@ static int try_worker_shutdown(struct btrfs_worker_thread *worker) | |||
| 196 | return freeit; | 196 | return freeit; |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | static struct btrfs_work *get_next_work(struct btrfs_worker_thread *worker, | ||
| 200 | struct list_head *prio_head, | ||
| 201 | struct list_head *head) | ||
| 202 | { | ||
| 203 | struct btrfs_work *work = NULL; | ||
| 204 | struct list_head *cur = NULL; | ||
| 205 | |||
| 206 | if(!list_empty(prio_head)) | ||
| 207 | cur = prio_head->next; | ||
| 208 | |||
| 209 | smp_mb(); | ||
| 210 | if (!list_empty(&worker->prio_pending)) | ||
| 211 | goto refill; | ||
| 212 | |||
| 213 | if (!list_empty(head)) | ||
| 214 | cur = head->next; | ||
| 215 | |||
| 216 | if (cur) | ||
| 217 | goto out; | ||
| 218 | |||
| 219 | refill: | ||
| 220 | spin_lock_irq(&worker->lock); | ||
| 221 | list_splice_tail_init(&worker->prio_pending, prio_head); | ||
| 222 | list_splice_tail_init(&worker->pending, head); | ||
| 223 | |||
| 224 | if (!list_empty(prio_head)) | ||
| 225 | cur = prio_head->next; | ||
| 226 | else if (!list_empty(head)) | ||
| 227 | cur = head->next; | ||
| 228 | spin_unlock_irq(&worker->lock); | ||
| 229 | |||
| 230 | if (!cur) | ||
| 231 | goto out_fail; | ||
| 232 | |||
| 233 | out: | ||
| 234 | work = list_entry(cur, struct btrfs_work, list); | ||
| 235 | |||
| 236 | out_fail: | ||
| 237 | return work; | ||
| 238 | } | ||
| 239 | |||
| 199 | /* | 240 | /* |
| 200 | * main loop for servicing work items | 241 | * main loop for servicing work items |
| 201 | */ | 242 | */ |
| 202 | static int worker_loop(void *arg) | 243 | static int worker_loop(void *arg) |
| 203 | { | 244 | { |
| 204 | struct btrfs_worker_thread *worker = arg; | 245 | struct btrfs_worker_thread *worker = arg; |
| 205 | struct list_head *cur; | 246 | struct list_head head; |
| 247 | struct list_head prio_head; | ||
| 206 | struct btrfs_work *work; | 248 | struct btrfs_work *work; |
| 249 | |||
| 250 | INIT_LIST_HEAD(&head); | ||
| 251 | INIT_LIST_HEAD(&prio_head); | ||
| 252 | |||
| 207 | do { | 253 | do { |
| 208 | spin_lock_irq(&worker->lock); | 254 | again: |
| 209 | again_locked: | ||
| 210 | while (1) { | 255 | while (1) { |
| 211 | if (!list_empty(&worker->prio_pending)) | 256 | |
| 212 | cur = worker->prio_pending.next; | 257 | |
| 213 | else if (!list_empty(&worker->pending)) | 258 | work = get_next_work(worker, &prio_head, &head); |
| 214 | cur = worker->pending.next; | 259 | if (!work) |
| 215 | else | ||
| 216 | break; | 260 | break; |
| 217 | 261 | ||
| 218 | work = list_entry(cur, struct btrfs_work, list); | ||
| 219 | list_del(&work->list); | 262 | list_del(&work->list); |
| 220 | clear_bit(WORK_QUEUED_BIT, &work->flags); | 263 | clear_bit(WORK_QUEUED_BIT, &work->flags); |
| 221 | 264 | ||
| 222 | work->worker = worker; | 265 | work->worker = worker; |
| 223 | spin_unlock_irq(&worker->lock); | ||
| 224 | 266 | ||
| 225 | work->func(work); | 267 | work->func(work); |
| 226 | 268 | ||
| @@ -233,9 +275,11 @@ again_locked: | |||
| 233 | 275 | ||
| 234 | check_pending_worker_creates(worker); | 276 | check_pending_worker_creates(worker); |
| 235 | 277 | ||
| 236 | spin_lock_irq(&worker->lock); | ||
| 237 | check_idle_worker(worker); | ||
| 238 | } | 278 | } |
| 279 | |||
| 280 | spin_lock_irq(&worker->lock); | ||
| 281 | check_idle_worker(worker); | ||
| 282 | |||
| 239 | if (freezing(current)) { | 283 | if (freezing(current)) { |
| 240 | worker->working = 0; | 284 | worker->working = 0; |
| 241 | spin_unlock_irq(&worker->lock); | 285 | spin_unlock_irq(&worker->lock); |
| @@ -274,8 +318,10 @@ again_locked: | |||
| 274 | spin_lock_irq(&worker->lock); | 318 | spin_lock_irq(&worker->lock); |
| 275 | set_current_state(TASK_INTERRUPTIBLE); | 319 | set_current_state(TASK_INTERRUPTIBLE); |
| 276 | if (!list_empty(&worker->pending) || | 320 | if (!list_empty(&worker->pending) || |
| 277 | !list_empty(&worker->prio_pending)) | 321 | !list_empty(&worker->prio_pending)) { |
| 278 | goto again_locked; | 322 | spin_unlock_irq(&worker->lock); |
| 323 | goto again; | ||
| 324 | } | ||
| 279 | 325 | ||
| 280 | /* | 326 | /* |
| 281 | * this makes sure we get a wakeup when someone | 327 | * this makes sure we get a wakeup when someone |
