Merge tag 'gfs2-4.18.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 4 Jun 2018 21:36:38 +0000 (14:36 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 4 Jun 2018 21:36:38 +0000 (14:36 -0700)
Pull gfs2 updates from Bob Peterson:
 "We've got nine more patches for this merge window.

   - remove sd_jheightsize to greatly simplify some code (Andreas
     Gruenbacher)

   - fix some comments (Andreas)

   - fix a glock recursion bug when allocation errors occur (Andreas)

   - improve the hole_size function so it returns the entire hole rather
     than figuring it out piecemeal (Andreas)

   - clean up gfs2_stuffed_write_end to remove a lot of redundancy
     (Andreas)

   - clarify code with regard to the way ordered writes are processed
     (Andreas)

   - a bunch of improvements and cleanups of the iomap code to pave the
     way for iomap writes, which is a future patch set (Andreas)

   - fix a bug where block reservations can run off the end of a bitmap
     (Bob Peterson)

   - add Andreas to the MAINTAINERS file (Bob Peterson)"

* tag 'gfs2-4.18.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  MAINTAINERS: Add Andreas Gruenbacher as a maintainer for gfs2
  gfs2: Iomap cleanups and improvements
  gfs2: Remove ordered write mode handling from gfs2_trans_add_data
  gfs2: gfs2_stuffed_write_end cleanup
  gfs2: hole_size improvement
  GFS2: gfs2_free_extlen can return an extent that is too long
  GFS2: Fix allocation error bug with recursive rgrp glocking
  gfs2: Update find_metapath comment
  gfs2: Remove sdp->sd_jheightsize

12 files changed:
MAINTAINERS
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/bmap.h
fs/gfs2/file.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/log.h
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/rgrp.c
fs/gfs2/trans.c

index 1e22aa66ed9faaefb9e26c157a38ccc936198b4e..fdf15f3de473a223848c483903b1d98dd96b45d4 100644 (file)
@@ -5950,8 +5950,8 @@ S:        Maintained
 F:     scripts/get_maintainer.pl
 
 GFS2 FILE SYSTEM
-M:     Steven Whitehouse <swhiteho@redhat.com>
 M:     Bob Peterson <rpeterso@redhat.com>
+M:     Andreas Gruenbacher <agruenba@redhat.com>
 L:     cluster-devel@redhat.com
 W:     http://sources.redhat.com/cluster/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2.git
index f58716567972ec121762db4ce94a4da4245b6a8d..35f5ee23566d6af25a5c8b3e62508aea2fe7cc69 100644 (file)
@@ -54,8 +54,7 @@ static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
                        continue;
                if (start >= to)
                        break;
-               if (gfs2_is_jdata(ip))
-                       set_buffer_uptodate(bh);
+               set_buffer_uptodate(bh);
                gfs2_trans_add_data(ip->i_gl, bh);
        }
 }
@@ -747,18 +746,21 @@ out:
        put_page(page);
 
        gfs2_trans_end(sdp);
-       if (pos + len > ip->i_inode.i_size)
-               gfs2_trim_blocks(&ip->i_inode);
-       goto out_trans_fail;
+       if (alloc_required) {
+               gfs2_inplace_release(ip);
+               if (pos + len > ip->i_inode.i_size)
+                       gfs2_trim_blocks(&ip->i_inode);
+       }
+       goto out_qunlock;
 
 out_endtrans:
        gfs2_trans_end(sdp);
 out_trans_fail:
-       if (alloc_required) {
+       if (alloc_required)
                gfs2_inplace_release(ip);
 out_qunlock:
+       if (alloc_required)
                gfs2_quota_unlock(ip);
-       }
 out_unlock:
        if (&ip->i_inode == sdp->sd_rindex) {
                gfs2_glock_dq(&m_ip->i_gh);
@@ -814,7 +816,6 @@ out:
  * @inode: The inode
  * @dibh: The buffer_head containing the on-disk inode
  * @pos: The file position
- * @len: The length of the write
  * @copied: How much was actually copied by the VFS
  * @page: The page
  *
@@ -824,17 +825,15 @@ out:
  * Returns: errno
  */
 static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
-                                 loff_t pos, unsigned len, unsigned copied,
+                                 loff_t pos, unsigned copied,
                                  struct page *page)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
-       struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
        u64 to = pos + copied;
        void *kaddr;
        unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode);
 
