In gfs2_alloc_size, compute exactly which effect unstuffing will have on a write: if unstuffing will allocate block 0 and the write starts at block 0, only that block can be written in the first iomap operation; if the write starts above block 0, it won't be affected by the unstuffing.
Signed-off-by: Andreas Gruenbacher <[email protected]> --- fs/gfs2/bmap.c | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index b0cdd606be13..7d5fa46f648b 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -795,45 +795,44 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap, * gfs2_alloc_size - Compute the maximum allocation size * @inode: The inode * @mp: The metapath - * @size: Requested size in blocks + * @iomap: The iomap * * Compute the maximum size of the next allocation at @mp. * * Returns: size in blocks */ -static u64 gfs2_alloc_size(struct inode *inode, struct metapath *mp, u64 size) +static u64 gfs2_alloc_size(struct inode *inode, struct metapath *mp, + struct iomap *iomap) { struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); - const __be64 *first, *ptr, *end; - - /* - * For writes to stuffed files, this function is called twice via - * gfs2_iomap_get, before and after unstuffing. The size we return the - * first time needs to be large enough to get the reservation and - * allocation sizes right. The size we return the second time must - * be exact or else gfs2_iomap_alloc won't do the right thing. - */ + u64 size = iomap->length >> inode->i_blkbits; if (gfs2_is_stuffed(ip) || mp->mp_fheight != mp->mp_aheight) { - unsigned int maxsize = mp->mp_fheight > 1 ? - sdp->sd_inptrs : sdp->sd_diptrs; + unsigned int maxsize; + maxsize = mp->mp_fheight > 1 ? sdp->sd_inptrs : sdp->sd_diptrs; maxsize -= mp->mp_list[mp->mp_fheight - 1]; + if (gfs2_inode_contains_data(inode)) { + if (iomap->offset == 0) + maxsize = 1; + } if (size > maxsize) size = maxsize; - return size; - } - - first = metapointer(ip->i_height - 1, mp); - end = metaend(ip->i_height - 1, mp); - if (end - first > size) - end = first + size; - for (ptr = first; ptr < end; ptr++) { - if (*ptr) - break; + } else { + const __be64 *first, *ptr, *end; + + first = metapointer(ip->i_height - 1, mp); + end = metaend(ip->i_height - 1, mp); + if (end - first > size) + end = first + size; + for (ptr = first; ptr < end; ptr++) { + if (*ptr) + break; + } + size = ptr - first; } - return ptr - first; + return size; } /** @@ -963,7 +962,7 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length, if (flags & IOMAP_DIRECT) goto out; /* (see gfs2_file_direct_write) */ - len = gfs2_alloc_size(inode, mp, len); + len = gfs2_alloc_size(inode, mp, iomap); alloc_size = len << inode->i_blkbits; if (alloc_size < iomap->length) iomap->length = alloc_size; -- 2.17.1
