diff options
Diffstat (limited to 'block/cfq-iosched.c')
| -rw-r--r-- | block/cfq-iosched.c | 16 | 
1 files changed, 14 insertions, 2 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 16ace89613b..4c12869fcf7 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -3184,7 +3184,7 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,  		}  	} -	if (ret) +	if (ret && ret != -EEXIST)  		printk(KERN_ERR "cfq: cic link failed!\n");  	return ret; @@ -3200,6 +3200,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)  {  	struct io_context *ioc = NULL;  	struct cfq_io_context *cic; +	int ret;  	might_sleep_if(gfp_mask & __GFP_WAIT); @@ -3207,6 +3208,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)  	if (!ioc)  		return NULL; +retry:  	cic = cfq_cic_lookup(cfqd, ioc);  	if (cic)  		goto out; @@ -3215,7 +3217,12 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)  	if (cic == NULL)  		goto err; -	if (cfq_cic_link(cfqd, ioc, cic, gfp_mask)) +	ret = cfq_cic_link(cfqd, ioc, cic, gfp_mask); +	if (ret == -EEXIST) { +		/* someone has linked cic to ioc already */ +		cfq_cic_free(cic); +		goto retry; +	} else if (ret)  		goto err_free;  out: @@ -4036,6 +4043,11 @@ static void *cfq_init_queue(struct request_queue *q)  	if (blkio_alloc_blkg_stats(&cfqg->blkg)) {  		kfree(cfqg); + +		spin_lock(&cic_index_lock); +		ida_remove(&cic_index_ida, cfqd->cic_index); +		spin_unlock(&cic_index_lock); +  		kfree(cfqd);  		return NULL;  	}  |