diff options
author | Robert Elliott <elliott@hp.com> | 2014-09-02 12:38:44 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-09-03 12:44:15 -0400 |
commit | 5676e7b6db02b80eafc2e3ad316d5f2fee817ecb (patch) | |
tree | 540c780f1bb691971d55bffdbecec972ffa5e5eb | |
parent | dc501dc0d9dc9cbabc18b920f91a26c207e9476c (diff) |
blk-mq: cleanup after blk_mq_init_rq_map failures
In blk-mq.c blk_mq_alloc_tag_set, if:
set->tags = kmalloc_node()
succeeds, but one of the blk_mq_init_rq_map() calls fails,
goto out_unwind;
needs to free set->tags so the caller is not obligated
to do so. None of the current callers (null_blk,
virtio_blk, virtio_blk, or the forthcoming scsi-mq)
do so.
set->tags needs to be set to NULL after doing so,
so other tag cleanup logic doesn't try to free
a stale pointer later. Also set it to NULL
in blk_mq_free_tag_set.
Tested with error injection on the forthcoming
scsi-mq + hpsa combination.
Signed-off-by: Robert Elliott <elliott@hp.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | block/blk-mq.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/block/blk-mq.c b/block/blk-mq.c index 4aac82615a46..f9b85e83d9ba 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c | |||
@@ -1982,6 +1982,8 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set) | |||
1982 | out_unwind: | 1982 | out_unwind: |
1983 | while (--i >= 0) | 1983 | while (--i >= 0) |
1984 | blk_mq_free_rq_map(set, set->tags[i], i); | 1984 | blk_mq_free_rq_map(set, set->tags[i], i); |
1985 | kfree(set->tags); | ||
1986 | set->tags = NULL; | ||
1985 | out: | 1987 | out: |
1986 | return -ENOMEM; | 1988 | return -ENOMEM; |
1987 | } | 1989 | } |
@@ -1997,6 +1999,7 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set) | |||
1997 | } | 1999 | } |
1998 | 2000 | ||
1999 | kfree(set->tags); | 2001 | kfree(set->tags); |
2002 | set->tags = NULL; | ||
2000 | } | 2003 | } |
2001 | EXPORT_SYMBOL(blk_mq_free_tag_set); | 2004 | EXPORT_SYMBOL(blk_mq_free_tag_set); |
2002 | 2005 | ||