Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 336218
b: refs/heads/master
c: 57302e0
h: refs/heads/master
v: v3
  • Loading branch information
Linus Torvalds committed Dec 4, 2012
1 parent a97d72c commit e639278
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b69f0859dc8e633c5d8c06845811588fe17e68b3
refs/heads/master: 57302e0ddf8a210a66fd8a1a2fa50844863b5ded
52 changes: 52 additions & 0 deletions trunk/fs/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2893,6 +2893,55 @@ static void end_bio_bh_io_sync(struct bio *bio, int err)
bio_put(bio);
}

/*
* This allows us to do IO even on the odd last sectors
* of a device, even if the bh block size is some multiple
* of the physical sector size.
*
* We'll just truncate the bio to the size of the device,
* and clear the end of the buffer head manually.
*
* Truly out-of-range accesses will turn into actual IO
* errors, this only handles the "we need to be able to
* do IO at the final sector" case.
*/
static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh)
{
sector_t maxsector;
unsigned bytes;

maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
if (!maxsector)
return;

/*
* If the *whole* IO is past the end of the device,
* let it through, and the IO layer will turn it into
* an EIO.
*/
if (unlikely(bio->bi_sector >= maxsector))
return;

maxsector -= bio->bi_sector;
bytes = bio->bi_size;
if (likely((bytes >> 9) <= maxsector))
return;

/* Uhhuh. We've got a bh that straddles the device size! */
bytes = maxsector << 9;

/* Truncate the bio.. */
bio->bi_size = bytes;
bio->bi_io_vec[0].bv_len = bytes;

/* ..and clear the end of the buffer for reads */
if (rw & READ) {
void *kaddr = kmap_atomic(bh->b_page);
memset(kaddr + bh_offset(bh) + bytes, 0, bh->b_size - bytes);
kunmap_atomic(kaddr);
}
}

int submit_bh(int rw, struct buffer_head * bh)
{
struct bio *bio;
Expand Down Expand Up @@ -2929,6 +2978,9 @@ int submit_bh(int rw, struct buffer_head * bh)
bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh;

/* Take care of bh's that straddle the end of the device */
guard_bh_eod(rw, bio, bh);

bio_get(bio);
submit_bio(rw, bio);

Expand Down

0 comments on commit e639278

Please sign in to comment.