|
@@ -25,6 +25,7 @@
|
|
|
#define WORK_QUEUED_BIT 0
|
|
|
#define WORK_DONE_BIT 1
|
|
|
#define WORK_ORDER_DONE_BIT 2
|
|
|
+#define WORK_HIGH_PRIO_BIT 3
|
|
|
|
|
|
/*
|
|
|
* container for the kthread task pointer and the list of pending work
|
|
@@ -36,6 +37,7 @@ struct btrfs_worker_thread {
|
|
|
|
|
|
/* list of struct btrfs_work that are waiting for service */
|
|
|
struct list_head pending;
|
|
|
+ struct list_head prio_pending;
|
|
|
|
|
|
/* list of worker threads from struct btrfs_workers */
|
|
|
struct list_head worker_list;
|
|
@@ -103,10 +105,16 @@ static noinline int run_ordered_completions(struct btrfs_workers *workers,
|
|
|
|
|
|
spin_lock_irqsave(&workers->lock, flags);
|
|
|
|
|
|
- while (!list_empty(&workers->order_list)) {
|
|
|
- work = list_entry(workers->order_list.next,
|
|
|
- struct btrfs_work, order_list);
|
|
|
-
|
|
|
+ while (1) {
|
|
|
+ if (!list_empty(&workers->prio_order_list)) {
|
|
|
+ work = list_entry(workers->prio_order_list.next,
|
|
|
+ struct btrfs_work, order_list);
|
|
|
+ } else if (!list_empty(&workers->order_list)) {
|
|
|
+ work = list_entry(workers->order_list.next,
|
|
|
+ struct btrfs_work, order_list);
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
if (!test_bit(WORK_DONE_BIT, &work->flags))
|
|
|
break;
|
|
|
|
|
@@ -143,8 +151,14 @@ static int worker_loop(void *arg)
|
|
|
do {
|
|
|
spin_lock_irq(&worker->lock);
|
|
|
again_locked:
|
|
|
- while (!list_empty(&worker->pending)) {
|
|
|
- cur = worker->pending.next;
|
|
|
+ while (1) {
|
|
|
+ if (!list_empty(&worker->prio_pending))
|
|
|
+ cur = worker->prio_pending.next;
|
|
|
+ else if (!list_empty(&worker->pending))
|
|
|
+ cur = worker->pending.next;
|
|
|
+ else
|
|
|
+ break;
|
|
|
+
|
|
|
work = list_entry(cur, struct btrfs_work, list);
|
|
|
list_del(&work->list);
|
|
|
clear_bit(WORK_QUEUED_BIT, &work->flags);
|
|
@@ -163,7 +177,6 @@ again_locked:
|
|
|
|
|
|
spin_lock_irq(&worker->lock);
|
|
|
check_idle_worker(worker);
|
|
|
-
|
|
|
}
|
|
|
if (freezing(current)) {
|
|
|
worker->working = 0;
|
|
@@ -178,7 +191,8 @@ again_locked:
|
|
|
* jump_in?
|
|
|
*/
|
|
|
smp_mb();
|
|
|
- if (!list_empty(&worker->pending))
|
|
|
+ if (!list_empty(&worker->pending) ||
|
|
|
+ !list_empty(&worker->prio_pending))
|
|
|
continue;
|
|
|
|
|
|
/*
|
|
@@ -191,7 +205,8 @@ again_locked:
|
|
|
*/
|
|
|
schedule_timeout(1);
|
|
|
smp_mb();
|
|
|
- if (!list_empty(&worker->pending))
|
|
|
+ if (!list_empty(&worker->pending) ||
|
|
|
+ !list_empty(&worker->prio_pending))
|
|
|
continue;
|
|
|
|
|
|
if (kthread_should_stop())
|
|
@@ -200,7 +215,8 @@ again_locked:
|
|
|
/* still no more work?, sleep for real */
|
|
|
spin_lock_irq(&worker->lock);
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
|
- if (!list_empty(&worker->pending))
|
|
|
+ if (!list_empty(&worker->pending) ||
|
|
|
+ !list_empty(&worker->prio_pending))
|
|
|
goto again_locked;
|
|
|
|
|
|
/*
|
|
@@ -248,6 +264,7 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max)
|
|
|
INIT_LIST_HEAD(&workers->worker_list);
|
|
|
INIT_LIST_HEAD(&workers->idle_list);
|
|
|
INIT_LIST_HEAD(&workers->order_list);
|
|
|
+ INIT_LIST_HEAD(&workers->prio_order_list);
|
|
|
spin_lock_init(&workers->lock);
|
|
|
workers->max_workers = max;
|
|
|
workers->idle_thresh = 32;
|
|
@@ -273,6 +290,7 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
|
|
|
}
|
|
|
|
|
|
INIT_LIST_HEAD(&worker->pending);
|
|
|
+ INIT_LIST_HEAD(&worker->prio_pending);
|
|
|
INIT_LIST_HEAD(&worker->worker_list);
|
|
|
spin_lock_init(&worker->lock);
|
|
|
atomic_set(&worker->num_pending, 0);
|
|
@@ -396,7 +414,10 @@ int btrfs_requeue_work(struct btrfs_work *work)
|
|
|
goto out;
|
|
|
|
|
|
spin_lock_irqsave(&worker->lock, flags);
|
|
|
- list_add_tail(&work->list, &worker->pending);
|
|
|
+ if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags))
|
|
|
+ list_add_tail(&work->list, &worker->prio_pending);
|
|
|
+ else
|
|
|
+ list_add_tail(&work->list, &worker->pending);
|
|
|
atomic_inc(&worker->num_pending);
|
|
|
|
|
|
/* by definition we're busy, take ourselves off the idle
|
|
@@ -422,6 +443,11 @@ out:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+void btrfs_set_work_high_prio(struct btrfs_work *work)
|
|
|
+{
|
|
|
+ set_bit(WORK_HIGH_PRIO_BIT, &work->flags);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* places a struct btrfs_work into the pending queue of one of the kthreads
|
|
|
*/
|
|
@@ -438,7 +464,12 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
|
|
|
worker = find_worker(workers);
|
|
|
if (workers->ordered) {
|
|
|
spin_lock_irqsave(&workers->lock, flags);
|
|
|
- list_add_tail(&work->order_list, &workers->order_list);
|
|
|
+ if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags)) {
|
|
|
+ list_add_tail(&work->order_list,
|
|
|
+ &workers->prio_order_list);
|
|
|
+ } else {
|
|
|
+ list_add_tail(&work->order_list, &workers->order_list);
|
|
|
+ }
|
|
|
spin_unlock_irqrestore(&workers->lock, flags);
|
|
|
} else {
|
|
|
INIT_LIST_HEAD(&work->order_list);
|
|
@@ -446,7 +477,10 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
|
|
|
|
|
|
spin_lock_irqsave(&worker->lock, flags);
|
|
|
|
|
|
- list_add_tail(&work->list, &worker->pending);
|
|
|
+ if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags))
|
|
|
+ list_add_tail(&work->list, &worker->prio_pending);
|
|
|
+ else
|
|
|
+ list_add_tail(&work->list, &worker->pending);
|
|
|
atomic_inc(&worker->num_pending);
|
|
|
check_busy_worker(worker);
|
|
|
|