On 10 April 2018 at 20:22, Andreas Gruenbacher <[email protected]> wrote: > On 10 April 2018 at 19:39, Andreas Gruenbacher <[email protected]> wrote: >> Rewrite function hole_size so that it computes the entire size of a >> hole. Previously, the hole size returned wasn't guaranteed to span the >> entire hole and multiple invocations of hole_size could be needed to >> reach the next bit of data. >> >> Signed-off-by: Andreas Gruenbacher <[email protected]> >> --- >> fs/gfs2/bmap.c | 106 >> ++++++++++++++++++++++++++++++++++++--------------------- >> 1 file changed, 67 insertions(+), 39 deletions(-) >> >> diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c >> index 8c25a64d8ae0..14c21825b890 100644 >> --- a/fs/gfs2/bmap.c >> +++ b/fs/gfs2/bmap.c >> @@ -279,6 +279,12 @@ static inline __be64 *metapointer(unsigned int height, >> const struct metapath *mp >> return p + mp->mp_list[height]; >> } >> >> +static inline const __be64 *metaend(unsigned int height, const struct >> metapath *mp) >> +{ >> + const struct buffer_head *bh = mp->mp_bh[height]; >> + return (const __be64 *)(bh->b_data + bh->b_size); >> +} >> + >> static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 >> *end) >> { >> const __be64 *t; >> @@ -631,56 +637,78 @@ static int gfs2_iomap_alloc(struct inode *inode, >> struct iomap *iomap, >> * hole_size - figure out the size of a hole >> * @inode: The inode >> * @lblock: The logical starting block number >> - * @mp: The metapath >> + * @mp: The metapath at lblock >> + * @pholesz: The hole size in bytes (output) >> + * >> + * This function modifies @mp. >> * >> - * Returns: The hole size in bytes >> + * Returns: errno on error >> * >> */ >> -static u64 hole_size(struct inode *inode, sector_t lblock, struct metapath >> *mp) >> +static int hole_size(struct inode *inode, sector_t lblock, struct metapath >> *mp, >> + u64 *pholesz) >> { >> + sector_t lblock_end = (i_size_read(inode) + i_blocksize(inode) - 1) >> >> >> + inode->i_blkbits; >> struct gfs2_inode *ip = GFS2_I(inode); >> struct gfs2_sbd *sdp = GFS2_SB(inode); >> - struct metapath mp_eof; >> - u64 factor = 1; >> - int hgt; >> - u64 holesz = 0; >> const __be64 *first, *end, *ptr; >> - const struct buffer_head *bh; >> - u64 lblock_stop = (i_size_read(inode) - 1) >> inode->i_blkbits; >> - int zeroptrs; >> - bool done = false; >> - >> - /* Get another metapath, to the very last byte */ >> - find_metapath(sdp, lblock_stop, &mp_eof, ip->i_height); >> - for (hgt = ip->i_height - 1; hgt >= 0 && !done; hgt--) { >> - bh = mp->mp_bh[hgt]; >> - if (bh) { >> - zeroptrs = 0; >> - first = metapointer(hgt, mp); >> - end = (const __be64 *)(bh->b_data + bh->b_size); >> - >> - for (ptr = first; ptr < end; ptr++) { >> - if (*ptr) { >> - done = true; >> - break; >> - } else { >> - zeroptrs++; >> - } >> + u64 holesz = 0, factor = 1; >> + int hgt, ret; >> + >> + for (hgt = ip->i_height - 1; hgt >= mp->mp_aheight; hgt--) >> + factor *= sdp->sd_inptrs; >> + >> + for (;;) { >> + /* Count the number of zero pointers. */ >> + first = metapointer(hgt, mp); >> + end = metaend(hgt, mp); >> + if (end - first > lblock_end - lblock - holesz) >> + end = first + lblock_end - lblock - holesz; >> + for (ptr = first; ptr < end; ptr++) { >> + if (*ptr) { >> + holesz += (ptr - first) * factor; >> + if (hgt == ip->i_height - 1) >> + goto out; >> + mp->mp_list[hgt] += (ptr - first); >> + goto fill_up_metapath; >> } >> - } else { >> - zeroptrs = sdp->sd_inptrs; >> } >> - if (factor * zeroptrs >= lblock_stop - lblock + 1) { >> - holesz = lblock_stop - lblock + 1; >> - break; >> + holesz += (ptr - first) * factor; > > We probably want to check for EOF here as well to stop immediately > when we've had enough: > > if (lblock + holesz >= lblock_end) > goto out; > >> + >> +lower_metapath: >> + /* Decrease height of metapath. */ >> + brelse(mp->mp_bh[hgt]); >> + mp->mp_bh[hgt] = NULL; >> + mp->mp_list[hgt] = 0; >> + if (!hgt) >> + goto out; >> + hgt--; >> + factor *= sdp->sd_inptrs; >> + >> + /* Advance in metadata tree. */ >> + (mp->mp_list[hgt])++; >> + first = metapointer(hgt, mp); >> + end = metaend(hgt, mp); >> + if (first >= end) { >> + if (!hgt) >> + goto out; >> + goto lower_metapath; >> } >> - holesz += factor * zeroptrs; >> >> - factor *= sdp->sd_inptrs; >> - if (hgt && (mp->mp_list[hgt - 1] < mp_eof.mp_list[hgt - 1])) >> - (mp->mp_list[hgt - 1])++; >> +fill_up_metapath: >> + /* Fill up metapath. */ >> + ret = fillup_metapath(ip, mp, ip->i_height - 1); >> + if (ret < 0) >> + return ret; >> + while (ret--) { >> + hgt++; >> + factor /= sdp->sd_inptrs;
This should have been do_div(factor, sdp->sd_inptrs). >> + } >> } >> - return holesz << inode->i_blkbits; >> +out: >> + *pholesz = holesz << inode->i_blkbits; >> + return 0; >> } >> >> static void gfs2_stuffed_iomap(struct inode *inode, struct iomap *iomap) >> @@ -804,7 +832,7 @@ int gfs2_iomap_begin(struct inode *inode, loff_t pos, >> loff_t length, >> if (pos >= size) >> ret = -ENOENT; >> else if (height <= ip->i_height) >> - iomap->length = hole_size(inode, lblock, &mp); >> + ret = hole_size(inode, lblock, &mp, &iomap->length); >> else >> iomap->length = size - pos; >> } >> -- >> 2.14.3 >>
