]> git.hungrycats.org Git - linux/commitdiff
[XFS] Fix for large allocation groups, so that extent
authorEric Sandeen <sandeen@sgi.com>
Sat, 24 Jan 2004 03:41:38 +0000 (14:41 +1100)
committerNathan Scott <nathans@sgi.com>
Sat, 24 Jan 2004 03:41:38 +0000 (14:41 +1100)
sizes will not overflow pagebuf lengths.

SGI Modid: xfs-linux:xfs-kern:164827a

fs/xfs/linux/xfs_aops.c
fs/xfs/xfs_iomap.h

index 038cb9300c06869c14b45c35beeea2a125618749..112e297e4b678a197ddad23e41e34f47bc9306de 100644 (file)
@@ -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;
index fa82aa404ea92a56865ad36265f551a5dc4fd232..673410c564b891759c6f310b31cf0e6e0594bdd6 100644 (file)
@@ -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;