-       BUG_ON(pos + len > gfs2_max_stuffed_size(ip));
+       BUG_ON(pos + copied > gfs2_max_stuffed_size(ip));
 
        kaddr = kmap_atomic(page);
        memcpy(buf + pos, kaddr + pos, copied);
@@ -850,20 +849,6 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
                        i_size_write(inode, to);
                mark_inode_dirty(inode);
        }
-
-       if (inode == sdp->sd_rindex) {
-               adjust_fs_space(inode);
-               sdp->sd_rindex_uptodate = 0;
-       }
-
-       brelse(dibh);
-       gfs2_trans_end(sdp);
-       if (inode == sdp->sd_rindex) {
-               gfs2_glock_dq(&m_ip->i_gh);
-               gfs2_holder_uninit(&m_ip->i_gh);
-       }
-       gfs2_glock_dq(&ip->i_gh);
-       gfs2_holder_uninit(&ip->i_gh);
        return copied;
 }
 
@@ -877,9 +862,8 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
  * @page: The page that has been written
  * @fsdata: The fsdata (unused in GFS2)
  *
- * The main write_end function for GFS2. We have a separate one for
- * stuffed files as they are slightly different, otherwise we just
- * put our locking around the VFS provided functions.
+ * The main write_end function for GFS2. We just put our locking around the VFS
+ * provided functions.
  *
  * Returns: errno
  */
@@ -900,32 +884,39 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == NULL);
 
        ret = gfs2_meta_inode_buffer(ip, &dibh);
-       if (unlikely(ret)) {
-               unlock_page(page);
-               put_page(page);
-               goto failed;
-       }
+       if (unlikely(ret))
+               goto out;
 
-       if (gfs2_is_stuffed(ip))
-               return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page);
+       if (gfs2_is_stuffed(ip)) {
+               ret = gfs2_stuffed_write_end(inode, dibh, pos, copied, page);
+               page = NULL;
+               goto out2;
+       }
 
-       if (!gfs2_is_writeback(ip))
+       if (gfs2_is_jdata(ip))
                gfs2_page_add_databufs(ip, page, pos & ~PAGE_MASK, len);
+       else
+               gfs2_ordered_add_inode(ip);
 
        ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+       page = NULL;
        if (tr->tr_num_buf_new)
                __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
        else
                gfs2_trans_add_meta(ip->i_gl, dibh);
 
-
+out2:
        if (inode == sdp->sd_rindex) {
                adjust_fs_space(inode);
                sdp->sd_rindex_uptodate = 0;
        }
 
        brelse(dibh);
-failed:
+out:
+       if (page) {
+               unlock_page(page);
+               put_page(page);
+       }
        gfs2_trans_end(sdp);
        gfs2_inplace_release(ip);
        if (ip->i_qadata && ip->i_qadata->qa_qd_num)
index 278ed0869c3c11b9a3a512de9bb043c0b35bfee8..a7b586e02693738144460c105b166bccba4e8628 100644 (file)
@@ -89,10 +89,12 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
                map_bh(bh, inode->i_sb, block);
 
        set_buffer_uptodate(bh);
-       if (!gfs2_is_jdata(ip))
-               mark_buffer_dirty(bh);
-       if (!gfs2_is_writeback(ip))
+       if (gfs2_is_jdata(ip))
                gfs2_trans_add_data(ip->i_gl, bh);
