From 9f9e93fe8365285652d40a83958d455542e8266b Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Wed, 27 Jul 2011 20:53:45 +0200 Subject: [PATCH 53/84] lsbd: fix cleaning in mirrored devices In case of mirrored only even blocks were checked and sector numbers were checked against lcache using normal equality operator. This caused skipping of sectors mapped to odd blocks. Such mapping is very frequent because of ptab - all sectors mapping written after lcache write are readed using ptab instead of lcache. --- drivers/block/lsbd.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/block/lsbd.c b/drivers/block/lsbd.c index e760292..39ee11b 100644 --- a/drivers/block/lsbd.c +++ b/drivers/block/lsbd.c @@ -1656,6 +1656,28 @@ static int lsbd_make_request(request_queue_t *q, int rw, struct buffer_head *bh) } /** + * lsbd_sector_eq - compare physical sectors numbers + * @p: LSBD device + * @a: first sector + * @b: second sector + * + * This function returns non-zero value when both sector numbers are equal; + * zero otherwise. + * + * In case of mirroring the comparsion is not-trivial and a == b cannot + * be used. + */ +static int lsbd_sector_eq(struct lsbd *p, unsigned int a, unsigned b) +{ + /* in case of mirroring we need to normalize sector numbers */ + if (p->mirrored) { + a &= ~p->sectors_per_block; + b &= ~p->sectors_per_block; + } + return a == b; +} + +/** * lsbd_clean_block - clean next LSBD block * @p: LSBD device * @@ -1682,9 +1704,12 @@ void lsbd_clean_block(struct lsbd *p) if (block >= p->blocks) block = 0; + /* + * in case of error on even block in mirrored devices we just + * skip such block and the next block will be properly cleared + */ if (!(block & 1) && p->mirrored) { - if (block + 1 >= p->blocks) - block = 0; + BUG_ON(block + 1 >= p->blocks); mirrored = 1; } @@ -1745,7 +1770,8 @@ void lsbd_clean_block(struct lsbd *p) lsbd_debug(p, "block %ld.%ld: logical %d, phys %d, " "lcache %d\n", block, i, sector_id, s, sector); - if (sector == s) { + + if (lsbd_sector_eq(p, sector, s)) { rbh = lsbd_sread(p, block, i + 1); if (rbh == NULL) continue; -- 1.8.4.652.g0d6e0ce