summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2003-05-26 07:05:55 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-05-26 07:05:55 -0700
commit31458043214802d7bb86552a420f2a7e3c81e1b7 (patch)
tree2d3c4b9427390efd065c85fc65ff3ff5567a0004
parent757400c3f3d5d732d04fb9b20cf45797387a3917 (diff)
[PATCH] md: Remove MD_SB_DISKS limits from raid1
raid1 uses MD_SB_DISKS to size two data structures, but the new version-1 superblock allows for more than this number of disks (and most actual arrays use many fewer). This patch sizes to two arrays dynamically. One becomes a separate kmalloced array. The other is moved to the end of the containing structure and appropriate extra space is allocated. Also, change r1buf_pool_alloc (which allocates buffers for a mempool for doing re-sync) to not get r1bio structures from the r1bio pool (which could exhaust the pool) but instead to allocate them separately.
-rw-r--r--drivers/md/raid1.c29
-rw-r--r--include/linux/raid/raid1.h11
2 files changed, 28 insertions, 12 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 3c92652762c3..9cf99f812690 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -40,9 +40,12 @@ static LIST_HEAD(retry_list_head);
static void * r1bio_pool_alloc(int gfp_flags, void *data)
{
+ mddev_t *mddev = data;
r1bio_t *r1_bio;
- r1_bio = kmalloc(sizeof(r1bio_t), gfp_flags);
+ /* allocate a r1bio with room for raid_disks entries in the write_bios array */
+ r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*mddev->raid_disks,
+ gfp_flags);
if (r1_bio)
memset(r1_bio, 0, sizeof(*r1_bio));
@@ -67,8 +70,9 @@ static void * r1buf_pool_alloc(int gfp_flags, void *data)
struct bio *bio;
int i, j;
- r1_bio = mempool_alloc(conf->r1bio_pool, gfp_flags);
-
+ r1_bio = r1bio_pool_alloc(gfp_flags, conf->mddev);
+ if (!r1_bio)
+ return NULL;
bio = bio_alloc(gfp_flags, RESYNC_PAGES);
if (!bio)
goto out_free_r1_bio;
@@ -101,7 +105,7 @@ out_free_pages:
__free_page(bio->bi_io_vec[j].bv_page);
bio_put(bio);
out_free_r1_bio:
- mempool_free(r1_bio, conf->r1bio_pool);
+ r1bio_pool_free(r1_bio, conf->mddev);
return NULL;
}
@@ -121,7 +125,7 @@ static void r1buf_pool_free(void *__r1_bio, void *data)
if (atomic_read(&bio->bi_cnt) != 1)
BUG();
bio_put(bio);
- mempool_free(r1bio, conf->r1bio_pool);
+ r1bio_pool_free(r1bio, conf->mddev);
}
static void put_all_bios(conf_t *conf, r1bio_t *r1_bio)
@@ -1085,13 +1089,20 @@ static int run(mddev_t *mddev)
goto out;
}
memset(conf, 0, sizeof(*conf));
+ conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks,
+ GFP_KERNEL);
+ if (!conf->mirrors) {
+ printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n",
+ mdidx(mddev));
+ goto out_free_conf;
+ }
conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,
- r1bio_pool_free, NULL);
+ r1bio_pool_free, mddev);
if (!conf->r1bio_pool) {
printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n",
mdidx(mddev));
- goto out;
+ goto out_free_conf;
}
@@ -1169,6 +1180,8 @@ static int run(mddev_t *mddev)
out_free_conf:
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
+ if (conf->mirrors)
+ kfree(conf->mirrors);
kfree(conf);
mddev->private = NULL;
out:
@@ -1183,6 +1196,8 @@ static int stop(mddev_t *mddev)
mddev->thread = NULL;
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
+ if (conf->mirrors)
+ kfree(conf->mirrors);
kfree(conf);
mddev->private = NULL;
return 0;
diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
index cc7aa899a613..a9d1161ccab3 100644
--- a/include/linux/raid/raid1.h
+++ b/include/linux/raid/raid1.h
@@ -14,7 +14,7 @@ typedef struct r1bio_s r1bio_t;
struct r1_private_data_s {
mddev_t *mddev;
- mirror_info_t mirrors[MD_SB_DISKS];
+ mirror_info_t *mirrors;
int raid_disks;
int working_disks;
int last_used;
@@ -67,13 +67,14 @@ struct r1bio_s {
*/
struct bio *read_bio;
int read_disk;
- /*
- * if the IO is in WRITE direction, then multiple bios are used:
- */
- struct bio *write_bios[MD_SB_DISKS];
r1bio_t *next_r1; /* next for retry or in free list */
struct list_head retry_list;
+ /*
+ * if the IO is in WRITE direction, then multiple bios are used.
+ * We choose the number when they are allocated.
+ */
+ struct bio *write_bios[0];
};
/* bits for r1bio.state */