+       else {
+               mark_buffer_dirty(bh);
+               gfs2_ordered_add_inode(ip);
+       }
 
        if (release) {
                unlock_page(page);
@@ -176,8 +178,8 @@ out:
 /**
  * find_metapath - Find path through the metadata tree
  * @sdp: The superblock
- * @mp: The metapath to return the result in
  * @block: The disk block to look up
+ * @mp: The metapath to return the result in
  * @height: The pre-calculated height of the metadata tree
  *
  *   This routine returns a struct metapath structure that defines a path
@@ -188,8 +190,7 @@ out:
  *   filesystem with a blocksize of 4096.
  *
  *   find_metapath() would return a struct metapath structure set to:
- *   mp_offset = 101342453, mp_height = 3, mp_list[0] = 0, mp_list[1] = 48,
- *   and mp_list[2] = 165.
+ *   mp_fheight = 3, mp_list[0] = 0, mp_list[1] = 48, and mp_list[2] = 165.
  *
  *   That means that in order to get to the block containing the byte at
  *   offset 101342453, we would load the indirect block pointed to by pointer
@@ -279,6 +280,21 @@ 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 clone_metapath(struct metapath *clone, struct metapath *mp)
+{
+       unsigned int hgt;
+
+       *clone = *mp;
+       for (hgt = 0; hgt < mp->mp_aheight; hgt++)
+               get_bh(clone->mp_bh[hgt]);
+}
+
 static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
 {
        const __be64 *t;
@@ -420,20 +436,140 @@ static inline unsigned int gfs2_extent_length(void *start, unsigned int len, __b
        return (ptr - first);
 }
 
-static inline void bmap_lock(struct gfs2_inode *ip, int create)
+typedef const __be64 *(*gfs2_metadata_walker)(
+               struct metapath *mp,
+               const __be64 *start, const __be64 *end,
+               u64 factor, void *data);
+
+#define WALK_STOP ((__be64 *)0)
+#define WALK_NEXT ((__be64 *)1)
+
+static int gfs2_walk_metadata(struct inode *inode, sector_t lblock,
+               u64 len, struct metapath *mp, gfs2_metadata_walker walker,
+               void *data)
 {
-       if (create)
-               down_write(&ip->i_rw_mutex);
-       else
-               down_read(&ip->i_rw_mutex);
+       struct metapath clone;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       const __be64 *start, *end, *ptr;
+       u64 factor = 1;
+       unsigned int hgt;
+       int ret = 0;
+
+       for (hgt = ip->i_height - 1; hgt >= mp->mp_aheight; hgt--)
+               factor *= sdp->sd_inptrs;
+
+       for (;;) {
+               u64 step;
+
+               /* Walk indirect block. */
+               start = metapointer(hgt, mp);
+               end = metaend(hgt, mp);
+
+               step = (end - start) * factor;
+               if (step > len)
+                       end = start + DIV_ROUND_UP_ULL(len, factor);
+
+               ptr = walker(mp, start, end, factor, data);
+               if (ptr == WALK_STOP)
+                       break;
+               if (step >= len)
+                       break;
+               len -= step;
+               if (ptr != WALK_NEXT) {
+                       BUG_ON(!*ptr);
+                       mp->mp_list[hgt] += ptr - start;
+                       goto fill_up_metapath;
+               }
+
+lower_metapath:
+               /* Decrease height of metapath. */
+               if (mp != &clone) {
+                       clone_metapath(&clone, mp);
+                       mp = &clone;
+               }
+               brelse(mp->mp_bh[hgt]);
+               mp->mp_bh[hgt] = NULL;
+               if (!hgt)
+                       break;
+               hgt--;
+               factor *= sdp->sd_inptrs;
+
+               /* Advance in metadata tree. */
+               (mp->mp_list[hgt])++;
+               start = metapointer(hgt, mp);
+               end = metaend(hgt, mp);
+               if (start >= end) {
+                       mp->mp_list[hgt] = 0;
+                       if (!hgt)
+                               break;
+                       goto lower_metapath;
+               }
+
+fill_up_metapath:
+               /* Increase height of metapath. */
+               if (mp != &clone) {
+                       clone_metapath(&clone, mp);
+                       mp = &clone;
+               }
+               ret = fillup_metapath(ip, mp, ip->i_height - 1);
+               if (ret < 0)
+                       break;
+               hgt += ret;
+               for (; ret; ret--)
+                       do_div(factor, sdp->sd_inptrs);
+               mp->mp_aheight = hgt + 1;
+       }
+       if (mp == &clone)
+               release_metapath(mp);
+       return ret;
 }
 
