=========================================================================== Index: linux-2.4/xfs_aops.c =========================================================================== --- /usr/tmp/TmpDir.10141-0/linux-2.4/xfs_aops.c_1.64 2004-01-12 23:44:25.000000000 -0600 +++ linux-2.4/xfs_aops.c 2004-01-12 21:52:57.000000000 -0600 @@ -374,8 +374,9 @@ offset <<= PAGE_CACHE_SHIFT; offset += p_offset; - pb = pagebuf_lookup(iomapp->iomap_target, - iomapp->iomap_offset, iomapp->iomap_bsize, 0); + /* get an "empty" pagebuf to manage IO completion + * Proper values will be set before returning */ + pb = pagebuf_lookup(iomapp->iomap_target, 0, 0, 0); if (!pb) return -EAGAIN; @@ -438,6 +439,13 @@ nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); convert_page(inode, page, iomapp, pb, startio, all_bh); + /* stop if we've found enough blocks that the + * corresponding byte count won't fit in our ulong + * pagebuf length (max 128 blocks could be returned + * from probe_unwritten_page - 64k page / 512b blocks) + */ + if ((nblocks + 128) > (ULONG_MAX >> block_bits)) + goto enough; } if (tindex == tlast && @@ -448,16 +456,20 @@ nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); convert_page(inode, page, iomapp, pb, startio, all_bh); + if ((nblocks + 128) > (ULONG_MAX >> block_bits)) + goto enough; } } } +enough: size = nblocks; /* NB: using 64bit number here */ size <<= block_bits; /* convert fsb's to byte range */ XFS_BUF_DATAIO(pb); XFS_BUF_ASYNC(pb); XFS_BUF_SET_SIZE(pb, size); + XFS_BUF_SET_COUNT(pb, size); XFS_BUF_SET_OFFSET(pb, offset); XFS_BUF_SET_FSPRIVATE(pb, LINVFS_GET_VP(inode)); XFS_BUF_SET_IODONE_FUNC(pb, linvfs_unwritten_convert); @@ -1127,10 +1139,14 @@ int error = 0; int pb_flags, map_flags, pg_index = 0; size_t length, total; - loff_t offset; - size_t map_size, size; + loff_t offset, map_size; + size_t size; vnode_t *vp = LINVFS_GET_VP(inode); + /* Note - although the iomap could have a 64-bit size, + * kiobuf->length is only an int, so the min(map_size, length) + * test will keep us from overflowing the pagebuf size_t size. + */ total = length = iobuf->length; offset = blocknr; offset <<= inode->i_blkbits; @@ -1147,7 +1163,7 @@ BUG_ON(iomap.iomap_flags & IOMAP_DELAY); map_size = iomap.iomap_bsize - iomap.iomap_delta; - size = min(map_size, length); + size = (size_t)min(map_size, (loff_t)length); if ((iomap.iomap_flags & IOMAP_HOLE) || ((iomap.iomap_flags & IOMAP_UNWRITTEN) && rw == READ)) { =========================================================================== Index: linux-2.6/xfs_aops.c =========================================================================== --- /usr/tmp/TmpDir.10141-0/linux-2.6/xfs_aops.c_1.56 2004-01-12 23:44:25.000000000 -0600 +++ linux-2.6/xfs_aops.c 2004-01-12 23:36:05.000000000 -0600 @@ -407,8 +407,10 @@ offset <<= PAGE_CACHE_SHIFT; offset += p_offset; - pb = pagebuf_lookup(iomapp->iomap_target, - iomapp->iomap_offset, iomapp->iomap_bsize, 0); + /* get an "empty" pagebuf to manage IO completion + * Proper values will be set before returning */ + pb = pagebuf_lookup(iomapp->iomap_target, 0, 0, 0); + if (!pb) return -EAGAIN; @@ -471,6 +473,13 @@ nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); convert_page(inode, page, iomapp, pb, startio, all_bh); + /* stop if we've found enough blocks that the + * corresponding byte count won't fit in the + * pagebuf length (max 128 blocks could be returned + * from probe_unwritten_page: 64k page / 512b blocks) + */ + if ((nblocks + 128) > (ULONG_MAX >> block_bits)) + goto enough; } if (tindex == tlast && @@ -481,16 +490,20 @@ nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); convert_page(inode, page, iomapp, pb, startio, all_bh); + if ((nblocks + 128) > (ULONG_MAX >> block_bits)) + goto enough; } } } +enough: size = nblocks; /* NB: using 64bit number here */ size <<= block_bits; /* convert fsb's to byte range */ XFS_BUF_DATAIO(pb); XFS_BUF_ASYNC(pb); XFS_BUF_SET_SIZE(pb, size); + XFS_BUF_SET_COUNT(pb, size); XFS_BUF_SET_OFFSET(pb, offset); XFS_BUF_SET_FSPRIVATE(pb, LINVFS_GET_VP(inode)); XFS_BUF_SET_IODONE_FUNC(pb, linvfs_unwritten_convert); @@ -925,8 +938,10 @@ } if (blocks) { - size = (iomap.iomap_bsize - iomap.iomap_delta); - bh_result->b_size = min_t(ssize_t, size, blocks << inode->i_blkbits); + loff_t iosize; + iosize = (iomap.iomap_bsize - iomap.iomap_delta); + bh_result->b_size = + (ssize_t)min(iosize, (loff_t)(blocks << inode->i_blkbits)); } return 0; =========================================================================== Index: xfs_iomap.h =========================================================================== --- /usr/tmp/TmpDir.10141-0/xfs_iomap.h_1.1 2004-01-12 23:44:25.000000000 -0600 +++ xfs_iomap.h 2004-01-05 23:05:32.000000000 -0600 @@ -66,27 +66,26 @@ /* * xfs_iomap_t: File system I/O map * - * The iomap_bn, iomap_offset and iomap_length fields are expressed in disk blocks. - * The iomap_length field specifies the size of the underlying backing store - * for the particular mapping. + * The iomap_bn field is expressed in 512-byte blocks, and is where the + * mapping starts on disk. * - * The iomap_bsize, iomap_size and iomap_delta fields are in bytes and indicate - * the size of the mapping, the number of bytes that are valid to access - * (read or write), and the offset into the mapping, given the offset - * supplied to the file I/O map routine. iomap_delta is the offset of the - * desired data from the beginning of the mapping. + * The iomap_offset, iomap_bsize and iomap_delta fields are in bytes. + * iomap_offset is the offset of the mapping in the file itself. + * iomap_bsize is the size of the mapping, iomap_delta is the + * desired data's offset into the mapping, given the offset supplied + * to the file I/O map routine. * * When a request is made to read beyond the logical end of the object, - * iomap_size may be set to 0, but iomap_offset and iomap_length should be set to - * the actual amount of underlying storage that has been allocated, if any. + * iomap_size may be set to 0, but iomap_offset and iomap_length should be set + * to the actual amount of underlying storage that has been allocated, if any. */ typedef struct xfs_iomap { - xfs_daddr_t iomap_bn; + xfs_daddr_t iomap_bn; /* first 512b blk of mapping */ xfs_buftarg_t *iomap_target; - loff_t iomap_offset; - size_t iomap_delta; - size_t iomap_bsize; + loff_t iomap_offset; /* offset of mapping, bytes */ + loff_t iomap_bsize; /* size of mapping, bytes */ + size_t iomap_delta; /* offset into mapping, bytes */ iomap_flags_t iomap_flags; } xfs_iomap_t; =========================================================================== Index: xfsidbg.c =========================================================================== --- /usr/tmp/TmpDir.10141-0/xfsidbg.c_1.250 2004-01-12 23:44:25.000000000 -0600 +++ xfsidbg.c 2004-01-05 23:15:44.000000000 -0600 @@ -2610,9 +2610,9 @@ (diag = kdb_getarea(iomap, addr))) kdb_printf("iomap_t at 0x%lx\n", addr); - kdb_printf(" iomap_bn 0x%llx iomap_offset 0x%Lx iomap_delta 0x%lx iomap_bsize 0x%lx\n", + kdb_printf(" iomap_bn 0x%llx iomap_offset 0x%Lx iomap_delta 0x%lx iomap_bsize 0x%llx\n", (long long) iomap.iomap_bn, iomap.iomap_offset, - (unsigned long) iomap.iomap_delta, (unsigned long) iomap.iomap_bsize); + (unsigned long)iomap.iomap_delta, (long long)iomap.iomap_bsize); kdb_printf(" iomap_flags %s\n", map_flags(iomap.iomap_flags, iomap_flag_vals));