diff options
| author | Shaohua Li <shli@fb.com> | 2016-08-23 00:14:01 -0400 |
|---|---|---|
| committer | Shaohua Li <shli@fb.com> | 2016-08-24 13:21:52 -0400 |
| commit | 5f9d1fde7d54a5d5fd8cccbee9c9c31474fcdcf2 (patch) | |
| tree | 928efbe6ba6efef4e84eed37103038015770614a | |
| parent | 27028626b4b9022dcac23688e09ea43b36e1183c (diff) | |
raid5: fix memory leak of bio integrity data
Yi reported a memory leak of raid5 with DIF/DIX enabled disks. raid5
doesn't alloc/free bio, instead it reuses bios. There are two issues in
current code:
1. the code calls bio_init (from
init_stripe->raid5_build_block->bio_init) then bio_reset (ops_run_io).
The bio is reused, so likely there is integrity data attached. bio_init
will clear a pointer to integrity data and makes bio_reset can't release
the data
2. bio_reset is called before dispatching bio. After bio is finished,
it's possible we don't free bio's integrity data (eg, we don't call
bio_reset again)
Both issues will cause memory leak. The patch moves bio_init to stripe
creation and bio_reset to bio end io. This will fix the two issues.
Reported-by: Yi Zhang <yizhan@redhat.com>
Signed-off-by: Shaohua Li <shli@fb.com>
| -rw-r--r-- | drivers/md/raid5.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2119e094dfb3..d1a279b1916b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -1005,7 +1005,6 @@ again: | |||
| 1005 | 1005 | ||
| 1006 | set_bit(STRIPE_IO_STARTED, &sh->state); | 1006 | set_bit(STRIPE_IO_STARTED, &sh->state); |
| 1007 | 1007 | ||
| 1008 | bio_reset(bi); | ||
| 1009 | bi->bi_bdev = rdev->bdev; | 1008 | bi->bi_bdev = rdev->bdev; |
| 1010 | bio_set_op_attrs(bi, op, op_flags); | 1009 | bio_set_op_attrs(bi, op, op_flags); |
| 1011 | bi->bi_end_io = op_is_write(op) | 1010 | bi->bi_end_io = op_is_write(op) |
| @@ -1057,7 +1056,6 @@ again: | |||
| 1057 | 1056 | ||
| 1058 | set_bit(STRIPE_IO_STARTED, &sh->state); | 1057 | set_bit(STRIPE_IO_STARTED, &sh->state); |
| 1059 | 1058 | ||
| 1060 | bio_reset(rbi); | ||
| 1061 | rbi->bi_bdev = rrdev->bdev; | 1059 | rbi->bi_bdev = rrdev->bdev; |
| 1062 | bio_set_op_attrs(rbi, op, op_flags); | 1060 | bio_set_op_attrs(rbi, op, op_flags); |
| 1063 | BUG_ON(!op_is_write(op)); | 1061 | BUG_ON(!op_is_write(op)); |
| @@ -1990,9 +1988,11 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request) | |||
| 1990 | put_cpu(); | 1988 | put_cpu(); |
| 1991 | } | 1989 | } |
| 1992 | 1990 | ||
| 1993 | static struct stripe_head *alloc_stripe(struct kmem_cache *sc, gfp_t gfp) | 1991 | static struct stripe_head *alloc_stripe(struct kmem_cache *sc, gfp_t gfp, |
| 1992 | int disks) | ||
| 1994 | { | 1993 | { |
| 1995 | struct stripe_head *sh; | 1994 | struct stripe_head *sh; |
| 1995 | int i; | ||
| 1996 | 1996 | ||
| 1997 | sh = kmem_cache_zalloc(sc, gfp); | 1997 | sh = kmem_cache_zalloc(sc, gfp); |
| 1998 | if (sh) { | 1998 | if (sh) { |
| @@ -2001,6 +2001,12 @@ static struct stripe_head *alloc_stripe(struct kmem_cache *sc, gfp_t gfp) | |||
| 2001 | INIT_LIST_HEAD(&sh->batch_list); | 2001 | INIT_LIST_HEAD(&sh->batch_list); |
| 2002 | INIT_LIST_HEAD(&sh->lru); | 2002 | INIT_LIST_HEAD(&sh->lru); |
| 2003 | atomic_set(&sh->count, 1); | 2003 | atomic_set(&sh->count, 1); |
| 2004 | for (i = 0; i < disks; i++) { | ||
| 2005 | struct r5dev *dev = &sh->dev[i]; | ||
| 2006 | |||
| 2007 | bio_init(&dev->req); | ||
| 2008 | bio_init(&dev->rreq); | ||
| 2009 | } | ||
| 2004 | } | 2010 | } |
| 2005 | return sh; | 2011 | return sh; |
| 2006 | } | 2012 | } |
| @@ -2008,7 +2014,7 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp) | |||
| 2008 | { | 2014 | { |
| 2009 | struct stripe_head *sh; | 2015 | struct stripe_head *sh; |
| 2010 | 2016 | ||
| 2011 | sh = alloc_stripe(conf->slab_cache, gfp); | 2017 | sh = alloc_stripe(conf->slab_cache, gfp, conf->pool_size); |
| 2012 | if (!sh) | 2018 | if (!sh) |
| 2013 | return 0; | 2019 | return 0; |
| 2014 | 2020 | ||
| @@ -2179,7 +2185,7 @@ static int resize_stripes(struct r5conf *conf, int newsize) | |||
| 2179 | mutex_lock(&conf->cache_size_mutex); | 2185 | mutex_lock(&conf->cache_size_mutex); |
| 2180 | 2186 | ||
| 2181 | for (i = conf->max_nr_stripes; i; i--) { | 2187 | for (i = conf->max_nr_stripes; i; i--) { |
| 2182 | nsh = alloc_stripe(sc, GFP_KERNEL); | 2188 | nsh = alloc_stripe(sc, GFP_KERNEL, newsize); |
| 2183 | if (!nsh) | 2189 | if (!nsh) |
| 2184 | break; | 2190 | break; |
| 2185 | 2191 | ||
| @@ -2311,6 +2317,7 @@ static void raid5_end_read_request(struct bio * bi) | |||
| 2311 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), | 2317 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), |
| 2312 | bi->bi_error); | 2318 | bi->bi_error); |
| 2313 | if (i == disks) { | 2319 | if (i == disks) { |
| 2320 | bio_reset(bi); | ||
| 2314 | BUG(); | 2321 | BUG(); |
| 2315 | return; | 2322 | return; |
| 2316 | } | 2323 | } |
| @@ -2414,6 +2421,7 @@ static void raid5_end_read_request(struct bio * bi) | |||
| 2414 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | 2421 | clear_bit(R5_LOCKED, &sh->dev[i].flags); |
| 2415 | set_bit(STRIPE_HANDLE, &sh->state); | 2422 | set_bit(STRIPE_HANDLE, &sh->state); |
| 2416 | raid5_release_stripe(sh); | 2423 | raid5_release_stripe(sh); |
| 2424 | bio_reset(bi); | ||
| 2417 | } | 2425 | } |
| 2418 | 2426 | ||
| 2419 | static void raid5_end_write_request(struct bio *bi) | 2427 | static void raid5_end_write_request(struct bio *bi) |
| @@ -2448,6 +2456,7 @@ static void raid5_end_write_request(struct bio *bi) | |||
| 2448 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), | 2456 | (unsigned long long)sh->sector, i, atomic_read(&sh->count), |
| 2449 | bi->bi_error); | 2457 | bi->bi_error); |
| 2450 | if (i == disks) { | 2458 | if (i == disks) { |
| 2459 | bio_reset(bi); | ||
| 2451 | BUG(); | 2460 | BUG(); |
| 2452 | return; | 2461 | return; |
| 2453 | } | 2462 | } |
| @@ -2491,18 +2500,17 @@ static void raid5_end_write_request(struct bio *bi) | |||
| 2491 | 2500 | ||
| 2492 | if (sh->batch_head && sh != sh->batch_head) | 2501 | if (sh->batch_head && sh != sh->batch_head) |
| 2493 | raid5_release_stripe(sh->batch_head); | 2502 | raid5_release_stripe(sh->batch_head); |
| 2503 | bio_reset(bi); | ||
| 2494 | } | 2504 | } |
| 2495 | 2505 | ||
| 2496 | static void raid5_build_block(struct stripe_head *sh, int i, int previous) | 2506 | static void raid5_build_block(struct stripe_head *sh, int i, int previous) |
| 2497 | { | 2507 | { |
| 2498 | struct r5dev *dev = &sh->dev[i]; | 2508 | struct r5dev *dev = &sh->dev[i]; |
| 2499 | 2509 | ||
| 2500 | bio_init(&dev->req); | ||
| 2501 | dev->req.bi_io_vec = &dev->vec; | 2510 | dev->req.bi_io_vec = &dev->vec; |
| 2502 | dev->req.bi_max_vecs = 1; | 2511 | dev->req.bi_max_vecs = 1; |
| 2503 | dev->req.bi_private = sh; | 2512 | dev->req.bi_private = sh; |
| 2504 | 2513 | ||
| 2505 | bio_init(&dev->rreq); | ||
| 2506 | dev->rreq.bi_io_vec = &dev->rvec; | 2514 | dev->rreq.bi_io_vec = &dev->rvec; |
| 2507 | dev->rreq.bi_max_vecs = 1; | 2515 | dev->rreq.bi_max_vecs = 1; |
| 2508 | dev->rreq.bi_private = sh; | 2516 | dev->rreq.bi_private = sh; |
