aboutsummaryrefslogtreecommitdiff
path: root/linux/dev/glue/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/dev/glue/block.c')
-rw-r--r--linux/dev/glue/block.c50
1 files changed, 45 insertions, 5 deletions
diff --git a/linux/dev/glue/block.c b/linux/dev/glue/block.c
index a8cb9b3f..ee5ef7bc 100644
--- a/linux/dev/glue/block.c
+++ b/linux/dev/glue/block.c
@@ -442,6 +442,22 @@ enqueue_request (struct request *req)
sti ();
}
+int
+check_rw_block (int nr, struct buffer_head **bh)
+{
+ int i, bshift, bsize;
+ get_block_size (bh[0]->b_dev, &bsize, &bshift);
+ loff_t sectorl = bh[0]->b_blocknr << (bshift - 9);
+
+ for (i = 0; i < nr; i++)
+ {
+ sectorl += bh[i]->b_size >> 9;
+ unsigned long sector = sectorl;
+ if (sector != sectorl)
+ return -EOVERFLOW;
+ }
+}
+
/* Perform the I/O operation RW on the buffer list BH
containing NR buffers. */
void
@@ -506,11 +522,15 @@ rdwr_partial (int rw, kdev_t dev, loff_t *off,
long sect, nsect;
struct buffer_head bhead, *bh = &bhead;
struct gendisk *gd;
+ loff_t blkl;
memset (bh, 0, sizeof (struct buffer_head));
bh->b_state = 1 << BH_Lock;
bh->b_dev = dev;
- bh->b_blocknr = *off >> bshift;
+ blkl = *off >> bshift;
+ bh->b_blocknr = blkl;
+ if (bh->b_blocknr != blkl)
+ return -EOVERFLOW;
bh->b_size = BSIZE;
/* Check if this device has non even number of blocks. */
@@ -522,7 +542,9 @@ rdwr_partial (int rw, kdev_t dev, loff_t *off,
}
if (nsect > 0)
{
- sect = bh->b_blocknr << (bshift - 9);
+ loff_t sectl;
+ sectl = bh->b_blocknr << (bshift - 9);
+ sect = sectl;
assert ((nsect - sect) > 0);
if (nsect - sect < (BSIZE >> 9))
bh->b_size = (nsect - sect) << 9;
@@ -530,6 +552,9 @@ rdwr_partial (int rw, kdev_t dev, loff_t *off,
bh->b_data = alloc_buffer (bh->b_size);
if (! bh->b_data)
return -ENOMEM;
+ err = check_rw_block (1, &bh);
+ if (err)
+ goto out;
ll_rw_block (READ, 1, &bh, 0);
wait_on_buffer (bh);
if (buffer_uptodate (bh))
@@ -544,6 +569,9 @@ rdwr_partial (int rw, kdev_t dev, loff_t *off,
{
memcpy (bh->b_data + o, *buf, c);
bh->b_state = (1 << BH_Dirty) | (1 << BH_Lock);
+ err = check_rw_block (1, &bh);
+ if (err)
+ goto out;
ll_rw_block (WRITE, 1, &bh, 0);
wait_on_buffer (bh);
if (! buffer_uptodate (bh))
@@ -576,14 +604,18 @@ static int
rdwr_full (int rw, kdev_t dev, loff_t *off, char **buf, int *resid, int bshift)
{
int cc, err = 0, i, j, nb, nbuf;
- long blk;
+ loff_t blkl;
+ long blk, newblk;
struct buffer_head bhead[MAX_BUF], *bh, *bhp[MAX_BUF];
phys_addr_t pa;
assert ((*off & BMASK) == 0);
nbuf = *resid >> bshift;
- blk = *off >> bshift;
+ blkl = *off >> bshift;
+ blk = blkl;
+ if (blk != blkl)
+ return -EOVERFLOW;
for (i = nb = 0, bh = bhead; nb < nbuf; bh++)
{
memset (bh, 0, sizeof (*bh));
@@ -621,11 +653,19 @@ rdwr_full (int rw, kdev_t dev, loff_t *off, char **buf, int *resid, int bshift)
bh->b_size = cc;
bhp[i] = bh;
nb += cc >> bshift;
- blk += cc >> bshift;
+ newblk = blk + (cc >> bshift);
+ if (newblk < blk)
+ {
+ err = -EOVERFLOW;
+ break;
+ }
+ blk = newblk;
if (++i == MAX_BUF)
break;
}
if (! err)
+ err = check_rw_block (i, bhp);
+ if (! err)
{
assert (i > 0);
ll_rw_block (rw, i, bhp, 0);