Messages in this thread | | | Subject | Unsuccessful access to the last blocks of a device [2.4/2.6 PATCH] | Date | Mon, 28 Apr 2008 11:39:59 +0200 | From | "Mathieu Lafon" <> |
| |
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
| |