-static inline void bmap_unlock(struct gfs2_inode *ip, int create)
+struct gfs2_hole_walker_args {
+       u64 blocks;
+};
+
+static const __be64 *gfs2_hole_walker(struct metapath *mp,
+               const __be64 *start, const __be64 *end,
+               u64 factor, void *data)
 {
-       if (create)
-               up_write(&ip->i_rw_mutex);
-       else
-               up_read(&ip->i_rw_mutex);
+       struct gfs2_hole_walker_args *args = data;
+       const __be64 *ptr;
+
+       for (ptr = start; ptr < end; ptr++) {
+               if (*ptr) {
+                       args->blocks += (ptr - start) * factor;
+                       if (mp->mp_aheight == mp->mp_fheight)
+                               return WALK_STOP;
+                       return ptr;  /* increase height */
+               }
+       }
+       args->blocks += (end - start) * factor;
+       return WALK_NEXT;
+}
+
+/**
+ * gfs2_hole_size - figure out the size of a hole
+ * @inode: The inode
+ * @lblock: The logical starting block number
+ * @len: How far to look (in blocks)
+ * @mp: The metapath at lblock
+ * @iomap: The iomap to store the hole size in
+ *
+ * This function modifies @mp.
+ *
+ * Returns: errno on error
+ */
+static int gfs2_hole_size(struct inode *inode, sector_t lblock, u64 len,
+                         struct metapath *mp, struct iomap *iomap)
+{
+       struct gfs2_hole_walker_args args = { };
+       int ret = 0;
+
+       ret = gfs2_walk_metadata(inode, lblock, len, mp, gfs2_hole_walker, &args);
+       if (!ret)
+               iomap->length = args.blocks << inode->i_blkbits;
+       return ret;
 }
 
 static inline __be64 *gfs2_indirect_init(struct metapath *mp,
@@ -462,15 +598,11 @@ enum alloc_state {
 };
 
 /**
- * gfs2_bmap_alloc - Build a metadata tree of the requested height
+ * gfs2_iomap_alloc - Build a metadata tree of the requested height
  * @inode: The GFS2 inode
- * @lblock: The logical starting block of the extent
- * @bh_map: This is used to return the mapping details
- * @zero_new: True if newly allocated blocks should be zeroed
+ * @iomap: The iomap structure
+ * @flags: iomap flags
  * @mp: The metapath, with proper height information calculated
- * @maxlen: The max number of data blocks to alloc
- * @dblock: Pointer to return the resulting new block
- * @dblks: Pointer to return the number of blocks allocated
  *
  * In this routine we may have to alloc:
  *   i) Indirect blocks to grow the metadata tree height
@@ -483,6 +615,13 @@ enum alloc_state {
  * blocks are available, there will only be one request per bmap call)
  * and uses the state machine to initialise the blocks in order.
  *
+ * Right now, this function will allocate at most one indirect block
+ * worth of data -- with a default block size of 4K, that's slightly
+ * less than 2M.  If this limitation is ever removed to allow huge
+ * allocations, we would probably still want to limit the iomap size we
+ * return to avoid stalling other tasks during huge writes; the next
+ * iomap iteration would then find the blocks already allocated.
+ *
  * Returns: errno on error
  */
 
@@ -497,6 +636,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
        unsigned dblks = 0;
        unsigned ptrs_per_blk;
        const unsigned end_of_metadata = mp->mp_fheight - 1;
+       int ret;
        enum alloc_state state;
        __be64 *ptr;
        __be64 zero_bn = 0;
@@ -507,6 +647,8 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
 
        gfs2_trans_add_meta(ip->i_gl, dibh);
 
+       down_write(&ip->i_rw_mutex);
+
        if (mp->mp_fheight == mp->mp_aheight) {
                struct buffer_head *bh;
                int eob;
@@ -542,11 +684,10 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
        blks = dblks + iblks;
        i = mp->mp_aheight;
        do {
-               int error;
                n = blks - alloced;
-               error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
-               if (error)
-                       return error;
+               ret = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
+               if (ret)
+                       goto out;
                alloced += n;
                if (state != ALLOC_DATA || gfs2_is_jdata(ip))
                        gfs2_trans_add_unrevoke(sdp, bn, n);
@@ -602,7 +743,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
                        dblks = n;
                        ptr = metapointer(end_of_metadata, mp);
                        iomap->addr = bn << inode->i_blkbits;
-                       iomap->flags |= IOMAP_F_NEW;
+                       iomap->flags |= IOMAP_F_MERGED | IOMAP_F_NEW;
                        while (n-- > 0)
                                *ptr++ = cpu_to_be64(bn++);
                        break;
@@ -612,64 +753,10 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
        iomap->length = (u64)dblks << inode->i_blkbits;
        ip->i_height = mp->mp_fheight;
        gfs2_add_inode_blocks(&ip->i_inode, alloced);
-       gfs2_dinode_out(ip, mp->mp_bh[0]->b_data);
-       return 0;
-}
-
-/**
- * hole_size - figure out the size of a hole
- * @inode: The inode
- * @lblock: The logical starting block number
- * @mp: The metapath
- *
- * Returns: The hole size in bytes
- *
- */
-static u64 hole_size(struct inode *inode, sector_t lblock, struct metapath *mp)
-{
-       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++;
-                               }
-                       }
-               } else {
-                       zeroptrs = sdp->sd_inptrs;
-               }
-               if (factor * zeroptrs >= lblock_stop - lblock + 1) {
-                       holesz = lblock_stop - lblock + 1;
-                       break;
-               }
-               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])++;
-       }
-       return holesz << inode->i_blkbits;
+       gfs2_dinode_out(ip, dibh->b_data);
+out:
+       up_write(&ip->i_rw_mutex);
+       return ret;
 }
 
 static void gfs2_stuffed_iomap(struct inode *inode, struct iomap *iomap)
