Commit e0ee7785 authored by NeilBrown's avatar NeilBrown

md/raid10: fix problem with on-stack allocation of r10bio structure.

A 'struct r10bio' has an array of per-copy information at the end.
This array is declared with size [0] and r10bio_pool_alloc allocates
enough extra space to store the per-copy information depending on the
number of copies needed.

So declaring a 'struct r10bio on the stack isn't going to work.  It
won't allocate enough space, and memory corruption will ensue.

So in the two places where this is done, declare a sufficiently large
structure and use that instead.

The two call-sites of this bug were introduced in 3.4 and 3.5
so this is suitable for both those kernels.  The patch will have to
be modified for 3.4 as it only has one bug.

Cc: stable@vger.kernel.org
Reported-by: default avatarIvan Vasilyev <ivan.vasilyev@gmail.com>
Tested-by: default avatarIvan Vasilyev <ivan.vasilyev@gmail.com>
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
parent 667a5313
...@@ -659,7 +659,11 @@ static int raid10_mergeable_bvec(struct request_queue *q, ...@@ -659,7 +659,11 @@ static int raid10_mergeable_bvec(struct request_queue *q,
max = biovec->bv_len; max = biovec->bv_len;
if (mddev->merge_check_needed) { if (mddev->merge_check_needed) {
struct {
struct r10bio r10_bio; struct r10bio r10_bio;
struct r10dev devs[conf->copies];
} on_stack;
struct r10bio *r10_bio = &on_stack.r10_bio;
int s; int s;
if (conf->reshape_progress != MaxSector) { if (conf->reshape_progress != MaxSector) {
/* Cannot give any guidance during reshape */ /* Cannot give any guidance during reshape */
...@@ -667,18 +671,18 @@ static int raid10_mergeable_bvec(struct request_queue *q, ...@@ -667,18 +671,18 @@ static int raid10_mergeable_bvec(struct request_queue *q,
return biovec->bv_len; return biovec->bv_len;
return 0; return 0;
} }
r10_bio.sector = sector; r10_bio->sector = sector;
raid10_find_phys(conf, &r10_bio); raid10_find_phys(conf, r10_bio);
rcu_read_lock(); rcu_read_lock();
for (s = 0; s < conf->copies; s++) { for (s = 0; s < conf->copies; s++) {
int disk = r10_bio.devs[s].devnum; int disk = r10_bio->devs[s].devnum;
struct md_rdev *rdev = rcu_dereference( struct md_rdev *rdev = rcu_dereference(
conf->mirrors[disk].rdev); conf->mirrors[disk].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) { if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct request_queue *q = struct request_queue *q =
bdev_get_queue(rdev->bdev); bdev_get_queue(rdev->bdev);
if (q->merge_bvec_fn) { if (q->merge_bvec_fn) {
bvm->bi_sector = r10_bio.devs[s].addr bvm->bi_sector = r10_bio->devs[s].addr
+ rdev->data_offset; + rdev->data_offset;
bvm->bi_bdev = rdev->bdev; bvm->bi_bdev = rdev->bdev;
max = min(max, q->merge_bvec_fn( max = min(max, q->merge_bvec_fn(
...@@ -690,7 +694,7 @@ static int raid10_mergeable_bvec(struct request_queue *q, ...@@ -690,7 +694,7 @@ static int raid10_mergeable_bvec(struct request_queue *q,
struct request_queue *q = struct request_queue *q =
bdev_get_queue(rdev->bdev); bdev_get_queue(rdev->bdev);
if (q->merge_bvec_fn) { if (q->merge_bvec_fn) {
bvm->bi_sector = r10_bio.devs[s].addr bvm->bi_sector = r10_bio->devs[s].addr
+ rdev->data_offset; + rdev->data_offset;
bvm->bi_bdev = rdev->bdev; bvm->bi_bdev = rdev->bdev;
max = min(max, q->merge_bvec_fn( max = min(max, q->merge_bvec_fn(
...@@ -4414,14 +4418,18 @@ static int handle_reshape_read_error(struct mddev *mddev, ...@@ -4414,14 +4418,18 @@ static int handle_reshape_read_error(struct mddev *mddev,
{ {
/* Use sync reads to get the blocks from somewhere else */ /* Use sync reads to get the blocks from somewhere else */
int sectors = r10_bio->sectors; int sectors = r10_bio->sectors;
struct r10bio r10b;
struct r10conf *conf = mddev->private; struct r10conf *conf = mddev->private;
struct {
struct r10bio r10_bio;
struct r10dev devs[conf->copies];
} on_stack;
struct r10bio *r10b = &on_stack.r10_bio;
int slot = 0; int slot = 0;
int idx = 0; int idx = 0;
struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec; struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec;
r10b.sector = r10_bio->sector; r10b->sector = r10_bio->sector;
__raid10_find_phys(&conf->prev, &r10b); __raid10_find_phys(&conf->prev, r10b);
while (sectors) { while (sectors) {
int s = sectors; int s = sectors;
...@@ -4432,7 +4440,7 @@ static int handle_reshape_read_error(struct mddev *mddev, ...@@ -4432,7 +4440,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
s = PAGE_SIZE >> 9; s = PAGE_SIZE >> 9;
while (!success) { while (!success) {
int d = r10b.devs[slot].devnum; int d = r10b->devs[slot].devnum;
struct md_rdev *rdev = conf->mirrors[d].rdev; struct md_rdev *rdev = conf->mirrors[d].rdev;
sector_t addr; sector_t addr;
if (rdev == NULL || if (rdev == NULL ||
...@@ -4440,7 +4448,7 @@ static int handle_reshape_read_error(struct mddev *mddev, ...@@ -4440,7 +4448,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
!test_bit(In_sync, &rdev->flags)) !test_bit(In_sync, &rdev->flags))
goto failed; goto failed;
addr = r10b.devs[slot].addr + idx * PAGE_SIZE; addr = r10b->devs[slot].addr + idx * PAGE_SIZE;
success = sync_page_io(rdev, success = sync_page_io(rdev,
addr, addr,
s << 9, s << 9,
......
...@@ -110,7 +110,7 @@ struct r10bio { ...@@ -110,7 +110,7 @@ struct r10bio {
* We choose the number when they are allocated. * We choose the number when they are allocated.
* We sometimes need an extra bio to write to the replacement. * We sometimes need an extra bio to write to the replacement.
*/ */
struct { struct r10dev {
struct bio *bio; struct bio *bio;
union { union {
struct bio *repl_bio; /* used for resync and struct bio *repl_bio; /* used for resync and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment