diff options
-rw-r--r-- | fs/xfs/xfs_aops.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 596ec71da00e..79670869d436 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c | |||
@@ -1516,13 +1516,26 @@ xfs_vm_write_failed( | |||
1516 | loff_t pos, | 1516 | loff_t pos, |
1517 | unsigned len) | 1517 | unsigned len) |
1518 | { | 1518 | { |
1519 | loff_t block_offset = pos & PAGE_MASK; | 1519 | loff_t block_offset; |
1520 | loff_t block_start; | 1520 | loff_t block_start; |
1521 | loff_t block_end; | 1521 | loff_t block_end; |
1522 | loff_t from = pos & (PAGE_CACHE_SIZE - 1); | 1522 | loff_t from = pos & (PAGE_CACHE_SIZE - 1); |
1523 | loff_t to = from + len; | 1523 | loff_t to = from + len; |
1524 | struct buffer_head *bh, *head; | 1524 | struct buffer_head *bh, *head; |
1525 | 1525 | ||
1526 | /* | ||
1527 | * The request pos offset might be 32 or 64 bit, this is all fine | ||
1528 | * on 64-bit platform. However, for 64-bit pos request on 32-bit | ||
1529 | * platform, the high 32-bit will be masked off if we evaluate the | ||
1530 | * block_offset via (pos & PAGE_MASK) because the PAGE_MASK is | ||
1531 | * 0xfffff000 as an unsigned long, hence the result is incorrect | ||
1532 | * which could cause the following ASSERT failed in most cases. | ||
1533 | * In order to avoid this, we can evaluate the block_offset of the | ||
1534 | * start of the page by using shifts rather than masks the mismatch | ||
1535 | * problem. | ||
1536 | */ | ||
1537 | block_offset = (pos >> PAGE_CACHE_SHIFT) << PAGE_CACHE_SHIFT; | ||
1538 | |||
1526 | ASSERT(block_offset + from == pos); | 1539 | ASSERT(block_offset + from == pos); |
1527 | 1540 | ||
1528 | head = page_buffers(page); | 1541 | head = page_buffers(page); |