gfs2: Further iomap cleanups
authorAndreas Gruenbacher <agruenba@redhat.com>
Sun, 24 Jun 2018 09:43:49 +0000 (10:43 +0100)
committerAndreas Gruenbacher <agruenba@redhat.com>
Mon, 2 Jul 2018 15:26:01 +0000 (16:26 +0100)
In gfs2_iomap_alloc, set the type of newly allocated extents to
IOMAP_MAPPED so that iomap_to_bh will set the bh states correctly:
otherwise, the bhs would not be marked as mapped, confusing
__mpage_writepage.  This means that we need to check for the IOMAP_F_NEW
flag in fallocate_chunk now.

Further clean up gfs2_iomap_get and implement gfs2_stuffed_iomap here
directly.  For reads beyond the end of the file, return holes instead of
failing with -ENOENT so that we can get rid of that special case in
gfs2_block_map.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Bob Peterson <rpeterso@redhat.com>
fs/gfs2/bmap.c
fs/gfs2/file.c

index ed66997..33ee933 100644 (file)
@@ -750,6 +750,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
                }
        } while (iomap->addr == IOMAP_NULL_ADDR);
 
+       iomap->type = IOMAP_MAPPED;
        iomap->length = (u64)dblks << inode->i_blkbits;
        ip->i_height = mp->mp_fheight;
        gfs2_add_inode_blocks(&ip->i_inode, alloced);
@@ -759,17 +760,6 @@ out:
        return ret;
 }
 
-static void gfs2_stuffed_iomap(struct inode *inode, struct iomap *iomap)
-{
-       struct gfs2_inode *ip = GFS2_I(inode);
-
-       iomap->addr = (ip->i_no_addr << inode->i_blkbits) +
-                     sizeof(struct gfs2_dinode);
-       iomap->offset = 0;
-       iomap->length = i_size_read(inode);
-       iomap->type = IOMAP_INLINE;
-}
-
 #define IOMAP_F_GFS2_BOUNDARY IOMAP_F_PRIVATE
 
 /**
@@ -789,37 +779,61 @@ static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length,
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
+       loff_t size = i_size_read(inode);
        __be64 *ptr;
        sector_t lblock;
        sector_t lblock_stop;
        int ret;
        int eob;
        u64 len;
-       struct buffer_head *bh;
+       struct buffer_head *dibh = NULL, *bh;
        u8 height;
 
        if (!length)
                return -EINVAL;
 
+       down_read(&ip->i_rw_mutex);
+
+       ret = gfs2_meta_inode_buffer(ip, &dibh);
+       if (ret)
+               goto unlock;
+
        if (gfs2_is_stuffed(ip)) {
-               if (flags & IOMAP_REPORT) {
-                       if (pos >= i_size_read(inode))
-                               return -ENOENT;
-                       gfs2_stuffed_iomap(inode, iomap);
-                       return 0;
+               if (flags & IOMAP_WRITE) {
+                       loff_t max_size = gfs2_max_stuffed_size(ip);
+
+                       if (pos + length > max_size)
+                               goto unstuff;
+                       iomap->length = max_size;
+               } else {
+                       if (pos >= size) {
+                               if (flags & IOMAP_REPORT) {
+                                       ret = -ENOENT;
+                                       goto unlock;
+                               } else {
+                                       /* report a hole */
+                                       iomap->offset = pos;
+                                       iomap->length = length;
+                                       goto do_alloc;
+                               }
+                       }
+                       iomap->length = size;
                }
-               BUG_ON(!(flags & IOMAP_WRITE));
+               iomap->addr = (ip->i_no_addr << inode->i_blkbits) +
+                             sizeof(struct gfs2_dinode);
+               iomap->type = IOMAP_INLINE;
+               goto out;
        }
+
+unstuff:
        lblock = pos >> inode->i_blkbits;
        iomap->offset = lblock << inode->i_blkbits;
        lblock_stop = (pos + length - 1) >> inode->i_blkbits;
        len = lblock_stop - lblock + 1;
+       iomap->length = len << inode->i_blkbits;
 
-       down_read(&ip->i_rw_mutex);
-
-       ret = gfs2_meta_inode_buffer(ip, &mp->mp_bh[0]);
-       if (ret)
-               goto unlock;
+       get_bh(dibh);
+       mp->mp_bh[0] = dibh;
 
        height = ip->i_height;
        while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height])
@@ -853,21 +867,23 @@ out:
        iomap->bdev = inode->i_sb->s_bdev;
 unlock:
        up_read(&ip->i_rw_mutex);
+       if (dibh)
+               brelse(dibh);
        return ret;
 
 do_alloc:
        iomap->addr = IOMAP_NULL_ADDR;
-       iomap->length = len << inode->i_blkbits;
        iomap->type = IOMAP_HOLE;
-       iomap->flags = 0;
        if (flags & IOMAP_REPORT) {
-               loff_t size = i_size_read(inode);
                if (pos >= size)
                        ret = -ENOENT;
                else if (height == ip->i_height)
                        ret = gfs2_hole_size(inode, lblock, len, mp, iomap);
                else
                        iomap->length = size - pos;
+       } else if (!(flags & IOMAP_WRITE)) {
+               if (pos < size && height == ip->i_height)
+                       ret = gfs2_hole_size(inode, lblock, len, mp, iomap);
        }
        goto out;
 }
@@ -941,12 +957,6 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
        } else {
                ret = gfs2_iomap_get(inode, pos, length, 0, &iomap, &mp);
                release_metapath(&mp);
-
-               /* Return unmapped buffer beyond the end of file. */
-               if (ret == -ENOENT) {
-                       ret = 0;
-                       goto out;
-               }
        }
        if (ret)
                goto out;
index 7137db7..6f6bbfb 100644 (file)
@@ -754,7 +754,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
                if (error)
                        goto out;
                offset = iomap.offset + iomap.length;
-               if (iomap.type != IOMAP_HOLE)
+               if (!(iomap.flags & IOMAP_F_NEW))
                        continue;
                error = sb_issue_zeroout(sb, iomap.addr >> inode->i_blkbits,
                                         iomap.length >> inode->i_blkbits,