]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/btrfs/async-thread.c
Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / fs / btrfs / async-thread.c
index 6ea5cd0a595fd165b6d24c38e644e195fe69930f..282ca085c2fbff854bcf4a396d0773db129c5085 100644 (file)
@@ -74,7 +74,12 @@ static void check_idle_worker(struct btrfs_worker_thread *worker)
                unsigned long flags;
                spin_lock_irqsave(&worker->workers->lock, flags);
                worker->idle = 1;
-               list_move(&worker->worker_list, &worker->workers->idle_list);
+
+               /* the list may be empty if the worker is just starting */
+               if (!list_empty(&worker->worker_list)) {
+                       list_move(&worker->worker_list,
+                                &worker->workers->idle_list);
+               }
                spin_unlock_irqrestore(&worker->workers->lock, flags);
        }
 }
@@ -90,8 +95,11 @@ static void check_busy_worker(struct btrfs_worker_thread *worker)
                unsigned long flags;
                spin_lock_irqsave(&worker->workers->lock, flags);
                worker->idle = 0;
-               list_move_tail(&worker->worker_list,
-                              &worker->workers->worker_list);
+
+               if (!list_empty(&worker->worker_list)) {
+                       list_move_tail(&worker->worker_list,
+                                     &worker->workers->worker_list);
+               }
                spin_unlock_irqrestore(&worker->workers->lock, flags);
        }
 }
@@ -177,18 +185,19 @@ static int try_worker_shutdown(struct btrfs_worker_thread *worker)
        int freeit = 0;
 
        spin_lock_irq(&worker->lock);
-       spin_lock_irq(&worker->workers->lock);
+       spin_lock(&worker->workers->lock);
        if (worker->workers->num_workers > 1 &&
            worker->idle &&
            !worker->working &&
            !list_empty(&worker->worker_list) &&
            list_empty(&worker->prio_pending) &&
-           list_empty(&worker->pending)) {
+           list_empty(&worker->pending) &&
+           atomic_read(&worker->num_pending) == 0) {
                freeit = 1;
                list_del_init(&worker->worker_list);
                worker->workers->num_workers--;
        }
-       spin_unlock_irq(&worker->workers->lock);
+       spin_unlock(&worker->workers->lock);
        spin_unlock_irq(&worker->lock);
 
        if (freeit)
@@ -477,7 +486,6 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers)
         */
        next = workers->worker_list.next;
        worker = list_entry(next, struct btrfs_worker_thread, worker_list);
-       atomic_inc(&worker->num_pending);
        worker->sequence++;
 
        if (worker->sequence % workers->idle_thresh == 0)
@@ -513,8 +521,7 @@ again:
                        goto again;
                }
        }
-       spin_unlock_irqrestore(&workers->lock, flags);
-       return worker;
+       goto found;
 
 fallback:
        fallback = NULL;
@@ -529,6 +536,12 @@ fallback:
        BUG_ON(!fallback);
        worker = list_entry(fallback,
                  struct btrfs_worker_thread, worker_list);
+found:
+       /*
+        * this makes sure the worker doesn't exit before it is placed
+        * onto a busy/idle list
+        */
+       atomic_inc(&worker->num_pending);
        spin_unlock_irqrestore(&workers->lock, flags);
        return worker;
 }
@@ -561,7 +574,7 @@ int btrfs_requeue_work(struct btrfs_work *work)
                spin_lock(&worker->workers->lock);
                worker->idle = 0;
                list_move_tail(&worker->worker_list,
-                              &worker->workers->worker_list);
+                             &worker->workers->worker_list);
                spin_unlock(&worker->workers->lock);
        }
        if (!worker->working) {
@@ -619,7 +632,6 @@ int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work)
                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);
 
        /*