diff options
Diffstat (limited to 'fs/btrfs/async-thread.c')
| -rw-r--r-- | fs/btrfs/async-thread.c | 60 | 
1 files changed, 47 insertions, 13 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 @@  #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);  | 
