From efe78c6546e4f0d64a9b1f3877caee55c5821f2d Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Fri, 22 Jul 2011 21:48:42 +0200 Subject: [PATCH 47/84] lsbd: add lcache locking This patch adds SMP locking of lcache. --- drivers/block/lsbd.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/block/lsbd.c b/drivers/block/lsbd.c index a817a1d..6e3176f 100644 --- a/drivers/block/lsbd.c +++ b/drivers/block/lsbd.c @@ -101,6 +101,7 @@ struct lsbd { unsigned long sectors_written; unsigned long blocks_written; + rwlock_t lcache_lock; lsbd_lcache_t *lcache; unsigned int cur_lcache; @@ -1211,8 +1212,10 @@ static int lsbd_partition(struct lsbd *p, struct lsbd_part_info *part) for (i = 0; i < p->lsectors; i++) l[i] = p->lcache[i]; + write_lock(&p->lcache_lock); ol = p->lcache; p->lcache = l; + write_unlock(&p->lcache_lock); lsbd_start(p); @@ -1440,6 +1443,8 @@ static int lsbd_read_mirrored(struct lsbd *p, struct buffer_head *bh, * @p: LSBD device * @lsector: logical sector * @sector: current logical sector mapping + * + * This function should be called with locked lcache_lock for write. */ static int lsbd_switch_mirror(struct lsbd *p, unsigned int lsector, unsigned int sector) @@ -1489,7 +1494,9 @@ static int lsbd_make_read(struct lsbd *p, int rw, struct buffer_head *bh) return 0; } + read_lock(&p->lcache_lock); sector = p->lcache[lsector]; + read_unlock(&p->lcache_lock); lsbd_debug(p, "read %d, mapped to %d\n", lsector, sector); if (sector == LSBD_SECT_INVALID) { buffer_IO_error(bh); @@ -1511,7 +1518,7 @@ static int lsbd_make_read(struct lsbd *p, int rw, struct buffer_head *bh) * just remapped to lower level device */ if (!p->mirrored) { - bh->b_rsector = (unsigned long) p->lcache[lsector] << 3; + bh->b_rsector = (unsigned long) sector << 3; lsbd_debug(p, "mapped to physical %ld\n", bh->b_rsector); bh->b_rdev = p->dev; @@ -1527,9 +1534,13 @@ static int lsbd_make_read(struct lsbd *p, int rw, struct buffer_head *bh) return 0; p->read_errors++; + /* try to switch this sector to mirror and retry */ + write_lock(&p->lcache_lock); lsbd_switch_mirror(p, lsector, sector); sector = p->lcache[lsector]; + write_unlock(&p->lcache_lock); + if (sector >= p->psectors) { lsbd_info(p, "invalid lcache entry: %d -> %d\n", lsector, sector); @@ -1677,15 +1688,18 @@ void lsbd_clean_block(struct lsbd *p) for (i = 0; i < sectors; i++) { unsigned int sector_id = be32_to_cpu(sects[i].id); unsigned int s = block * p->sectors_per_block + i + 1; + unsigned int sector; if (sector_id >= p->lsectors) continue; + read_lock(&p->lcache_lock); + sector = p->lcache[sector_id]; + read_unlock(&p->lcache_lock); lsbd_debug(p, "block %ld.%ld: logical %d, phys %d, " "lcache %d\n", - block, i, sector_id, s, - (unsigned int) p->lcache[sector_id]); - if (p->lcache[sector_id] == s) { + block, i, sector_id, s, sector); + if (sector == s) { rbh = lsbd_sread(p, block, i + 1); if (rbh == NULL) continue; @@ -1773,6 +1787,7 @@ static int lsbd_write_lcache(struct lsbd *p, void *bp) b->lcache_chunk = cpu_to_be32(chunk); cache = (void *) ((char *) bp + be32_to_cpu(b->lcache_offset)); + read_lock(&p->lcache_lock); for (i = 0; i < chunk; i++) { unsigned long long sector_id = p->cur_lcache + i; @@ -1780,6 +1795,7 @@ static int lsbd_write_lcache(struct lsbd *p, void *bp) break; cache[i] = cpu_to_be32(p->lcache[sector_id]); } + read_unlock(&p->lcache_lock); b->lcache_checksum = cpu_to_be32(lsbd_checksum(cache, chunk * sizeof(*cache))); @@ -1929,9 +1945,13 @@ static int lsbd_write_block(struct lsbd *p) BUG_ON(r->sector >= p->lsectors); sects[i].id = cpu_to_be32(r->sector); + + write_lock(&p->lcache_lock); p->lcache[r->sector] = p->cur_block * p->sectors_per_block + i + 1; BUG_ON(p->lcache[r->sector] >= p->psectors); + write_unlock(&p->lcache_lock); + memcpy(bh[i + 1]->b_data, r->bh->b_data, p->sector_size); move = r->move; -- 1.8.4.652.g0d6e0ce