From 62aec1e215961b52b586fbb89e416bf5c1af80fc Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Tue, 21 Dec 2010 13:28:44 +0100 Subject: [PATCH 11/84] lsbd: check for invalid lcache entries --- drivers/block/lsbd.c | 62 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/drivers/block/lsbd.c b/drivers/block/lsbd.c index 3fee0a3..45e2292 100644 --- a/drivers/block/lsbd.c +++ b/drivers/block/lsbd.c @@ -73,6 +73,7 @@ struct lsbd { spinlock_t lock; struct semaphore mutex; + unsigned int psectors; unsigned int lsectors; unsigned long long epoch; @@ -412,6 +413,22 @@ static int lsbd_find_current_block(struct lsbd *p) p->cur_block, p->epoch, reads); return 0; } + +/** + * lsbd_psector_valid - check if physical sector identifier is valid + * @p: LSBD device + * @psector: physical sector identifier to check + * + * This function returns non-zero on success; zero otherwise. + */ +static int lsbd_psector_valid(struct lsbd *p, unsigned int psector) +{ + if (psector == LSBD_SECT_INVALID) + return 1; + if (psector == LSBD_SECT_ZERO) + return 1; + return psector < p->psectors; +} /** * lsbd_read_lcache - create lcache mapping @@ -485,6 +502,7 @@ int lsbd_read_lcache(struct lsbd *p) if (p->lcache[sector_id] == LSBD_SECT_INVALID) { p->lcache[sector_id] = block * p->sectors_per_block + i + 1; + BUG_ON(p->lcache[sector_id] >= p->psectors); readed++; } } @@ -519,13 +537,23 @@ int lsbd_read_lcache(struct lsbd *p) } for (i = 0; i < lcache_chunk; i++) { - unsigned long long sector_id = lcache_base + i; + unsigned int sector_id = lcache_base + i; if (sector_id >= p->lsectors) break; if (p->lcache[sector_id] == LSBD_SECT_INVALID) { - p->lcache[sector_id] = be32_to_cpu(cache[i]); - readed++; + unsigned int psector; + + psector = be32_to_cpu(cache[i]); + if (lsbd_psector_valid(p, psector)) { + p->lcache[sector_id] = psector; + readed++; + } else { + lsbd_info(p, "lcache: invalid entry %d " + "-> %d\n", + sector_id, + psector); + } } } brelse(bh); @@ -658,6 +686,7 @@ static int lsbd_load_params(struct lsbd *p) if (blocks < p->blocks) { p->blocks = blocks; + p->psectors = p->blocks * p->sectors_per_block; lsbd_info(p, "shrinking device to %d blocks\n", p->blocks); } else if (blocks > p->blocks) { @@ -740,6 +769,7 @@ static int lsbd_mount(struct lsbd *p) if (blk_size[MAJOR(p->dev)]) size = blk_size[MAJOR(p->dev)][MINOR(p->dev)]; p->blocks = size / (lsbd_block_size(p) >> 10); + p->psectors = p->blocks * p->sectors_per_block; lsbd_info(p, "%d KiB sectors, %d KiB blocks, %d blocks\n", p->sector_size >> 10, lsbd_block_size(p) >> 10, p->blocks); @@ -1000,8 +1030,15 @@ static int lsbd_queue_bh(struct lsbd *p, struct buffer_head *bh, if (sector >= p->lsectors) return -EINVAL; - if (!move) - down(&p->req_sem); + if (!move) { + if (current == p->tsk) { + lsbd_info(p, "%s: BUG?\n", current->comm); + dump_stack(); + } else { + lsbd_info(p, "%s: waiting on request\n", current->comm); + down(&p->req_sem); + } + } r = kmalloc(sizeof(*r), GFP_NOIO); if (r == NULL) { @@ -1066,6 +1103,12 @@ static int lsbd_make_request(request_queue_t *q, int rw, bh->b_end_io(bh, 1); return 0; } + if (sector >= p->psectors) { + lsbd_info(p, "invalid lcache entry: %d -> %d\n", + lsector, sector); + buffer_IO_error(bh); + return 0; + } bh->b_rsector = (unsigned long) p->lcache[lsector] << 3; lsbd_debug(p, "mapped to physical %ld\n", bh->b_rsector); @@ -1151,8 +1194,8 @@ void lsbd_clean_block(struct lsbd *p) sects = (void *) (bh->b_data + b->ptab_offset); for (i = 0; i < sectors; i++) { - unsigned long long sector_id = be64_to_cpu(sects[i].id); - unsigned long s = block * p->sectors_per_block + i; + unsigned int sector_id = be64_to_cpu(sects[i].id); + unsigned int s = block * p->sectors_per_block + i; if (sector_id >= p->lsectors) continue; @@ -1163,8 +1206,10 @@ void lsbd_clean_block(struct lsbd *p) lock_buffer(rbh); ret = lsbd_queue_bh(p, rbh, s, LSBD_QUEUE_MOVE); - if (ret) + if (ret) { + unlock_buffer(rbh); brelse(rbh); + } } } brelse(bh); @@ -1324,6 +1369,7 @@ static int lsbd_write_block(struct lsbd *p) sects[i].id = cpu_to_be32(r->sector); p->lcache[r->sector] = p->cur_block * p->sectors_per_block + i + 1; + BUG_ON(p->lcache[r->sector] >= p->psectors); memcpy(bh[i + 1]->b_data, r->bh->b_data, p->sector_size); move = r->move; -- 1.8.4.652.g0d6e0ce