md/r5cache: Check array size in r5l_init_log

Currently, r5l_write_stripe checks meta size for each stripe write,
which is not necessary.

With this patch, r5l_init_log checks maximal meta size of the array,
which is (r5l_meta_block + raid_disks x r5l_payload_data_parity).
If this is too big to fit in one page, r5l_init_log aborts.

With current meta data, r5l_log support raid_disks up to 203.

Signed-off-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Shaohua Li <shli@fb.com>
This commit is contained in:
Song Liu 2016-11-17 15:24:36 -08:00 committed by Shaohua Li
parent 504634f60f
commit c757ec95c2
1 changed files with 16 additions and 10 deletions

View File

@ -441,7 +441,6 @@ int r5l_write_stripe(struct r5l_log *log, struct stripe_head *sh)
{ {
int write_disks = 0; int write_disks = 0;
int data_pages, parity_pages; int data_pages, parity_pages;
int meta_size;
int reserve; int reserve;
int i; int i;
int ret = 0; int ret = 0;
@ -473,15 +472,6 @@ int r5l_write_stripe(struct r5l_log *log, struct stripe_head *sh)
parity_pages = 1 + !!(sh->qd_idx >= 0); parity_pages = 1 + !!(sh->qd_idx >= 0);
data_pages = write_disks - parity_pages; data_pages = write_disks - parity_pages;
meta_size =
((sizeof(struct r5l_payload_data_parity) + sizeof(__le32))
* data_pages) +
sizeof(struct r5l_payload_data_parity) +
sizeof(__le32) * parity_pages;
/* Doesn't work with very big raid array */
if (meta_size + sizeof(struct r5l_meta_block) > PAGE_SIZE)
return -EINVAL;
set_bit(STRIPE_LOG_TRAPPED, &sh->state); set_bit(STRIPE_LOG_TRAPPED, &sh->state);
/* /*
* The stripe must enter state machine again to finish the write, so * The stripe must enter state machine again to finish the write, so
@ -1197,6 +1187,22 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
if (PAGE_SIZE != 4096) if (PAGE_SIZE != 4096)
return -EINVAL; return -EINVAL;
/*
* The PAGE_SIZE must be big enough to hold 1 r5l_meta_block and
* raid_disks r5l_payload_data_parity.
*
* Write journal and cache does not work for very big array
* (raid_disks > 203)
*/
if (sizeof(struct r5l_meta_block) +
((sizeof(struct r5l_payload_data_parity) + sizeof(__le32)) *
conf->raid_disks) > PAGE_SIZE) {
pr_err("md/raid:%s: write journal/cache doesn't work for array with %d disks\n",
mdname(conf->mddev), conf->raid_disks);
return -EINVAL;
}
log = kzalloc(sizeof(*log), GFP_KERNEL); log = kzalloc(sizeof(*log), GFP_KERNEL);
if (!log) if (!log)
return -ENOMEM; return -ENOMEM;