@@ -685,121 +772,130 @@ static void gfs2_stuffed_iomap(struct inode *inode, struct iomap *iomap)
 }
 
 /**
- * gfs2_iomap_begin - Map blocks from an inode to disk blocks
+ * gfs2_iomap_get - Map blocks from an inode to disk blocks
  * @inode: The inode
  * @pos: Starting position in bytes
  * @length: Length to map, in bytes
  * @flags: iomap flags
  * @iomap: The iomap structure
+ * @mp: The metapath
  *
  * Returns: errno
  */
-int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
-                    unsigned flags, struct iomap *iomap)
+static int gfs2_iomap_get(struct inode *inode, loff_t pos, loff_t length,
+                         unsigned flags, struct iomap *iomap,
+                         struct metapath *mp)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
-       struct metapath mp = { .mp_aheight = 1, };
-       unsigned int factor = sdp->sd_sb.sb_bsize;
-       const u64 *arr = sdp->sd_heightsize;
        __be64 *ptr;
        sector_t lblock;
-       sector_t lend;
-       int ret = 0;
+       sector_t lblock_stop;
+       int ret;
        int eob;
-       unsigned int len;
+       u64 len;
        struct buffer_head *bh;
        u8 height;
 
-       trace_gfs2_iomap_start(ip, pos, length, flags);
-       if (!length) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (!length)
+               return -EINVAL;
 
        if (gfs2_is_stuffed(ip)) {
                if (flags & IOMAP_REPORT) {
+                       if (pos >= i_size_read(inode))
+                               return -ENOENT;
                        gfs2_stuffed_iomap(inode, iomap);
-                       if (pos >= iomap->length)
-                               ret = -ENOENT;
-                       goto out;
+                       return 0;
                }
                BUG_ON(!(flags & IOMAP_WRITE));
        }
-
        lblock = pos >> inode->i_blkbits;
-       lend = (pos + length + sdp->sd_sb.sb_bsize - 1) >> inode->i_blkbits;
-
        iomap->offset = lblock << inode->i_blkbits;
-       iomap->addr = IOMAP_NULL_ADDR;
-       iomap->type = IOMAP_HOLE;
-       iomap->length = (u64)(lend - lblock) << inode->i_blkbits;
-       iomap->flags = IOMAP_F_MERGED;
-       bmap_lock(ip, flags & IOMAP_WRITE);
+       lblock_stop = (pos + length - 1) >> inode->i_blkbits;
+       len = lblock_stop - lblock + 1;
 
-       /*
-        * Directory data blocks have a struct gfs2_meta_header header, so the
-        * remaining size is smaller than the filesystem block size.  Logical
-        * block numbers for directories are in units of this remaining size!
-        */
-       if (gfs2_is_dir(ip)) {
-               factor = sdp->sd_jbsize;
-               arr = sdp->sd_jheightsize;
-       }
+       down_read(&ip->i_rw_mutex);
 
-       ret = gfs2_meta_inode_buffer(ip, &mp.mp_bh[0]);
+       ret = gfs2_meta_inode_buffer(ip, &mp->mp_bh[0]);
        if (ret)
-               goto out_release;
+               goto unlock;
 
        height = ip->i_height;
-       while ((lblock + 1) * factor > arr[height])
+       while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height])
                height++;
-       find_metapath(sdp, lblock, &mp, height);
+       find_metapath(sdp, lblock, mp, height);
        if (height > ip->i_height || gfs2_is_stuffed(ip))
                goto do_alloc;
 
-       ret = lookup_metapath(ip, &mp);
+       ret = lookup_metapath(ip, mp);
        if (ret)
-               goto out_release;
+               goto unlock;
 
-       if (mp.mp_aheight != ip->i_height)
+       if (mp->mp_aheight != ip->i_height)
                goto do_alloc;
 
-       ptr = metapointer(ip->i_height - 1, &mp);
+       ptr = metapointer(ip->i_height - 1, mp);
        if (*ptr == 0)
                goto do_alloc;
 
