Commit c582fee9 authored by Nathan Scott's avatar Nathan Scott Committed by Christoph Hellwig

[XFS] Fix a very hard-to-hit, small-block-size only corruption.

SGI Modid: xfs-linux:xfs-kern:168987a
parent eef2c071
...@@ -364,16 +364,16 @@ _pagebuf_lookup_pages( ...@@ -364,16 +364,16 @@ _pagebuf_lookup_pages(
uint flags) uint flags)
{ {
struct address_space *mapping = bp->pb_target->pbr_mapping; struct address_space *mapping = bp->pb_target->pbr_mapping;
unsigned int sectorshift = bp->pb_target->pbr_sshift;
size_t blocksize = bp->pb_target->pbr_bsize; size_t blocksize = bp->pb_target->pbr_bsize;
size_t size = bp->pb_count_desired, nbytes; size_t size = bp->pb_count_desired;
size_t offset = bp->pb_offset; size_t nbytes, offset;
int gfp_mask = pb_to_gfp(flags); int gfp_mask = pb_to_gfp(flags);
unsigned short page_count, i; unsigned short page_count, i;
pgoff_t first; pgoff_t first;
loff_t end; loff_t end;
int error; int error;
first = (bp->pb_file_offset - bp->pb_offset) >> PAGE_CACHE_SHIFT;
end = bp->pb_file_offset + bp->pb_buffer_length; end = bp->pb_file_offset + bp->pb_buffer_length;
page_count = page_buf_btoc(end) - page_buf_btoct(bp->pb_file_offset); page_count = page_buf_btoc(end) - page_buf_btoct(bp->pb_file_offset);
...@@ -381,6 +381,9 @@ _pagebuf_lookup_pages( ...@@ -381,6 +381,9 @@ _pagebuf_lookup_pages(
if (unlikely(error)) if (unlikely(error))
return error; return error;
offset = bp->pb_offset;
first = bp->pb_file_offset >> PAGE_CACHE_SHIFT;
for (i = 0; i < bp->pb_page_count; i++) { for (i = 0; i < bp->pb_page_count; i++) {
struct page *page; struct page *page;
uint retries = 0; uint retries = 0;
...@@ -421,18 +424,17 @@ _pagebuf_lookup_pages( ...@@ -421,18 +424,17 @@ _pagebuf_lookup_pages(
if (flags & PBF_READ) if (flags & PBF_READ)
bp->pb_locked = 1; bp->pb_locked = 1;
} else if (!PagePrivate(page)) { } else if (!PagePrivate(page)) {
uint sectorshift = bp->pb_target->pbr_sshift; unsigned long j, range;
ulong range, i;
/* /*
* In this case page->private holds a bitmap * In this case page->private holds a bitmap
* of uptodate sectors within the page * of uptodate sectors within the page
*/ */
range = (offset + nbytes) >> sectorshift; range = (offset + nbytes) >> sectorshift;
for (i = offset >> sectorshift; i < range; i++) for (j = offset >> sectorshift; j < range; j++)
if (!test_bit(i, &page->private)) if (!test_bit(j, &page->private))
break; break;
if (i == range) if (j == range)
page_count++; page_count++;
} }
} }
...@@ -445,12 +447,16 @@ _pagebuf_lookup_pages( ...@@ -445,12 +447,16 @@ _pagebuf_lookup_pages(
unlock_page(bp->pb_pages[i]); unlock_page(bp->pb_pages[i]);
} }
bp->pb_flags &= ~PBF_NONE;
bp->pb_flags |= (_PBF_PAGECACHE|_PBF_MEM_ALLOCATED); bp->pb_flags |= (_PBF_PAGECACHE|_PBF_MEM_ALLOCATED);
/* if some pages aren't uptodate mark that in the buffer */ if (page_count) {
/* if we have any uptodate pages, mark that in the buffer */
bp->pb_flags &= ~PBF_NONE;
/* if some pages aren't uptodate, mark that in the buffer */
if (page_count != bp->pb_page_count) if (page_count != bp->pb_page_count)
bp->pb_flags |= PBF_PARTIAL; bp->pb_flags |= PBF_PARTIAL;
}
PB_TRACE(bp, "lookup_pages", (long)page_count); PB_TRACE(bp, "lookup_pages", (long)page_count);
return error; return error;
...@@ -1269,7 +1275,7 @@ bio_end_io_pagebuf( ...@@ -1269,7 +1275,7 @@ bio_end_io_pagebuf(
} else if (blocksize == PAGE_CACHE_SIZE) { } else if (blocksize == PAGE_CACHE_SIZE) {
SetPageUptodate(page); SetPageUptodate(page);
} else if (!PagePrivate(page)) { } else if (!PagePrivate(page)) {
unsigned int j, range; unsigned long j, range;
ASSERT(blocksize < PAGE_CACHE_SIZE); ASSERT(blocksize < PAGE_CACHE_SIZE);
range = (bvec->bv_offset + bvec->bv_len) >> sectorshift; range = (bvec->bv_offset + bvec->bv_len) >> sectorshift;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment