--- /dev/null
+From e8b43fe0c1e035a135be7ca3791d465fcb1b501e Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruenba@redhat.com>
+Date: Fri, 8 Dec 2017 17:01:57 +0100
+Subject: gfs2: Clean up {lookup,fillup}_metapath
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+commit e8b43fe0c1e035a135be7ca3791d465fcb1b501e upstream.
+
+Split out the entire lookup loop from lookup_metapath and
+fillup_metapath. Make both functions return the actual height in
+mp->mp_aheight, and return 0 on success. Handle lookup errors properly
+in trunc_dealloc.
+
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Bob Peterson <rpeterso@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/gfs2/bmap.c | 74 +++++++++++++++++++++++----------------------------------
+ 1 file changed, 30 insertions(+), 44 deletions(-)
+
+--- a/fs/gfs2/bmap.c
++++ b/fs/gfs2/bmap.c
+@@ -305,21 +305,22 @@ static void gfs2_metapath_ra(struct gfs2
+ }
+ }
+
+-/**
+- * lookup_mp_height - helper function for lookup_metapath
+- * @ip: the inode
+- * @mp: the metapath
+- * @h: the height which needs looking up
+- */
+-static int lookup_mp_height(struct gfs2_inode *ip, struct metapath *mp, int h)
++static int __fillup_metapath(struct gfs2_inode *ip, struct metapath *mp,
++ unsigned int x, unsigned int h)
+ {
+- __be64 *ptr = metapointer(h, mp);
+- u64 dblock = be64_to_cpu(*ptr);
+-
+- if (!dblock)
+- return h + 1;
++ for (; x < h; x++) {
++ __be64 *ptr = metapointer(x, mp);
++ u64 dblock = be64_to_cpu(*ptr);
++ int ret;
+
+- return gfs2_meta_indirect_buffer(ip, h + 1, dblock, &mp->mp_bh[h + 1]);
++ if (!dblock)
++ break;
++ ret = gfs2_meta_indirect_buffer(ip, x + 1, dblock, &mp->mp_bh[x + 1]);
++ if (ret)
++ return ret;
++ }
++ mp->mp_aheight = x + 1;
++ return 0;
+ }
+
+ /**
+@@ -336,25 +337,12 @@ static int lookup_mp_height(struct gfs2_
+ * at which it found the unallocated block. Blocks which are found are
+ * added to the mp->mp_bh[] list.
+ *
+- * Returns: error or height of metadata tree
++ * Returns: error
+ */
+
+ static int lookup_metapath(struct gfs2_inode *ip, struct metapath *mp)
+ {
+- unsigned int end_of_metadata = ip->i_height - 1;
+- unsigned int x;
+- int ret;
+-
+- for (x = 0; x < end_of_metadata; x++) {
+- ret = lookup_mp_height(ip, mp, x);
+- if (ret)
+- goto out;
+- }
+-
+- ret = ip->i_height;
+-out:
+- mp->mp_aheight = ret;
+- return ret;
++ return __fillup_metapath(ip, mp, 0, ip->i_height - 1);
+ }
+
+ /**
+@@ -365,25 +353,21 @@ out:
+ *
+ * Similar to lookup_metapath, but does lookups for a range of heights
+ *
+- * Returns: error or height of metadata tree
++ * Returns: error
+ */
+
+ static int fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, int h)
+ {
+- unsigned int start_h = h - 1;
+- int ret;
++ unsigned int x = 0;
+
+ if (h) {
+ /* find the first buffer we need to look up. */
+- while (start_h > 0 && mp->mp_bh[start_h] == NULL)
+- start_h--;
+- for (; start_h < h; start_h++) {
+- ret = lookup_mp_height(ip, mp, start_h);
+- if (ret)
+- return ret;
++ for (x = h - 1; x > 0; x--) {
++ if (mp->mp_bh[x])
++ break;
+ }
+ }
+- return ip->i_height;
++ return __fillup_metapath(ip, mp, x, h);
+ }
+
+ static inline void release_metapath(struct metapath *mp)
+@@ -790,7 +774,7 @@ int gfs2_iomap_begin(struct inode *inode
+ goto do_alloc;
+
+ ret = lookup_metapath(ip, &mp);
+- if (ret < 0)
++ if (ret)
+ goto out_release;
+
+ if (mp.mp_aheight != ip->i_height)
+@@ -1339,7 +1323,9 @@ static int trunc_dealloc(struct gfs2_ino
+
+ mp.mp_bh[0] = dibh;
+ ret = lookup_metapath(ip, &mp);
+- if (ret == ip->i_height)
++ if (ret)
++ goto out_metapath;
++ if (mp.mp_aheight == ip->i_height)
+ state = DEALLOC_MP_FULL; /* We have a complete metapath */
+ else
+ state = DEALLOC_FILL_MP; /* deal with partial metapath */
+@@ -1435,16 +1421,16 @@ static int trunc_dealloc(struct gfs2_ino
+ case DEALLOC_FILL_MP:
+ /* Fill the buffers out to the current height. */
+ ret = fillup_metapath(ip, &mp, mp_h);
+- if (ret < 0)
++ if (ret)
+ goto out;
+
+ /* If buffers found for the entire strip height */
+- if ((ret == ip->i_height) && (mp_h == strip_h)) {
++ if (mp.mp_aheight - 1 == strip_h) {
+ state = DEALLOC_MP_FULL;
+ break;
+ }
+- if (ret < ip->i_height) /* We have a partial height */
+- mp_h = ret - 1;
++ if (mp.mp_aheight < ip->i_height) /* We have a partial height */
++ mp_h = mp.mp_aheight - 1;
+
+ /* If we find a non-null block pointer, crawl a bit
+ higher up in the metapath and try again, otherwise
--- /dev/null
+From 3b5da96e4585a2788da6a07619bda3518d76eb30 Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruenba@redhat.com>
+Date: Mon, 5 Mar 2018 06:18:25 -0700
+Subject: gfs2: Fixes to "Implement iomap for block_map" (2)
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+commit 3b5da96e4585a2788da6a07619bda3518d76eb30 upstream.
+
+It turns out that commit 3229c18c0d6b2 'Fixes to "Implement iomap for
+block_map"' introduced another bug in gfs2_iomap_begin that can cause
+gfs2_block_map to set bh->b_size of an actual buffer to 0. This can
+lead to arbitrary incorrect behavior including crashes or disk
+corruption. Revert the incorrect part of that commit.
+
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Bob Peterson <rpeterso@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/gfs2/bmap.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/fs/gfs2/bmap.c
++++ b/fs/gfs2/bmap.c
+@@ -811,9 +811,6 @@ do_alloc:
+ iomap->length = hole_size(inode, lblock, &mp);
+ else
+ iomap->length = size - pos;
+- } else {
+- if (height <= ip->i_height)
+- iomap->length = hole_size(inode, lblock, &mp);
+ }
+ goto out_release;
+ }