-       iomap->type = IOMAP_MAPPED;
-       iomap->addr = be64_to_cpu(*ptr) << inode->i_blkbits;
+       bh = mp->mp_bh[ip->i_height - 1];
+       len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, len, &eob);
 
-       bh = mp.mp_bh[ip->i_height - 1];
-       len = gfs2_extent_length(bh->b_data, bh->b_size, ptr, lend - lblock, &eob);
+       iomap->addr = be64_to_cpu(*ptr) << inode->i_blkbits;
+       iomap->length = len << inode->i_blkbits;
+       iomap->type = IOMAP_MAPPED;
+       iomap->flags = IOMAP_F_MERGED;
        if (eob)
                iomap->flags |= IOMAP_F_BOUNDARY;
-       iomap->length = (u64)len << inode->i_blkbits;
 
-out_release:
-       release_metapath(&mp);
-       bmap_unlock(ip, flags & IOMAP_WRITE);
 out:
-       trace_gfs2_iomap_end(ip, iomap, ret);
+       iomap->bdev = inode->i_sb->s_bdev;
+unlock:
+       up_read(&ip->i_rw_mutex);
        return ret;
 
 do_alloc:
-       if (flags & IOMAP_WRITE) {
-               ret = gfs2_iomap_alloc(inode, iomap, flags, &mp);
-       } else if (flags & IOMAP_REPORT) {
+       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)
-                       iomap->length = hole_size(inode, lblock, &mp);
+               else if (height == ip->i_height)
+                       ret = gfs2_hole_size(inode, lblock, len, mp, iomap);
                else
                        iomap->length = size - pos;
        }
-       goto out_release;
+       goto out;
+}
+
+static int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
+                           unsigned flags, struct iomap *iomap)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct metapath mp = { .mp_aheight = 1, };
+       int ret;
+
+       trace_gfs2_iomap_start(ip, pos, length, flags);
+       if (flags & IOMAP_WRITE) {
+               ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp);
+               if (!ret && iomap->type == IOMAP_HOLE)
+                       ret = gfs2_iomap_alloc(inode, iomap, flags, &mp);
+               release_metapath(&mp);
+       } else {
+               ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp);
+               release_metapath(&mp);
+       }
+       trace_gfs2_iomap_end(ip, iomap, ret);
+       return ret;
 }
 
+const struct iomap_ops gfs2_iomap_ops = {
+       .iomap_begin = gfs2_iomap_begin,
+};
+
 /**
  * gfs2_block_map - Map one or more blocks of an inode to a disk block
  * @inode: The inode
@@ -825,25 +921,34 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
                   struct buffer_head *bh_map, int create)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
-       struct iomap iomap;
-       int ret, flags = 0;
+       loff_t pos = (loff_t)lblock << inode->i_blkbits;
+       loff_t length = bh_map->b_size;
+       struct metapath mp = { .mp_aheight = 1, };
+       struct iomap iomap = { };
+       int ret;
 
        clear_buffer_mapped(bh_map);
        clear_buffer_new(bh_map);
        clear_buffer_boundary(bh_map);
        trace_gfs2_bmap(ip, bh_map, lblock, create, 1);
 
-       if (create)
-               flags |= IOMAP_WRITE;
-       ret = gfs2_iomap_begin(inode, (loff_t)lblock << inode->i_blkbits,
-                              bh_map->b_size, flags, &iomap);
-       if (ret) {
-               if (!create && ret == -ENOENT) {
-                       /* Return unmapped buffer beyond the end of file.  */
+       if (create) {
+               ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, &iomap, &mp);
+               if (!ret && iomap.type == IOMAP_HOLE)
+                       ret = gfs2_iomap_alloc(inode, &iomap, IOMAP_WRITE, &mp);
+               release_metapath(&mp);
+       } 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;
                }
-               goto out;
        }
+       if (ret)
+               goto out;
 
        if (iomap.length > bh_map->b_size) {
                iomap.length = bh_map->b_size;
@@ -945,8 +1050,10 @@ static int gfs2_block_zero_range(struct inode *inode, loff_t from,
                err = 0;
        }
 
-       if (!gfs2_is_writeback(ip))
+       if (gfs2_is_jdata(ip))
                gfs2_trans_add_data(ip->i_gl, bh);
+       else
+               gfs2_ordered_add_inode(ip);
 
        zero_user(page, offset, length);
        mark_buffer_dirty(bh);
@@ -1056,6 +1163,19 @@ out:
        return error;
 }
 
