diff options
| -rw-r--r-- | fs/btrfs/async-thread.c | 60 | ||||
| -rw-r--r-- | fs/btrfs/async-thread.h | 2 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/extent_io.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/file.c | 2 |
5 files changed, 56 insertions, 15 deletions
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 51bfdfc8fcda..502c3d61de62 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #define WORK_QUEUED_BIT 0 | 25 | #define WORK_QUEUED_BIT 0 |
| 26 | #define WORK_DONE_BIT 1 | 26 | #define WORK_DONE_BIT 1 |
| 27 | #define WORK_ORDER_DONE_BIT 2 | 27 | #define WORK_ORDER_DONE_BIT 2 |
| 28 | #define WORK_HIGH_PRIO_BIT 3 | ||
| 28 | 29 | ||
| 29 | /* | 30 | /* |
| 30 | * container for the kthread task pointer and the list of pending work | 31 | * container for the kthread task pointer and the list of pending work |
| @@ -36,6 +37,7 @@ struct btrfs_worker_thread { | |||
| 36 | 37 | ||
| 37 | /* list of struct btrfs_work that are waiting for service */ | 38 | /* list of struct btrfs_work that are waiting for service */ |
| 38 | struct list_head pending; | 39 | struct list_head pending; |
| 40 | struct list_head prio_pending; | ||
| 39 | 41 | ||
| 40 | /* list of worker threads from struct btrfs_workers */ | 42 | /* list of worker threads from struct btrfs_workers */ |
| 41 | struct list_head worker_list; | 43 | struct list_head worker_list; |
| @@ -103,10 +105,16 @@ static noinline int run_ordered_completions(struct btrfs_workers *workers, | |||
| 103 | 105 | ||
| 104 | spin_lock_irqsave(&workers->lock, flags); | 106 | spin_lock_irqsave(&workers->lock, flags); |
| 105 | 107 | ||
| 106 | while (!list_empty(&workers->order_list)) { | 108 | while (1) { |
| 107 | work = list_entry(workers->order_list.next, | 109 | if (!list_empty(&workers->prio_order_list)) { |
| 108 | struct btrfs_work, order_list); | 110 | work = list_entry(workers->prio_order_list.next, |
| 109 | 111 | struct btrfs_work, order_list); | |
| 112 | } else if (!list_empty(&workers->order_list)) { | ||
| 113 | work = list_entry(workers->order_list.next, | ||
| 114 | struct btrfs_work, order_list); | ||
| 115 | } else { | ||
| 116 | break; | ||
| 117 | } | ||
| 110 | if (!test_bit(WORK_DONE_BIT, &work->flags)) | 118 | if (!test_bit(WORK_DONE_BIT, &work->flags)) |
| 111 | break; | 119 | break; |
| 112 | 120 | ||
| @@ -143,8 +151,14 @@ static int worker_loop(void *arg) | |||
| 143 | do { | 151 | do { |
| 144 | spin_lock_irq(&worker->lock); | 152 | spin_lock_irq(&worker->lock); |
| 145 | again_locked: | 153 | again_locked: |
| 146 | while (!list_empty(&worker->pending)) { | 154 | while (1) { |
| 147 | cur = worker->pending.next; | 155 | if (!list_empty(&worker->prio_pending)) |
| 156 | cur = worker->prio_pending.next; | ||
| 157 | else if (!list_empty(&worker->pending)) | ||
| 158 | cur = worker->pending.next; | ||
| 159 | else | ||
| 160 | break; | ||
| 161 | |||
| 148 | work = list_entry(cur, struct btrfs_work, list); | 162 | work = list_entry(cur, struct btrfs_work, list); |
| 149 | list_del(&work->list); | 163 | list_del(&work->list); |
| 150 | clear_bit(WORK_QUEUED_BIT, &work->flags); | 164 | clear_bit(WORK_QUEUED_BIT, &work->flags); |
| @@ -163,7 +177,6 @@ again_locked: | |||
| 163 | 177 | ||
| 164 | spin_lock_irq(&worker->lock); | 178 | spin_lock_irq(&worker->lock); |
| 165 | check_idle_worker(worker); | 179 | check_idle_worker(worker); |
| 166 | |||
| 167 | } | 180 | } |
| 168 | if (freezing(current)) { | 181 | if (freezing(current)) { |
| 169 | worker->working = 0; | 182 | worker->working = 0; |
| @@ -178,7 +191,8 @@ again_locked: | |||
| 178 | * jump_in? | 191 | * jump_in? |
| 179 | */ | 192 | */ |
| 180 | smp_mb(); | 193 | smp_mb(); |
| 181 | if (!list_empty(&worker->pending)) | 194 | if (!list_empty(&worker->pending) || |
| 195 | !list_empty(&worker->prio_pending)) | ||
| 182 | continue; | 196 | continue; |
| 183 | 197 | ||
| 184 | /* | 198 | /* |
| @@ -191,7 +205,8 @@ again_locked: | |||
| 191 | */ | 205 | */ |
| 192 | schedule_timeout(1); | 206 | schedule_timeout(1); |
| 193 | smp_mb(); | 207 | smp_mb(); |
| 194 | if (!list_empty(&worker->pending)) | 208 | if (!list_empty(&worker->pending) || |
| 209 | !list_empty(&worker->prio_pending)) | ||
| 195 | continue; | 210 | continue; |
| 196 | 211 | ||
| 197 | if (kthread_should_stop()) | 212 | if (kthread_should_stop()) |
| @@ -200,7 +215,8 @@ again_locked: | |||
| 200 | /* still no more work?, sleep for real */ | 215 | /* still no more work?, sleep for real */ |
| 201 | spin_lock_irq(&worker->lock); | 216 | spin_lock_irq(&worker->lock); |
| 202 | set_current_state(TASK_INTERRUPTIBLE); | 217 | set_current_state(TASK_INTERRUPTIBLE); |
| 203 | if (!list_empty(&worker->pending)) | 218 | if (!list_empty(&worker->pending) || |
| 219 | !list_empty(&worker->prio_pending)) | ||
| 204 | goto again_locked; | 220 | goto again_locked; |
| 205 | 221 | ||
| 206 | /* | 222 | /* |
| @@ -248,6 +264,7 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max) | |||
| 248 | INIT_LIST_HEAD(&workers->worker_list); | 264 | INIT_LIST_HEAD(&workers->worker_list); |
| 249 | INIT_LIST_HEAD(&workers->idle_list); | 265 | INIT_LIST_HEAD(&workers->idle_list); |
| 250 | INIT_LIST_HEAD(&workers->order_list); | 266 | INIT_LIST_HEAD(&workers->order_list); |
| 267 | INIT_LIST_HEAD(&workers->prio_order_list); | ||
| 251 | spin_lock_init(&workers->lock); | 268 | spin_lock_init(&workers->lock); |
| 252 | workers->max_workers = max; | 269 | workers->max_workers = max; |
| 253 | workers->idle_thresh = 32; | 270 | workers->idle_thresh = 32; |
| @@ -273,6 +290,7 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) | |||
| 273 | } | 290 | } |
| 274 | 291 | ||
| 275 | INIT_LIST_HEAD(&worker->pending); | 292 | INIT_LIST_HEAD(&worker->pending); |
| 293 | INIT_LIST_HEAD(&worker->prio_pending); | ||
| 276 | INIT_LIST_HEAD(&worker->worker_list); | 294 | INIT_LIST_HEAD(&worker->worker_list); |
| 277 | spin_lock_init(&worker->lock); | 295 | spin_lock_init(&worker->lock); |
| 278 | atomic_set(&worker->num_pending, 0); | 296 | atomic_set(&worker->num_pending, 0); |
| @@ -396,7 +414,10 @@ int btrfs_requeue_work(struct btrfs_work *work) | |||
| 396 | goto out; | 414 | goto out; |
| 397 | 415 | ||
| 398 | spin_lock_irqsave(&worker->lock, flags); | 416 | spin_lock_irqsave(&worker->lock, flags); |
| 399 | list_add_tail(&work->list, &worker->pending); | 417 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) |
| 418 | list_add_tail(&work->list, &worker->prio_pending); | ||
| 419 | else | ||
| 420 | list_add_tail(&work->list, &worker->pending); | ||
| 400 | atomic_inc(&worker->num_pending); | 421 | atomic_inc(&worker->num_pending); |
| 401 | 422 | ||
| 402 | /* by definition we're busy, take ourselves off the idle | 423 | /* by definition we're busy, take ourselves off the idle |
| @@ -422,6 +443,11 @@ out: | |||
| 422 | return 0; | 443 | return 0; |
| 423 | } | 444 | } |
| 424 | 445 | ||
| 446 | void btrfs_set_work_high_prio(struct btrfs_work *work) | ||
| 447 | { | ||
| 448 | set_bit(WORK_HIGH_PRIO_BIT, &work->flags); | ||
| 449 | } | ||
| 450 | |||
| 425 | /* | 451 | /* |
| 426 | * places a struct btrfs_work into the pending queue of one of the kthreads | 452 | * places a struct btrfs_work into the pending queue of one of the kthreads |
| 427 | */ | 453 | */ |
| @@ -438,7 +464,12 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) | |||
| 438 | worker = find_worker(workers); | 464 | worker = find_worker(workers); |
| 439 | if (workers->ordered) { | 465 | if (workers->ordered) { |
| 440 | spin_lock_irqsave(&workers->lock, flags); | 466 | spin_lock_irqsave(&workers->lock, flags); |
| 441 | list_add_tail(&work->order_list, &workers->order_list); | 467 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) { |
| 468 | list_add_tail(&work->order_list, | ||
| 469 | &workers->prio_order_list); | ||
| 470 | } else { | ||
| 471 | list_add_tail(&work->order_list, &workers->order_list); | ||
| 472 | } | ||
| 442 | spin_unlock_irqrestore(&workers->lock, flags); | 473 | spin_unlock_irqrestore(&workers->lock, flags); |
| 443 | } else { | 474 | } else { |
| 444 | INIT_LIST_HEAD(&work->order_list); | 475 | INIT_LIST_HEAD(&work->order_list); |
| @@ -446,7 +477,10 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work) | |||
| 446 | 477 | ||
| 447 | spin_lock_irqsave(&worker->lock, flags); | 478 | spin_lock_irqsave(&worker->lock, flags); |
| 448 | 479 | ||
| 449 | list_add_tail(&work->list, &worker->pending); | 480 | if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) |
| 481 | list_add_tail(&work->list, &worker->prio_pending); | ||
| 482 | else | ||
| 483 | list_add_tail(&work->list, &worker->pending); | ||
| 450 | atomic_inc(&worker->num_pending); | 484 | atomic_inc(&worker->num_pending); |
| 451 | check_busy_worker(worker); | 485 | check_busy_worker(worker); |
| 452 | 486 | ||
diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index 31be4ed8b63e..1b511c109db6 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h | |||
| @@ -85,6 +85,7 @@ struct btrfs_workers { | |||
| 85 | * of work items waiting for completion | 85 | * of work items waiting for completion |
| 86 | */ | 86 | */ |
| 87 | struct list_head order_list; | 87 | struct list_head order_list; |
| 88 | struct list_head prio_order_list; | ||
| 88 | 89 | ||
| 89 | /* lock for finding the next worker thread to queue on */ | 90 | /* lock for finding the next worker thread to queue on */ |
| 90 | spinlock_t lock; | 91 | spinlock_t lock; |
| @@ -98,4 +99,5 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers); | |||
| 98 | int btrfs_stop_workers(struct btrfs_workers *workers); | 99 | int btrfs_stop_workers(struct btrfs_workers *workers); |
| 99 | void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max); | 100 | void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max); |
| 100 | int btrfs_requeue_work(struct btrfs_work *work); | 101 | int btrfs_requeue_work(struct btrfs_work *work); |
| 102 | void btrfs_set_work_high_prio(struct btrfs_work *work); | ||
| 101 | #endif | 103 | #endif |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index fec18b43c2c3..a6b83744b05d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -579,6 +579,10 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | |||
| 579 | async->bio_flags = bio_flags; | 579 | async->bio_flags = bio_flags; |
| 580 | 580 | ||
| 581 | atomic_inc(&fs_info->nr_async_submits); | 581 | atomic_inc(&fs_info->nr_async_submits); |
| 582 | |||
| 583 | if (rw & (1 << BIO_RW_SYNCIO)) | ||
| 584 | btrfs_set_work_high_prio(&async->work); | ||
| 585 | |||
| 582 | btrfs_queue_worker(&fs_info->workers, &async->work); | 586 | btrfs_queue_worker(&fs_info->workers, &async->work); |
| 583 | #if 0 | 587 | #if 0 |
| 584 | int limit = btrfs_async_submit_limit(fs_info); | 588 | int limit = btrfs_async_submit_limit(fs_info); |
| @@ -656,6 +660,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
| 656 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, | 660 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, |
| 657 | mirror_num, 0); | 661 | mirror_num, 0); |
| 658 | } | 662 | } |
| 663 | |||
| 659 | /* | 664 | /* |
| 660 | * kthread helpers are used to submit writes so that checksumming | 665 | * kthread helpers are used to submit writes so that checksumming |
| 661 | * can happen in parallel across all CPUs | 666 | * can happen in parallel across all CPUs |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 483b6727aaaf..5d66cb27e422 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
| @@ -2501,7 +2501,7 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page, | |||
| 2501 | }; | 2501 | }; |
| 2502 | struct writeback_control wbc_writepages = { | 2502 | struct writeback_control wbc_writepages = { |
| 2503 | .bdi = wbc->bdi, | 2503 | .bdi = wbc->bdi, |
| 2504 | .sync_mode = WB_SYNC_NONE, | 2504 | .sync_mode = wbc->sync_mode, |
| 2505 | .older_than_this = NULL, | 2505 | .older_than_this = NULL, |
| 2506 | .nr_to_write = 64, | 2506 | .nr_to_write = 64, |
| 2507 | .range_start = page_offset(page) + PAGE_CACHE_SIZE, | 2507 | .range_start = page_offset(page) + PAGE_CACHE_SIZE, |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 9c9fb46ccd08..e21c0060ee73 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -1131,7 +1131,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
| 1131 | if (will_write) { | 1131 | if (will_write) { |
| 1132 | btrfs_fdatawrite_range(inode->i_mapping, pos, | 1132 | btrfs_fdatawrite_range(inode->i_mapping, pos, |
| 1133 | pos + write_bytes - 1, | 1133 | pos + write_bytes - 1, |
| 1134 | WB_SYNC_NONE); | 1134 | WB_SYNC_ALL); |
| 1135 | } else { | 1135 | } else { |
| 1136 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, | 1136 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, |
| 1137 | num_pages); | 1137 | num_pages); |
