]> git.hungrycats.org Git - linux/commitdiff
[PATCH] CFQ: allocation under lock, missing memset on allocation
authorJens Axboe <axboe@suse.de>
Thu, 15 Jul 2004 02:23:57 +0000 (19:23 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 15 Jul 2004 02:23:57 +0000 (19:23 -0700)
This fixes two issues in the CFQ IO-scheduler:

o Still a bad allocation under the queue lock
o We need to clear crq after mempool_alloc(), otherwise the rbtree
  pointers can contain garbage if slab poisoning is enabled. This causes
  crashes on front/back merges because rb_next() returns crap.

Signed-off-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/block/cfq-iosched.c

index fc5f519ed892644c1f34e101cb0a023f2986903b..068f4eae0b5cfcdbfe3bcabca106c15e56e4d7dc 100644 (file)
@@ -460,22 +460,36 @@ static struct cfq_queue *__cfq_get_queue(struct cfq_data *cfqd, int pid,
                                         int gfp_mask)
 {
        const int hashval = hash_long(current->tgid, CFQ_QHASH_SHIFT);
-       struct cfq_queue *cfqq = __cfq_find_cfq_hash(cfqd, pid, hashval);
-
-       if (!cfqq) {
-               cfqq = mempool_alloc(cfq_mpool, gfp_mask);
+       struct cfq_queue *cfqq, *new_cfqq = NULL;
+       request_queue_t *q = cfqd->queue;
 
-               if (cfqq) {
-                       INIT_LIST_HEAD(&cfqq->cfq_hash);
-                       INIT_LIST_HEAD(&cfqq->cfq_list);
-                       RB_CLEAR_ROOT(&cfqq->sort_list);
+retry:
+       cfqq = __cfq_find_cfq_hash(cfqd, pid, hashval);
 
-                       cfqq->pid = pid;
-                       cfqq->queued[0] = cfqq->queued[1] = 0;
-                       list_add(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
-               }
+       if (!cfqq) {
+               if (new_cfqq) {
+                       cfqq = new_cfqq;
+                       new_cfqq = NULL;
+               } else if (gfp_mask & __GFP_WAIT) {
+                       spin_unlock_irq(q->queue_lock);
+                       new_cfqq = mempool_alloc(cfq_mpool, gfp_mask);
+                       spin_lock_irq(q->queue_lock);
+                       goto retry;
+               } else
+                       return NULL;
+
+               INIT_LIST_HEAD(&cfqq->cfq_hash);
+               INIT_LIST_HEAD(&cfqq->cfq_list);
+               RB_CLEAR_ROOT(&cfqq->sort_list);
+
+               cfqq->pid = pid;
+               cfqq->queued[0] = cfqq->queued[1] = 0;
+               list_add(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
        }
 
+       if (new_cfqq)
+               mempool_free(new_cfqq, cfq_mpool);
+
        return cfqq;
 }
 
@@ -653,6 +667,7 @@ static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 
        crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
        if (crq) {
+               memset(crq, 0, sizeof(*crq));
                RB_CLEAR(&crq->rb_node);
                crq->request = rq;
                crq->cfq_queue = NULL;