+int gfs2_iomap_get_alloc(struct inode *inode, loff_t pos, loff_t length,
+                        struct iomap *iomap)
+{
+       struct metapath mp = { .mp_aheight = 1, };
+       int ret;
+
+       ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, iomap, &mp);
+       if (!ret && iomap->type == IOMAP_HOLE)
+               ret = gfs2_iomap_alloc(inode, iomap, IOMAP_WRITE, &mp);
+       release_metapath(&mp);
+       return ret;
+}
+
 /**
  * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein
  * @ip: inode
index c3402fe0065366ba59a4331e73644cbb706b0a72..6b18fb323f0a1a325915a0552df8aa7a1c84a4b7 100644 (file)
@@ -46,11 +46,13 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip,
        }
 }
 
+extern const struct iomap_ops gfs2_iomap_ops;
+
 extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
 extern int gfs2_block_map(struct inode *inode, sector_t lblock,
                          struct buffer_head *bh, int create);
-extern int gfs2_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
-                           unsigned flags, struct iomap *iomap);
+extern int gfs2_iomap_get_alloc(struct inode *inode, loff_t pos, loff_t length,
+                               struct iomap *iomap);
 extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new,
                           u64 *dblock, unsigned *extlen);
 extern int gfs2_setattr_size(struct inode *inode, u64 size);
index 4b71f021a9e29828c472c56ebe59f3562bf956be..7137db7b0119d30530a6fcea9aab05c40fc570a3 100644 (file)
@@ -733,7 +733,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
        struct gfs2_inode *ip = GFS2_I(inode);
        loff_t end = offset + len;
        struct buffer_head *dibh;
-       struct iomap iomap;
+       struct iomap iomap = { };
        int error;
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
@@ -749,8 +749,8 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
        }
 
        while (offset < end) {
-               error = gfs2_iomap_begin(inode, offset, end - offset,
-                                        IOMAP_WRITE, &iomap);
+               error = gfs2_iomap_get_alloc(inode, offset, end - offset,
+                                            &iomap);
                if (error)
                        goto out;
                offset = iomap.offset + iomap.length;
index 1b6b1e3f5cafbd863edc47e3dc61ffe4d6eafad3..d2ad817e089f96d8b7d73cfcb4255682a5798af5 100644 (file)
@@ -116,6 +116,7 @@ static inline struct gfs2_bitmap *rbm_bi(const struct gfs2_rbm *rbm)
 
 static inline u64 gfs2_rbm_to_block(const struct gfs2_rbm *rbm)
 {
+       BUG_ON(rbm->offset >= rbm->rgd->rd_data);
        return rbm->rgd->rd_data0 + (rbm_bi(rbm)->bi_start * GFS2_NBBY) +
                rbm->offset;
 }
@@ -696,8 +697,6 @@ struct gfs2_sbd {
        u32 sd_max_dirres;      /* Max blocks needed to add a directory entry */
        u32 sd_max_height;      /* Max height of a file's metadata tree */
        u64 sd_heightsize[GFS2_MAX_META_HEIGHT + 1];
-       u32 sd_max_jheight; /* Max height of journaled file's meta tree */
-       u64 sd_jheightsize[GFS2_MAX_META_HEIGHT + 1];
        u32 sd_max_dents_per_leaf; /* Max number of dirents in a leaf block */
 
        struct gfs2_args sd_args;       /* Mount arguments */
index 8700eb81563829dd69929d5ad292e9ae1cbc7816..feda55f6705026168cdf7c479d71d527245b44a2 100644 (file)
@@ -2006,10 +2006,6 @@ static int gfs2_getattr(const struct path *path, struct kstat *stat,
        return 0;
 }
 
