From 5b3597e4f5934369aa113c1de5c01f17a07ad6bb Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Sat, 24 Jan 2004 14:41:38 +1100 Subject: [PATCH] [XFS] Fix for large allocation groups, so that extent sizes will not overflow pagebuf lengths. SGI Modid: xfs-linux:xfs-kern:164827a --- fs/xfs/linux/xfs_aops.c | 21 +++++++++++++++++---- fs/xfs/xfs_iomap.h | 27 +++++++++++++-------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c index 038cb9300c068..112e297e4b678 100644 --- a/fs/xfs/linux/xfs_aops.c +++ b/fs/xfs/linux/xfs_aops.c @@ -407,8 +407,10 @@ map_unwritten( 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,11 @@ map_unwritten( nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); convert_page(inode, page, iomapp, pb, startio, all_bh); + /* stop if converting the next page might add + * enough blocks that the corresponding byte + * count won't fit in our ulong page buf length */ + if (nblocks >= ((ULONG_MAX - PAGE_SIZE) >> block_bits)) + goto enough; } if (tindex == tlast && @@ -481,16 +488,20 @@ map_unwritten( nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); convert_page(inode, page, iomapp, pb, startio, all_bh); + if (nblocks >= ((ULONG_MAX - PAGE_SIZE) >> 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 +936,10 @@ linvfs_get_block_core( } 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; diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index fa82aa404ea92..673410c564b89 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -66,27 +66,26 @@ typedef enum { /* * 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; -- 2.53.0