From 1140b22f8cf24a7f1aa08655bdbbfee85873a87a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 14 Jul 2004 19:23:57 -0700 Subject: [PATCH] [PATCH] CFQ: allocation under lock, missing memset on allocation 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 Signed-off-by: Linus Torvalds --- drivers/block/cfq-iosched.c | 39 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index fc5f519ed8926..068f4eae0b5cf 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -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; -- 2.53.0