-const struct iomap_ops gfs2_iomap_ops = {
-       .iomap_begin = gfs2_iomap_begin,
-};
-
 static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                       u64 start, u64 len)
 {
index 1862e310a067c7182b6d1540999ea9f7fb0c1ccc..20241436126da6112925009e2adc9b4158699007 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/writeback.h>
 #include "incore.h"
+#include "inode.h"
 
 /**
  * gfs2_log_lock - acquire the right to mess with the log manager
@@ -50,8 +51,12 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
 
 static inline void gfs2_ordered_add_inode(struct gfs2_inode *ip)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct gfs2_sbd *sdp;
 
+       if (!gfs2_is_ordered(ip))
+               return;
+
+       sdp = GFS2_SB(&ip->i_inode);
        if (!test_bit(GIF_ORDERED, &ip->i_flags)) {
                spin_lock(&sdp->sd_ordered_lock);
                if (!test_and_set_bit(GIF_ORDERED, &ip->i_flags))
index 3ba3f167641ccb9d7935532377abf2565fc2d2ea..c2469833b4fba92d8d1be90b3637379b904920a7 100644 (file)
@@ -335,25 +335,6 @@ static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent)
        sdp->sd_heightsize[x] = ~0;
        gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT);
 
-       sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize -
-                                sizeof(struct gfs2_dinode);
-       sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
-       for (x = 2;; x++) {
-               u64 space, d;
-               u32 m;
-
-               space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs;
-               d = space;
-               m = do_div(d, sdp->sd_inptrs);
-
-               if (d != sdp->sd_jheightsize[x - 1] || m)
-                       break;
-               sdp->sd_jheightsize[x] = space;
-       }
-       sdp->sd_max_jheight = x;
-       sdp->sd_jheightsize[x] = ~0;
-       gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
-
        sdp->sd_max_dents_per_leaf = (sdp->sd_sb.sb_bsize -
                                      sizeof(struct gfs2_leaf)) /
                                     GFS2_MIN_DIRENT_SIZE;
index 7a98abd340ee96bdc4ce1cc7816e9c437700b0cc..e8585dfd209f5b8174b6fb8d892de7b4e28270fe 100644 (file)
@@ -735,7 +735,10 @@ static int gfs2_write_buf_to_page(struct gfs2_inode *ip, unsigned long index,
                        if (!buffer_uptodate(bh))
                                goto unlock_out;
                }
-               gfs2_trans_add_data(ip->i_gl, bh);
+               if (gfs2_is_jdata(ip))
+                       gfs2_trans_add_data(ip->i_gl, bh);
+               else
+                       gfs2_ordered_add_inode(ip);
 
                /* If we need to write to the next block as well */
                if (to_write > (bsize - boff)) {
index 8b683917a27ef87ffb53d8eb3b6a8f0877bbb400..6bc5cfe710d18fc1e7bf6a0550a1a032593e0ccb 100644 (file)
@@ -372,8 +372,8 @@ static u32 gfs2_free_extlen(const struct gfs2_rbm *rrbm, u32 len)
                start = bi->bi_bh->b_data;
                if (bi->bi_clone)
                        start = bi->bi_clone;
-               end = start + bi->bi_bh->b_size;
                start += bi->bi_offset;
+               end = start + bi->bi_len;
                BUG_ON(rbm.offset & 3);
                start += (rbm.offset / GFS2_NBBY);
                bytes = min_t(u32, len / GFS2_NBBY, (end - start));
index c75cacaa349b1d11d5b2b2c92e6cf13af4f896b1..064c9a0ef046068cd2547af5b5578d5bc65a4fe6 100644 (file)
@@ -143,32 +143,21 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
  * @gl: The inode glock associated with the buffer
  * @bh: The buffer to add
  *
- * This is used in two distinct cases:
- * i) In ordered write mode
- *    We put the data buffer on a list so that we can ensure that it's
- *    synced to disk at the right time
- * ii) In journaled data mode
- *    We need to journal the data block in the same way as metadata in
- *    the functions above. The difference is that here we have a tag
- *    which is two __be64's being the block number (as per meta data)
- *    and a flag which says whether the data block needs escaping or
- *    not. This means we need a new log entry for each 251 or so data
- *    blocks, which isn't an enormous overhead but twice as much as
- *    for normal metadata blocks.
+ * This is used in journaled data mode.
+ * We need to journal the data block in the same way as metadata in
+ * the functions above. The difference is that here we have a tag
+ * which is two __be64's being the block number (as per meta data)
+ * and a flag which says whether the data block needs escaping or
+ * not. This means we need a new log entry for each 251 or so data
+ * blocks, which isn't an enormous overhead but twice as much as
+ * for normal metadata blocks.
  */
 void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh)
 {
        struct gfs2_trans *tr = current->journal_info;
        struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
-       struct address_space *mapping = bh->b_page->mapping;
-       struct gfs2_inode *ip = GFS2_I(mapping->host);
        struct gfs2_bufdata *bd;
 
-       if (!gfs2_is_jdata(ip)) {
-               gfs2_ordered_add_inode(ip);
-               return;
-       }
-
        lock_buffer(bh);
        if (buffer_pinned(bh)) {
                set_bit(TR_TOUCHED, &tr->tr_flags);