Unsuccessful access to the last blocks of a device [2.4/2.6 PATCH] (repost)
From: Mathieu Lafon
Date: Mon Apr 28 2008 - 07:57:38 EST
[Reposted with the patch...]
I have encountered a problem where I wasn't able to access to the last
blocks
of a partition.
By example, using dd:
# dd if=/dev/hda1 of=/dev/null
dd: /dev/hda1: Input/output error
In the kernel logs:
03:01: rw=0, want=28864, limit=28863
attempt to access beyond end of device
After having investigated this issue, I have found the following
explanation:
- A getblk() call is done to read one of the last block of my partition.
The block is located in the last PAGE_SIZE (4kB) of the partition.
In my case, the getblk() call is done by the e2compr patch
(e2compr.sourceforge.net) but I don't think it is the problem (correct
me if I'm wrong).
- The block is not in the page cache so a new page is created by
grow_buffers()
with 4 buffers of 1kB.
- When the page is created, hash_page_buffers() is called to initialize
the
buffers. The buffers are initialized by simply incrementing the block
number without any check.
In my case, the last buffer is initialized with a block number outside
of
the partition.
- When dd try to access to one of the last block, the (invalid) cached
page
is found and trigger the previous error (attempt to access beyond end of
device) because one buffer of the page is really beyond end of device.
- If I manage to get the cache flushed, I can read the whole partition
because the (invalid) cached page is not found and
block_read_full_page()
correctly initialize the new page by checking the last block.
I have made a patch for 2.4.32 to test for the last block in
grow_buffers()
and hash_page_buffers() in the same way it is done in
block_read_full_page().
Regarding the 2.6 branch, I have looked at the source code and the problem
seems to be the same in init_page_buffers() which is called by __getblk().
--
Mathieu Lafon - Arkoon Network Security
Attachment:
linux-2.4.32-getblk-fix.diff
Description: Binary data