Home Home > GIT Browse > SLE15
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-05-17 17:33:32 +0200
committerTakashi Iwai <tiwai@suse.de>2019-05-17 17:33:32 +0200
commit558f3864413e823b3ca07accd27a35242e927115 (patch)
tree6de4fc16729e1e8e7ca51b5e294959215815b409
parent960072f1990f00ca42e8c1347ab0a1e75b944a5f (diff)
parentd9d191e60bf17aff81948efcd17321c5e27b654a (diff)
Merge branch 'users/ailiopoulos/SLE15/for-next' into SLE15
Pull xfs fixes from Anthony Iliopoulos
-rw-r--r--patches.fixes/0038-xfs-split-xfs_bmap_shift_extents.patch32
-rw-r--r--patches.fixes/xfs-check-_btree_check_block-value.patch49
-rw-r--r--patches.fixes/xfs-create-block-pointer-check-functions.patch137
-rw-r--r--patches.fixes/xfs-export-various-function-for-the-online-scrubber.patch277
-rw-r--r--patches.fixes/xfs-make-errortag-a-per-mountpoint-structure.patch336
-rw-r--r--patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch279
-rw-r--r--patches.fixes/xfs-refactor-btree-pointer-checks.patch162
-rw-r--r--patches.fixes/xfs-remove-unneeded-parameter-from-XFS_TEST_ERROR.patch306
-rw-r--r--patches.fixes/xfs-rename-MAXPATHLEN-to-XFS_SYMLINK_MAXLEN.patch138
-rw-r--r--patches.fixes/xfs-sanity-check-the-unused-space-before-trying-to-u.patch321
-rw-r--r--series.conf9
11 files changed, 2030 insertions, 16 deletions
diff --git a/patches.fixes/0038-xfs-split-xfs_bmap_shift_extents.patch b/patches.fixes/0038-xfs-split-xfs_bmap_shift_extents.patch
index 38b5598818..960381715b 100644
--- a/patches.fixes/0038-xfs-split-xfs_bmap_shift_extents.patch
+++ b/patches.fixes/0038-xfs-split-xfs_bmap_shift_extents.patch
@@ -23,10 +23,10 @@ Acked-by: Nikolay Borisov <nborisov@suse.com>
3 files changed, 148 insertions(+), 73 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
-index 4062ec298497..186f4719a582 100644
+index d0118a2e51d3..47fb51774fcc 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
-@@ -5687,57 +5687,151 @@ xfs_bmse_shift_one(
+@@ -5700,57 +5700,151 @@ xfs_bmse_shift_one(
return xfs_rmap_map_extent(mp, dfops, ip, whichfork, &new);
}
@@ -78,10 +78,10 @@ index 4062ec298497..186f4719a582 100644
if (unlikely(XFS_TEST_ERROR(
(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
- mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
+ mp, XFS_ERRTAG_BMAPIFORMAT))) {
- XFS_ERROR_REPORT("xfs_bmap_shift_extents",
- XFS_ERRLEVEL_LOW, mp);
-+ XFS_ERROR_REPORT("__func__", XFS_ERRLEVEL_LOW, mp);
++ XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
return -EFSCORRUPTED;
}
@@ -192,7 +192,7 @@ index 4062ec298497..186f4719a582 100644
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
-+ mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
++ mp, XFS_ERRTAG_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+ return -EFSCORRUPTED;
+ }
@@ -208,7 +208,7 @@ index 4062ec298497..186f4719a582 100644
error = xfs_iread_extents(tp, ip, whichfork);
if (error)
return error;
-@@ -5757,7 +5851,7 @@ xfs_bmap_shift_extents(
+@@ -5770,7 +5864,7 @@ xfs_bmap_shift_extents(
*/
total_extents = xfs_iext_count(ifp);
if (total_extents == 0) {
@@ -217,7 +217,7 @@ index 4062ec298497..186f4719a582 100644
goto del_cursor;
}
-@@ -5765,12 +5859,10 @@ xfs_bmap_shift_extents(
+@@ -5778,12 +5872,10 @@ xfs_bmap_shift_extents(
* In case of first right shift, we need to initialize next_fsb
*/
if (*next_fsb == NULLFSBLOCK) {
@@ -231,7 +231,7 @@ index 4062ec298497..186f4719a582 100644
goto del_cursor;
}
*next_fsb = got.br_startoff;
-@@ -5785,46 +5877,27 @@ xfs_bmap_shift_extents(
+@@ -5798,46 +5890,27 @@ xfs_bmap_shift_extents(
*/
if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &current_ext,
&got)) {
@@ -288,7 +288,7 @@ index 4062ec298497..186f4719a582 100644
}
xfs_iext_get_extent(ifp, current_ext, &got);
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
-index 7eb1cf199138..cee680f01d87 100644
+index ba5a4835bb13..ca37030f4cfb 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -228,10 +228,14 @@ int xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork,
@@ -310,10 +310,10 @@ index 7eb1cf199138..cee680f01d87 100644
int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc,
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
-index 29b999e86571..09e21f704444 100644
+index 3273f083c496..034f3429ca8c 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
-@@ -1303,7 +1303,6 @@ xfs_collapse_file_space(
+@@ -1322,7 +1322,6 @@ xfs_collapse_file_space(
xfs_off_t offset,
xfs_off_t len)
{
@@ -321,7 +321,7 @@ index 29b999e86571..09e21f704444 100644
struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp;
int error;
-@@ -1313,6 +1312,7 @@ xfs_collapse_file_space(
+@@ -1332,6 +1331,7 @@ xfs_collapse_file_space(
xfs_fileoff_t next_fsb = XFS_B_TO_FSB(mp, offset + len);
xfs_fileoff_t shift_fsb = XFS_B_TO_FSB(mp, len);
uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
@@ -329,7 +329,7 @@ index 29b999e86571..09e21f704444 100644
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
trace_xfs_collapse_file_space(ip);
-@@ -1340,9 +1340,8 @@ xfs_collapse_file_space(
+@@ -1359,9 +1359,8 @@ xfs_collapse_file_space(
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_defer_init(&dfops, &first_block);
@@ -341,7 +341,7 @@ index 29b999e86571..09e21f704444 100644
if (error)
goto out_bmap_cancel;
-@@ -1387,7 +1386,7 @@ xfs_insert_file_space(
+@@ -1406,7 +1405,7 @@ xfs_insert_file_space(
xfs_fileoff_t stop_fsb = XFS_B_TO_FSB(mp, offset);
xfs_fileoff_t next_fsb = NULLFSBLOCK;
xfs_fileoff_t shift_fsb = XFS_B_TO_FSB(mp, len);
@@ -350,7 +350,7 @@ index 29b999e86571..09e21f704444 100644
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
trace_xfs_insert_file_space(ip);
-@@ -1414,9 +1413,8 @@ xfs_insert_file_space(
+@@ -1433,9 +1432,8 @@ xfs_insert_file_space(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_defer_init(&dfops, &first_block);
@@ -363,5 +363,5 @@ index 29b999e86571..09e21f704444 100644
goto out_bmap_cancel;
--
-2.7.4
+2.16.4
diff --git a/patches.fixes/xfs-check-_btree_check_block-value.patch b/patches.fixes/xfs-check-_btree_check_block-value.patch
new file mode 100644
index 0000000000..a5d0edf4c8
--- /dev/null
+++ b/patches.fixes/xfs-check-_btree_check_block-value.patch
@@ -0,0 +1,49 @@
+From 1e86eabe73b73c82e1110c746ed3ec6d5e1c0a0d Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Mon, 17 Jul 2017 14:30:45 -0700
+Subject: [PATCH] xfs: check _btree_check_block value
+Git-commit: 1e86eabe73b73c82e1110c746ed3ec6d5e1c0a0d
+Patch-mainline: v4.13-rc3
+References: bsc#1123663
+
+Check the _btree_check_block return value for the firstrec and lastrec
+functions, since we have the ability to signal that the repositioning
+did not succeed.
+
+Fixes-coverity-id: 114067
+Fixes-coverity-id: 114068
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_btree.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
+index 4da85fff69ad..e0bcc4a59efd 100644
+--- a/fs/xfs/libxfs/xfs_btree.c
++++ b/fs/xfs/libxfs/xfs_btree.c
+@@ -728,7 +728,8 @@ xfs_btree_firstrec(
+ * Get the block pointer for this level.
+ */
+ block = xfs_btree_get_block(cur, level, &bp);
+- xfs_btree_check_block(cur, block, level, bp);
++ if (xfs_btree_check_block(cur, block, level, bp))
++ return 0;
+ /*
+ * It's empty, there is no such record.
+ */
+@@ -757,7 +758,8 @@ xfs_btree_lastrec(
+ * Get the block pointer for this level.
+ */
+ block = xfs_btree_get_block(cur, level, &bp);
+- xfs_btree_check_block(cur, block, level, bp);
++ if (xfs_btree_check_block(cur, block, level, bp))
++ return 0;
+ /*
+ * It's empty, there is no such record.
+ */
+--
+2.16.4
+
diff --git a/patches.fixes/xfs-create-block-pointer-check-functions.patch b/patches.fixes/xfs-create-block-pointer-check-functions.patch
new file mode 100644
index 0000000000..c4c84d8308
--- /dev/null
+++ b/patches.fixes/xfs-create-block-pointer-check-functions.patch
@@ -0,0 +1,137 @@
+From 21ec54168b368f1a98097dee00625ec8ec2d47f3 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Tue, 17 Oct 2017 21:37:32 -0700
+Subject: [PATCH] xfs: create block pointer check functions
+Git-commit: 21ec54168b368f1a98097dee00625ec8ec2d47f3
+Patch-mainline: v4.15-rc1
+References: bsc#1123663
+
+Create some helper functions to check that a block pointer points
+within the filesystem (or AG) and doesn't point at static metadata.
+We will use this for scrub.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_alloc.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
+ fs/xfs/libxfs/xfs_alloc.h | 4 ++++
+ fs/xfs/libxfs/xfs_rtbitmap.c | 12 +++++++++++
+ fs/xfs/xfs_rtalloc.h | 2 ++
+ 4 files changed, 67 insertions(+)
+
+diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
+index f965ce832bc0..11c01e2668bf 100644
+--- a/fs/xfs/libxfs/xfs_alloc.c
++++ b/fs/xfs/libxfs/xfs_alloc.c
+@@ -2931,3 +2931,52 @@ xfs_alloc_query_all(
+ query.fn = fn;
+ return xfs_btree_query_all(cur, xfs_alloc_query_range_helper, &query);
+ }
++
++/* Find the size of the AG, in blocks. */
++xfs_agblock_t
++xfs_ag_block_count(
++ struct xfs_mount *mp,
++ xfs_agnumber_t agno)
++{
++ ASSERT(agno < mp->m_sb.sb_agcount);
++
++ if (agno < mp->m_sb.sb_agcount - 1)
++ return mp->m_sb.sb_agblocks;
++ return mp->m_sb.sb_dblocks - (agno * mp->m_sb.sb_agblocks);
++}
++
++/*
++ * Verify that an AG block number pointer neither points outside the AG
++ * nor points at static metadata.
++ */
++bool
++xfs_verify_agbno(
++ struct xfs_mount *mp,
++ xfs_agnumber_t agno,
++ xfs_agblock_t agbno)
++{
++ xfs_agblock_t eoag;
++
++ eoag = xfs_ag_block_count(mp, agno);
++ if (agbno >= eoag)
++ return false;
++ if (agbno <= XFS_AGFL_BLOCK(mp))
++ return false;
++ return true;
++}
++
++/*
++ * Verify that an FS block number pointer neither points outside the
++ * filesystem nor points at static AG metadata.
++ */
++bool
++xfs_verify_fsbno(
++ struct xfs_mount *mp,
++ xfs_fsblock_t fsbno)
++{
++ xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno);
++
++ if (agno >= mp->m_sb.sb_agcount)
++ return false;
++ return xfs_verify_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno));
++}
+diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
+index ef26edc2e938..7ba2d129d504 100644
+--- a/fs/xfs/libxfs/xfs_alloc.h
++++ b/fs/xfs/libxfs/xfs_alloc.h
+@@ -232,5 +232,9 @@ int xfs_alloc_query_range(struct xfs_btree_cur *cur,
+ xfs_alloc_query_range_fn fn, void *priv);
+ int xfs_alloc_query_all(struct xfs_btree_cur *cur, xfs_alloc_query_range_fn fn,
+ void *priv);
++xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
++bool xfs_verify_agbno(struct xfs_mount *mp, xfs_agnumber_t agno,
++ xfs_agblock_t agbno);
++bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno);
+
+ #endif /* __XFS_ALLOC_H__ */
+diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c
+index 5d4e43ef4eea..4523a92d5507 100644
+--- a/fs/xfs/libxfs/xfs_rtbitmap.c
++++ b/fs/xfs/libxfs/xfs_rtbitmap.c
+@@ -1086,3 +1086,15 @@ xfs_rtalloc_query_all(
+
+ return xfs_rtalloc_query_range(tp, &keys[0], &keys[1], fn, priv);
+ }
++
++/*
++ * Verify that an realtime block number pointer doesn't point off the
++ * end of the realtime device.
++ */
++bool
++xfs_verify_rtbno(
++ struct xfs_mount *mp,
++ xfs_rtblock_t rtbno)
++{
++ return rtbno < mp->m_sb.sb_rblocks;
++}
+diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h
+index 79defa722bf1..3f30f846d7f2 100644
+--- a/fs/xfs/xfs_rtalloc.h
++++ b/fs/xfs/xfs_rtalloc.h
+@@ -138,6 +138,7 @@ int xfs_rtalloc_query_range(struct xfs_trans *tp,
+ int xfs_rtalloc_query_all(struct xfs_trans *tp,
+ xfs_rtalloc_query_range_fn fn,
+ void *priv);
++bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno);
+ #else
+ # define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (ENOSYS)
+ # define xfs_rtfree_extent(t,b,l) (ENOSYS)
+@@ -146,6 +147,7 @@ int xfs_rtalloc_query_all(struct xfs_trans *tp,
+ # define xfs_rtalloc_query_range(t,l,h,f,p) (ENOSYS)
+ # define xfs_rtalloc_query_all(t,f,p) (ENOSYS)
+ # define xfs_rtbuf_get(m,t,b,i,p) (ENOSYS)
++# define xfs_verify_rtbno(m, r) (false)
+ static inline int /* error */
+ xfs_rtmount_init(
+ xfs_mount_t *mp) /* file system mount structure */
+--
+2.16.4
+
diff --git a/patches.fixes/xfs-export-various-function-for-the-online-scrubber.patch b/patches.fixes/xfs-export-various-function-for-the-online-scrubber.patch
new file mode 100644
index 0000000000..efc78e3892
--- /dev/null
+++ b/patches.fixes/xfs-export-various-function-for-the-online-scrubber.patch
@@ -0,0 +1,277 @@
+From 2678809799e6e37db0800725157f5ebfc03a9df7 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Fri, 16 Jun 2017 11:00:07 -0700
+Subject: [PATCH] xfs: export various function for the online scrubber
+Git-commit: 2678809799e6e37db0800725157f5ebfc03a9df7
+Patch-mainline: v4.13-rc1
+References: bsc#1123663
+
+Export various internal functions so that the online scrubber can use
+them to check the state of metadata.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_alloc.c | 2 +-
+ fs/xfs/libxfs/xfs_alloc.h | 2 ++
+ fs/xfs/libxfs/xfs_btree.c | 12 ++++++------
+ fs/xfs/libxfs/xfs_btree.h | 13 +++++++++++++
+ fs/xfs/libxfs/xfs_dir2_leaf.c | 2 +-
+ fs/xfs/libxfs/xfs_dir2_priv.h | 2 ++
+ fs/xfs/libxfs/xfs_inode_buf.c | 2 +-
+ fs/xfs/libxfs/xfs_inode_buf.h | 3 +++
+ fs/xfs/libxfs/xfs_rmap.c | 3 ++-
+ fs/xfs/libxfs/xfs_rmap.h | 3 +++
+ fs/xfs/libxfs/xfs_rtbitmap.c | 2 +-
+ fs/xfs/xfs_itable.c | 2 +-
+ fs/xfs/xfs_itable.h | 2 ++
+ fs/xfs/xfs_rtalloc.h | 3 +++
+ 14 files changed, 41 insertions(+), 12 deletions(-)
+
+diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
+index 7486401ccbd3..fefa8daa1c36 100644
+--- a/fs/xfs/libxfs/xfs_alloc.c
++++ b/fs/xfs/libxfs/xfs_alloc.c
+@@ -606,7 +606,7 @@ const struct xfs_buf_ops xfs_agfl_buf_ops = {
+ /*
+ * Read in the allocation group free block array.
+ */
+-STATIC int /* error */
++int /* error */
+ xfs_alloc_read_agfl(
+ xfs_mount_t *mp, /* mount point structure */
+ xfs_trans_t *tp, /* transaction pointer */
+diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
+index 77d9c27330ab..ef26edc2e938 100644
+--- a/fs/xfs/libxfs/xfs_alloc.h
++++ b/fs/xfs/libxfs/xfs_alloc.h
+@@ -213,6 +213,8 @@ xfs_alloc_get_rec(
+
+ int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
++int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp,
++ xfs_agnumber_t agno, struct xfs_buf **bpp);
+ int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
+ int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno,
+ struct xfs_buf **agbp);
+diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
+index 2aac3f499d97..2f8075aa8725 100644
+--- a/fs/xfs/libxfs/xfs_btree.c
++++ b/fs/xfs/libxfs/xfs_btree.c
+@@ -568,7 +568,7 @@ xfs_btree_ptr_offset(
+ /*
+ * Return a pointer to the n-th record in the btree block.
+ */
+-STATIC union xfs_btree_rec *
++union xfs_btree_rec *
+ xfs_btree_rec_addr(
+ struct xfs_btree_cur *cur,
+ int n,
+@@ -581,7 +581,7 @@ xfs_btree_rec_addr(
+ /*
+ * Return a pointer to the n-th key in the btree block.
+ */
+-STATIC union xfs_btree_key *
++union xfs_btree_key *
+ xfs_btree_key_addr(
+ struct xfs_btree_cur *cur,
+ int n,
+@@ -594,7 +594,7 @@ xfs_btree_key_addr(
+ /*
+ * Return a pointer to the n-th high key in the btree block.
+ */
+-STATIC union xfs_btree_key *
++union xfs_btree_key *
+ xfs_btree_high_key_addr(
+ struct xfs_btree_cur *cur,
+ int n,
+@@ -607,7 +607,7 @@ xfs_btree_high_key_addr(
+ /*
+ * Return a pointer to the n-th block pointer in the btree block.
+ */
+-STATIC union xfs_btree_ptr *
++union xfs_btree_ptr *
+ xfs_btree_ptr_addr(
+ struct xfs_btree_cur *cur,
+ int n,
+@@ -641,7 +641,7 @@ xfs_btree_get_iroot(
+ * Retrieve the block pointer from the cursor at the given level.
+ * This may be an inode btree root or from a buffer.
+ */
+-STATIC struct xfs_btree_block * /* generic btree block pointer */
++struct xfs_btree_block * /* generic btree block pointer */
+ xfs_btree_get_block(
+ struct xfs_btree_cur *cur, /* btree cursor */
+ int level, /* level in btree */
+@@ -1756,7 +1756,7 @@ xfs_btree_decrement(
+ return error;
+ }
+
+-STATIC int
++int
+ xfs_btree_lookup_get_block(
+ struct xfs_btree_cur *cur, /* btree cursor */
+ int level, /* level in the btree */
+diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
+index 177a364ce5cf..9c95e965cfe5 100644
+--- a/fs/xfs/libxfs/xfs_btree.h
++++ b/fs/xfs/libxfs/xfs_btree.h
+@@ -504,4 +504,17 @@ int xfs_btree_visit_blocks(struct xfs_btree_cur *cur,
+
+ int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_extlen_t *blocks);
+
++union xfs_btree_rec *xfs_btree_rec_addr(struct xfs_btree_cur *cur, int n,
++ struct xfs_btree_block *block);
++union xfs_btree_key *xfs_btree_key_addr(struct xfs_btree_cur *cur, int n,
++ struct xfs_btree_block *block);
++union xfs_btree_key *xfs_btree_high_key_addr(struct xfs_btree_cur *cur, int n,
++ struct xfs_btree_block *block);
++union xfs_btree_ptr *xfs_btree_ptr_addr(struct xfs_btree_cur *cur, int n,
++ struct xfs_btree_block *block);
++int xfs_btree_lookup_get_block(struct xfs_btree_cur *cur, int level,
++ union xfs_btree_ptr *pp, struct xfs_btree_block **blkp);
++struct xfs_btree_block *xfs_btree_get_block(struct xfs_btree_cur *cur,
++ int level, struct xfs_buf **bpp);
++
+ #endif /* __XFS_BTREE_H__ */
+diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
+index 68bf3e860a90..7002024a5d0d 100644
+--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
++++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
+@@ -256,7 +256,7 @@ const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = {
+ .verify_write = xfs_dir3_leafn_write_verify,
+ };
+
+-static int
++int
+ xfs_dir3_leaf_read(
+ struct xfs_trans *tp,
+ struct xfs_inode *dp,
+diff --git a/fs/xfs/libxfs/xfs_dir2_priv.h b/fs/xfs/libxfs/xfs_dir2_priv.h
+index 011df4da6cc2..576f2d267fa7 100644
+--- a/fs/xfs/libxfs/xfs_dir2_priv.h
++++ b/fs/xfs/libxfs/xfs_dir2_priv.h
+@@ -58,6 +58,8 @@ extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
+ struct xfs_buf **bpp);
+
+ /* xfs_dir2_leaf.c */
++extern int xfs_dir3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
++ xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp);
+ extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
+ xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp);
+ extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
+diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
+index d887af940f09..0c970cf7ab63 100644
+--- a/fs/xfs/libxfs/xfs_inode_buf.c
++++ b/fs/xfs/libxfs/xfs_inode_buf.c
+@@ -381,7 +381,7 @@ xfs_log_dinode_to_disk(
+ }
+ }
+
+-static bool
++bool
+ xfs_dinode_verify(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
+index 0827d7def1ce..a9c97a356c30 100644
+--- a/fs/xfs/libxfs/xfs_inode_buf.h
++++ b/fs/xfs/libxfs/xfs_inode_buf.h
+@@ -82,4 +82,7 @@ void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
+ #define xfs_inobp_check(mp, bp)
+ #endif /* DEBUG */
+
++bool xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino,
++ struct xfs_dinode *dip);
++
+ #endif /* __XFS_INODE_BUF_H__ */
+diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
+index 1bcb41fe0156..eda275beebe0 100644
+--- a/fs/xfs/libxfs/xfs_rmap.c
++++ b/fs/xfs/libxfs/xfs_rmap.c
+@@ -179,7 +179,8 @@ xfs_rmap_delete(
+ return error;
+ }
+
+-static int
++/* Convert an internal btree record to an rmap record. */
++int
+ xfs_rmap_btrec_to_irec(
+ union xfs_btree_rec *rec,
+ struct xfs_rmap_irec *irec)
+diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
+index 265116d044f4..466ede637080 100644
+--- a/fs/xfs/libxfs/xfs_rmap.h
++++ b/fs/xfs/libxfs/xfs_rmap.h
+@@ -216,5 +216,8 @@ int xfs_rmap_lookup_le_range(struct xfs_btree_cur *cur, xfs_agblock_t bno,
+ struct xfs_rmap_irec *irec, int *stat);
+ int xfs_rmap_compare(const struct xfs_rmap_irec *a,
+ const struct xfs_rmap_irec *b);
++union xfs_btree_rec;
++int xfs_rmap_btrec_to_irec(union xfs_btree_rec *rec,
++ struct xfs_rmap_irec *irec);
+
+ #endif /* __XFS_RMAP_H__ */
+diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c
+index 26bba7f90fdf..5d4e43ef4eea 100644
+--- a/fs/xfs/libxfs/xfs_rtbitmap.c
++++ b/fs/xfs/libxfs/xfs_rtbitmap.c
+@@ -70,7 +70,7 @@ const struct xfs_buf_ops xfs_rtbuf_ops = {
+ * Get a buffer for the bitmap or summary file block specified.
+ * The buffer is returned read and locked.
+ */
+-static int
++int
+ xfs_rtbuf_get(
+ xfs_mount_t *mp, /* file system mount structure */
+ xfs_trans_t *tp, /* transaction pointer */
+diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
+index 26d67ce3c18d..c393a2f6d8c3 100644
+--- a/fs/xfs/xfs_itable.c
++++ b/fs/xfs/xfs_itable.c
+@@ -31,7 +31,7 @@
+ #include "xfs_trace.h"
+ #include "xfs_icache.h"
+
+-STATIC int
++int
+ xfs_internal_inum(
+ xfs_mount_t *mp,
+ xfs_ino_t ino)
+diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
+index 6ea8b3912fa4..17e86e0541af 100644
+--- a/fs/xfs/xfs_itable.h
++++ b/fs/xfs/xfs_itable.h
+@@ -96,4 +96,6 @@ xfs_inumbers(
+ void __user *buffer, /* buffer with inode info */
+ inumbers_fmt_pf formatter);
+
++int xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);
++
+ #endif /* __XFS_ITABLE_H__ */
+diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h
+index f13133e6f19f..79defa722bf1 100644
+--- a/fs/xfs/xfs_rtalloc.h
++++ b/fs/xfs/xfs_rtalloc.h
+@@ -107,6 +107,8 @@ xfs_growfs_rt(
+ /*
+ * From xfs_rtbitmap.c
+ */
++int xfs_rtbuf_get(struct xfs_mount *mp, struct xfs_trans *tp,
++ xfs_rtblock_t block, int issum, struct xfs_buf **bpp);
+ int xfs_rtcheck_range(struct xfs_mount *mp, struct xfs_trans *tp,
+ xfs_rtblock_t start, xfs_extlen_t len, int val,
+ xfs_rtblock_t *new, int *stat);
+@@ -143,6 +145,7 @@ int xfs_rtalloc_query_all(struct xfs_trans *tp,
+ # define xfs_growfs_rt(mp,in) (ENOSYS)
+ # define xfs_rtalloc_query_range(t,l,h,f,p) (ENOSYS)
+ # define xfs_rtalloc_query_all(t,f,p) (ENOSYS)
++# define xfs_rtbuf_get(m,t,b,i,p) (ENOSYS)
+ static inline int /* error */
+ xfs_rtmount_init(
+ xfs_mount_t *mp) /* file system mount structure */
+--
+2.16.4
+
diff --git a/patches.fixes/xfs-make-errortag-a-per-mountpoint-structure.patch b/patches.fixes/xfs-make-errortag-a-per-mountpoint-structure.patch
new file mode 100644
index 0000000000..fe026452b2
--- /dev/null
+++ b/patches.fixes/xfs-make-errortag-a-per-mountpoint-structure.patch
@@ -0,0 +1,336 @@
+From 31965ef34802f49903bba06dd7c3b96a2e2ed4e4 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Tue, 20 Jun 2017 17:54:46 -0700
+Subject: [PATCH] xfs: make errortag a per-mountpoint structure
+Git-commit: 31965ef34802f49903bba06dd7c3b96a2e2ed4e4
+Patch-mainline: v4.13-rc1
+References: bsc#1123663
+
+Remove the xfs_etest structure in favor of a per-mountpoint structure.
+This will give us the flexibility to set as many error injection points
+as we want, and later enable us to set up sysfs knobs to set the trigger
+frequency as we wish. This comes at a cost of higher memory use, but
+unti we hit 1024 injection points (we're at 29) or a lot of mounts this
+shouldn't be a huge issue.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/xfs_error.c | 154 ++++++++++++++++++++++++++++-------------------------
+ fs/xfs/xfs_error.h | 25 +++++----
+ fs/xfs/xfs_ioctl.c | 4 +-
+ fs/xfs/xfs_mount.c | 10 +++-
+ fs/xfs/xfs_mount.h | 7 +++
+ 5 files changed, 111 insertions(+), 89 deletions(-)
+
+diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
+index ed7ee4e8af73..52f75bc1abac 100644
+--- a/fs/xfs/xfs_error.c
++++ b/fs/xfs/xfs_error.c
+@@ -25,100 +25,106 @@
+
+ #ifdef DEBUG
+
+-int xfs_etest[XFS_NUM_INJECT_ERROR];
+-int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR];
+-char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR];
+-int xfs_error_test_active;
++static unsigned int xfs_errortag_random_default[] = {
++ XFS_RANDOM_DEFAULT,
++ XFS_RANDOM_IFLUSH_1,
++ XFS_RANDOM_IFLUSH_2,
++ XFS_RANDOM_IFLUSH_3,
++ XFS_RANDOM_IFLUSH_4,
++ XFS_RANDOM_IFLUSH_5,
++ XFS_RANDOM_IFLUSH_6,
++ XFS_RANDOM_DA_READ_BUF,
++ XFS_RANDOM_BTREE_CHECK_LBLOCK,
++ XFS_RANDOM_BTREE_CHECK_SBLOCK,
++ XFS_RANDOM_ALLOC_READ_AGF,
++ XFS_RANDOM_IALLOC_READ_AGI,
++ XFS_RANDOM_ITOBP_INOTOBP,
++ XFS_RANDOM_IUNLINK,
++ XFS_RANDOM_IUNLINK_REMOVE,
++ XFS_RANDOM_DIR_INO_VALIDATE,
++ XFS_RANDOM_BULKSTAT_READ_CHUNK,
++ XFS_RANDOM_IODONE_IOERR,
++ XFS_RANDOM_STRATREAD_IOERR,
++ XFS_RANDOM_STRATCMPL_IOERR,
++ XFS_RANDOM_DIOWRITE_IOERR,
++ XFS_RANDOM_BMAPIFORMAT,
++ XFS_RANDOM_FREE_EXTENT,
++ XFS_RANDOM_RMAP_FINISH_ONE,
++ XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE,
++ XFS_RANDOM_REFCOUNT_FINISH_ONE,
++ XFS_RANDOM_BMAP_FINISH_ONE,
++ XFS_RANDOM_AG_RESV_CRITICAL,
++};
+
+ int
+-xfs_error_test(int error_tag, int *fsidp, char *expression,
+- int line, char *file, unsigned long randfactor)
++xfs_errortag_init(
++ struct xfs_mount *mp)
+ {
+- int i;
+- int64_t fsid;
++ mp->m_errortag = kmem_zalloc(sizeof(unsigned int) * XFS_ERRTAG_MAX,
++ KM_SLEEP | KM_MAYFAIL);
++ if (!mp->m_errortag)
++ return -ENOMEM;
++ return 0;
++}
+
+- if (prandom_u32() % randfactor)
+- return 0;
++void
++xfs_errortag_del(
++ struct xfs_mount *mp)
++{
++ kmem_free(mp->m_errortag);
++}
+
+- memcpy(&fsid, fsidp, sizeof(xfs_fsid_t));
++bool
++xfs_errortag_test(
++ struct xfs_mount *mp,
++ const char *expression,
++ const char *file,
++ int line,
++ unsigned int error_tag)
++{
++ unsigned int randfactor;
+
+- for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
+- if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
+- xfs_warn(NULL,
+- "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
+- expression, file, line, xfs_etest_fsname[i]);
+- return 1;
+- }
+- }
++ ASSERT(error_tag < XFS_ERRTAG_MAX);
++ randfactor = mp->m_errortag[error_tag];
++ if (!randfactor || prandom_u32() % randfactor)
++ return false;
+
+- return 0;
++ xfs_warn_ratelimited(mp,
++"Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
++ expression, file, line, mp->m_fsname);
++ return true;
+ }
+
+ int
+-xfs_errortag_add(unsigned int error_tag, xfs_mount_t *mp)
++xfs_errortag_set(
++ struct xfs_mount *mp,
++ unsigned int error_tag,
++ unsigned int tag_value)
+ {
+- int i;
+- int len;
+- int64_t fsid;
+-
+ if (error_tag >= XFS_ERRTAG_MAX)
+ return -EINVAL;
+
+- memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
+-
+- for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
+- if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
+- xfs_warn(mp, "error tag #%d on", error_tag);
+- return 0;
+- }
+- }
+-
+- for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
+- if (xfs_etest[i] == 0) {
+- xfs_warn(mp, "Turned on XFS error tag #%d",
+- error_tag);
+- xfs_etest[i] = error_tag;
+- xfs_etest_fsid[i] = fsid;
+- len = strlen(mp->m_fsname);
+- xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP);
+- strcpy(xfs_etest_fsname[i], mp->m_fsname);
+- xfs_error_test_active++;
+- return 0;
+- }
+- }
+-
+- xfs_warn(mp, "error tag overflow, too many turned on");
+-
+- return 1;
++ mp->m_errortag[error_tag] = tag_value;
++ return 0;
+ }
+
+ int
+-xfs_errortag_clearall(xfs_mount_t *mp, int loud)
++xfs_errortag_add(
++ struct xfs_mount *mp,
++ unsigned int error_tag)
+ {
+- int64_t fsid;
+- int cleared = 0;
+- int i;
+-
+- memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t));
+-
+-
+- for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
+- if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) &&
+- xfs_etest[i] != 0) {
+- cleared = 1;
+- xfs_warn(mp, "Clearing XFS error tag #%d",
+- xfs_etest[i]);
+- xfs_etest[i] = 0;
+- xfs_etest_fsid[i] = 0LL;
+- kmem_free(xfs_etest_fsname[i]);
+- xfs_etest_fsname[i] = NULL;
+- xfs_error_test_active--;
+- }
+- }
++ if (error_tag >= XFS_ERRTAG_MAX)
++ return -EINVAL;
+
+- if (loud || cleared)
+- xfs_warn(mp, "Cleared all XFS error tags for filesystem");
++ return xfs_errortag_set(mp, error_tag,
++ xfs_errortag_random_default[error_tag]);
++}
+
++int
++xfs_errortag_clearall(
++ struct xfs_mount *mp)
++{
++ memset(mp->m_errortag, 0, sizeof(unsigned int) * XFS_ERRTAG_MAX);
+ return 0;
+ }
+ #endif /* DEBUG */
+diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
+index 05f8666733a0..b4316d39e1ca 100644
+--- a/fs/xfs/xfs_error.h
++++ b/fs/xfs/xfs_error.h
+@@ -131,21 +131,24 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
+ #define XFS_RANDOM_AG_RESV_CRITICAL 4
+
+ #ifdef DEBUG
+-extern int xfs_error_test_active;
+-extern int xfs_error_test(int, int *, char *, int, char *, unsigned long);
+-
+-#define XFS_NUM_INJECT_ERROR 10
++extern int xfs_errortag_init(struct xfs_mount *mp);
++extern void xfs_errortag_del(struct xfs_mount *mp);
++extern bool xfs_errortag_test(struct xfs_mount *mp, const char *expression,
++ const char *file, int line, unsigned int error_tag);
+ #define XFS_TEST_ERROR(expr, mp, tag, rf) \
+- ((expr) || (xfs_error_test_active && \
+- xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \
+- (rf))))
++ ((expr) || xfs_errortag_test((mp), #expr, __FILE__, __LINE__, (tag)))
+
+-extern int xfs_errortag_add(unsigned int error_tag, struct xfs_mount *mp);
+-extern int xfs_errortag_clearall(struct xfs_mount *mp, int loud);
++extern int xfs_errortag_set(struct xfs_mount *mp, unsigned int error_tag,
++ unsigned int tag_value);
++extern int xfs_errortag_add(struct xfs_mount *mp, unsigned int error_tag);
++extern int xfs_errortag_clearall(struct xfs_mount *mp);
+ #else
++#define xfs_errortag_init(mp) (0)
++#define xfs_errortag_del(mp)
+ #define XFS_TEST_ERROR(expr, mp, tag, rf) (expr)
+-#define xfs_errortag_add(tag, mp) (ENOSYS)
+-#define xfs_errortag_clearall(mp, loud) (ENOSYS)
++#define xfs_errortag_set(mp, tag, val) (ENOSYS)
++#define xfs_errortag_add(mp, tag) (ENOSYS)
++#define xfs_errortag_clearall(mp) (ENOSYS)
+ #endif /* DEBUG */
+
+ /*
+diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
+index 8ffe4eac0b48..9c0c7a920304 100644
+--- a/fs/xfs/xfs_ioctl.c
++++ b/fs/xfs/xfs_ioctl.c
+@@ -2037,14 +2037,14 @@ xfs_file_ioctl(
+ if (copy_from_user(&in, arg, sizeof(in)))
+ return -EFAULT;
+
+- return xfs_errortag_add(in.errtag, mp);
++ return xfs_errortag_add(mp, in.errtag);
+ }
+
+ case XFS_IOC_ERROR_CLEARALL:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+- return xfs_errortag_clearall(mp, 1);
++ return xfs_errortag_clearall(mp);
+
+ case XFS_IOC_FREE_EOFBLOCKS: {
+ struct xfs_fs_eofblocks eofb;
+diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
+index cc6789d35232..1a98c35e1ccf 100644
+--- a/fs/xfs/xfs_mount.c
++++ b/fs/xfs/xfs_mount.c
+@@ -720,10 +720,13 @@ xfs_mountfs(
+ if (error)
+ goto out_del_stats;
+
++ error = xfs_errortag_init(mp);
++ if (error)
++ goto out_remove_error_sysfs;
+
+ error = xfs_uuid_mount(mp);
+ if (error)
+- goto out_remove_error_sysfs;
++ goto out_remove_errortag;
+
+ /*
+ * Set the minimum read and write sizes
+@@ -1042,6 +1045,8 @@ xfs_mountfs(
+ xfs_da_unmount(mp);
+ out_remove_uuid:
+ xfs_uuid_unmount(mp);
++ out_remove_errortag:
++ xfs_errortag_del(mp);
+ out_remove_error_sysfs:
+ xfs_error_sysfs_del(mp);
+ out_del_stats:
+@@ -1145,10 +1150,11 @@ xfs_unmountfs(
+ xfs_uuid_unmount(mp);
+
+ #if defined(DEBUG)
+- xfs_errortag_clearall(mp, 0);
++ xfs_errortag_clearall(mp);
+ #endif
+ xfs_free_perag(mp);
+
++ xfs_errortag_del(mp);
+ xfs_error_sysfs_del(mp);
+ xfs_sysfs_del(&mp->m_stats.xs_kobj);
+ xfs_sysfs_del(&mp->m_kobj);
+diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
+index 305d95394e2d..e002ac52a4e6 100644
+--- a/fs/xfs/xfs_mount.h
++++ b/fs/xfs/xfs_mount.h
+@@ -198,6 +198,13 @@ typedef struct xfs_mount {
+
+ bool m_fail_unmount;
+ #ifdef DEBUG
++ /*
++ * Frequency with which errors are injected. Replaces xfs_etest; the
++ * value stored in here is the inverse of the frequency with which the
++ * error triggers. 1 = always, 2 = half the time, etc.
++ */
++ unsigned int *m_errortag;
++
+ /*
+ * DEBUG mode instrumentation to test and/or trigger delayed allocation
+ * block killing in the event of failed writes. When enabled, all
+--
+2.16.4
+
diff --git a/patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch b/patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch
new file mode 100644
index 0000000000..0091045f8a
--- /dev/null
+++ b/patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch
@@ -0,0 +1,279 @@
+From 52c732eee78b47ac2eb828b1c7fa611cd37b0090 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Tue, 17 Oct 2017 21:37:33 -0700
+Subject: [PATCH] xfs: refactor btree block header checking functions
+Git-commit: 52c732eee78b47ac2eb828b1c7fa611cd37b0090
+Patch-mainline: v4.15-rc1
+References: bsc#1123663
+
+Refactor the btree block header checks to have an internal function that
+returns the address of the failing check without logging errors. The
+scrubber will call the internal function, while the external version
+will maintain the current logging behavior.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_btree.c | 168 +++++++++++++++++++++++++++-------------------
+ fs/xfs/libxfs/xfs_btree.h | 8 +++
+ fs/xfs/libxfs/xfs_types.h | 6 ++
+ fs/xfs/xfs_linux.h | 7 ++
+ 4 files changed, 121 insertions(+), 68 deletions(-)
+
+diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
+index ae19f242c237..8bb20e1cf57b 100644
+--- a/fs/xfs/libxfs/xfs_btree.c
++++ b/fs/xfs/libxfs/xfs_btree.c
+@@ -63,44 +63,63 @@ xfs_btree_magic(
+ return magic;
+ }
+
+-STATIC int /* error (0 or EFSCORRUPTED) */
+-xfs_btree_check_lblock(
+- struct xfs_btree_cur *cur, /* btree cursor */
+- struct xfs_btree_block *block, /* btree long form block pointer */
+- int level, /* level of the btree block */
+- struct xfs_buf *bp) /* buffer for block, if any */
++/*
++ * Check a long btree block header. Return the address of the failing check,
++ * or NULL if everything is ok.
++ */
++xfs_failaddr_t
++__xfs_btree_check_lblock(
++ struct xfs_btree_cur *cur,
++ struct xfs_btree_block *block,
++ int level,
++ struct xfs_buf *bp)
+ {
+- int lblock_ok = 1; /* block passes checks */
+- struct xfs_mount *mp; /* file system mount point */
++ struct xfs_mount *mp = cur->bc_mp;
+ xfs_btnum_t btnum = cur->bc_btnum;
+- int crc;
+-
+- mp = cur->bc_mp;
+- crc = xfs_sb_version_hascrc(&mp->m_sb);
++ int crc = xfs_sb_version_hascrc(&mp->m_sb);
+
+ if (crc) {
+- lblock_ok = lblock_ok &&
+- uuid_equal(&block->bb_u.l.bb_uuid,
+- &mp->m_sb.sb_meta_uuid) &&
+- block->bb_u.l.bb_blkno == cpu_to_be64(
+- bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
++ if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid))
++ return __this_address;
++ if (block->bb_u.l.bb_blkno !=
++ cpu_to_be64(bp ? bp->b_bn : XFS_BUF_DADDR_NULL))
++ return __this_address;
++ if (block->bb_u.l.bb_pad != cpu_to_be32(0))
++ return __this_address;
+ }
+
+- lblock_ok = lblock_ok &&
+- be32_to_cpu(block->bb_magic) == xfs_btree_magic(crc, btnum) &&
+- be16_to_cpu(block->bb_level) == level &&
+- be16_to_cpu(block->bb_numrecs) <=
+- cur->bc_ops->get_maxrecs(cur, level) &&
+- block->bb_u.l.bb_leftsib &&
+- (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK) ||
+- XFS_FSB_SANITY_CHECK(mp,
+- be64_to_cpu(block->bb_u.l.bb_leftsib))) &&
+- block->bb_u.l.bb_rightsib &&
+- (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK) ||
+- XFS_FSB_SANITY_CHECK(mp,
+- be64_to_cpu(block->bb_u.l.bb_rightsib)));
+-
+- if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp,
++ if (be32_to_cpu(block->bb_magic) != xfs_btree_magic(crc, btnum))
++ return __this_address;
++ if (be16_to_cpu(block->bb_level) != level)
++ return __this_address;
++ if (be16_to_cpu(block->bb_numrecs) >
++ cur->bc_ops->get_maxrecs(cur, level))
++ return __this_address;
++ if (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) &&
++ !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_leftsib),
++ level + 1))
++ return __this_address;
++ if (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) &&
++ !xfs_btree_check_lptr(cur, be64_to_cpu(block->bb_u.l.bb_rightsib),
++ level + 1))
++ return __this_address;
++
++ return NULL;
++}
++
++/* Check a long btree block header. */
++int
++xfs_btree_check_lblock(
++ struct xfs_btree_cur *cur,
++ struct xfs_btree_block *block,
++ int level,
++ struct xfs_buf *bp)
++{
++ struct xfs_mount *mp = cur->bc_mp;
++ xfs_failaddr_t fa;
++
++ fa = __xfs_btree_check_lblock(cur, block, level, bp);
++ if (unlikely(XFS_TEST_ERROR(fa != NULL, mp,
+ XFS_ERRTAG_BTREE_CHECK_LBLOCK))) {
+ if (bp)
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+@@ -110,48 +129,61 @@ xfs_btree_check_lblock(
+ return 0;
+ }
+
+-STATIC int /* error (0 or EFSCORRUPTED) */
+-xfs_btree_check_sblock(
+- struct xfs_btree_cur *cur, /* btree cursor */
+- struct xfs_btree_block *block, /* btree short form block pointer */
+- int level, /* level of the btree block */
+- struct xfs_buf *bp) /* buffer containing block */
++/*
++ * Check a short btree block header. Return the address of the failing check,
++ * or NULL if everything is ok.
++ */
++xfs_failaddr_t
++__xfs_btree_check_sblock(
++ struct xfs_btree_cur *cur,
++ struct xfs_btree_block *block,
++ int level,
++ struct xfs_buf *bp)
+ {
+- struct xfs_mount *mp; /* file system mount point */
+- struct xfs_buf *agbp; /* buffer for ag. freespace struct */
+- struct xfs_agf *agf; /* ag. freespace structure */
+- xfs_agblock_t agflen; /* native ag. freespace length */
+- int sblock_ok = 1; /* block passes checks */
++ struct xfs_mount *mp = cur->bc_mp;
+ xfs_btnum_t btnum = cur->bc_btnum;
+- int crc;
+-
+- mp = cur->bc_mp;
+- crc = xfs_sb_version_hascrc(&mp->m_sb);
+- agbp = cur->bc_private.a.agbp;
+- agf = XFS_BUF_TO_AGF(agbp);
+- agflen = be32_to_cpu(agf->agf_length);
++ int crc = xfs_sb_version_hascrc(&mp->m_sb);
+
+ if (crc) {
+- sblock_ok = sblock_ok &&
+- uuid_equal(&block->bb_u.s.bb_uuid,
+- &mp->m_sb.sb_meta_uuid) &&
+- block->bb_u.s.bb_blkno == cpu_to_be64(
+- bp ? bp->b_bn : XFS_BUF_DADDR_NULL);
++ if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid))
++ return __this_address;
++ if (block->bb_u.s.bb_blkno !=
++ cpu_to_be64(bp ? bp->b_bn : XFS_BUF_DADDR_NULL))
++ return __this_address;
+ }
+
+- sblock_ok = sblock_ok &&
+- be32_to_cpu(block->bb_magic) == xfs_btree_magic(crc, btnum) &&
+- be16_to_cpu(block->bb_level) == level &&
+- be16_to_cpu(block->bb_numrecs) <=
+- cur->bc_ops->get_maxrecs(cur, level) &&
+- (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) ||
+- be32_to_cpu(block->bb_u.s.bb_leftsib) < agflen) &&
+- block->bb_u.s.bb_leftsib &&
+- (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) ||
+- be32_to_cpu(block->bb_u.s.bb_rightsib) < agflen) &&
+- block->bb_u.s.bb_rightsib;
+-
+- if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp,
++ if (be32_to_cpu(block->bb_magic) != xfs_btree_magic(crc, btnum))
++ return __this_address;
++ if (be16_to_cpu(block->bb_level) != level)
++ return __this_address;
++ if (be16_to_cpu(block->bb_numrecs) >
++ cur->bc_ops->get_maxrecs(cur, level))
++ return __this_address;
++ if (block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK) &&
++ !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_leftsib),
++ level + 1))
++ return __this_address;
++ if (block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK) &&
++ !xfs_btree_check_sptr(cur, be32_to_cpu(block->bb_u.s.bb_rightsib),
++ level + 1))
++ return __this_address;
++
++ return NULL;
++}
++
++/* Check a short btree block header. */
++STATIC int
++xfs_btree_check_sblock(
++ struct xfs_btree_cur *cur,
++ struct xfs_btree_block *block,
++ int level,
++ struct xfs_buf *bp)
++{
++ struct xfs_mount *mp = cur->bc_mp;
++ xfs_failaddr_t fa;
++
++ fa = __xfs_btree_check_sblock(cur, block, level, bp);
++ if (unlikely(XFS_TEST_ERROR(fa != NULL, mp,
+ XFS_ERRTAG_BTREE_CHECK_SBLOCK))) {
+ if (bp)
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
+index 8f52eda8eb82..3f8001de2493 100644
+--- a/fs/xfs/libxfs/xfs_btree.h
++++ b/fs/xfs/libxfs/xfs_btree.h
+@@ -255,6 +255,14 @@ typedef struct xfs_btree_cur
+ */
+ #define XFS_BUF_TO_BLOCK(bp) ((struct xfs_btree_block *)((bp)->b_addr))
+
++/*
++ * Internal long and short btree block checks. They return NULL if the
++ * block is ok or the address of the failed check otherwise.
++ */
++xfs_failaddr_t __xfs_btree_check_lblock(struct xfs_btree_cur *cur,
++ struct xfs_btree_block *block, int level, struct xfs_buf *bp);
++xfs_failaddr_t __xfs_btree_check_sblock(struct xfs_btree_cur *cur,
++ struct xfs_btree_block *block, int level, struct xfs_buf *bp);
+
+ /*
+ * Check that block header is ok.
+diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
+index 0220159bd463..f04dbfb2f50d 100644
+--- a/fs/xfs/libxfs/xfs_types.h
++++ b/fs/xfs/libxfs/xfs_types.h
+@@ -47,6 +47,12 @@ typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
+ typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+ typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
+
++/*
++ * New verifiers will return the instruction address of the failing check.
++ * NULL means everything is ok.
++ */
++typedef void * xfs_failaddr_t;
++
+ /*
+ * Null values for the types.
+ */
+diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
+index dcd1292664b3..00a5efeec496 100644
+--- a/fs/xfs/xfs_linux.h
++++ b/fs/xfs/xfs_linux.h
+@@ -142,6 +142,13 @@ typedef __u32 xfs_nlink_t;
+ #define SYNCHRONIZE() barrier()
+ #define __return_address __builtin_return_address(0)
+
++/*
++ * Return the address of a label. Use barrier() so that the optimizer
++ * won't reorder code to refactor the error jumpouts into a single
++ * return, which throws off the reported address.
++ */
++#define __this_address ({ __label__ __here; __here: barrier(); &&__here; })
++
+ #define XFS_PROJID_DEFAULT 0
+
+ #define MIN(a,b) (min(a,b))
+--
+2.16.4
+
diff --git a/patches.fixes/xfs-refactor-btree-pointer-checks.patch b/patches.fixes/xfs-refactor-btree-pointer-checks.patch
new file mode 100644
index 0000000000..ceae8b7a6a
--- /dev/null
+++ b/patches.fixes/xfs-refactor-btree-pointer-checks.patch
@@ -0,0 +1,162 @@
+From f135761a73b18877bdfb44018fe993172c7be203 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Tue, 17 Oct 2017 21:37:33 -0700
+Subject: [PATCH] xfs: refactor btree pointer checks
+Git-commit: f135761a73b18877bdfb44018fe993172c7be203
+Patch-mainline: v4.15-rc1
+References: bsc#1123663
+
+Refactor the btree pointer checks so that we can call them from the
+scrub code without logging errors to dmesg. Preserve the existing error
+reporting for regular operations.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_bmap.c | 4 +--
+ fs/xfs/libxfs/xfs_btree.c | 70 ++++++++++++++++++++++-------------------------
+ fs/xfs/libxfs/xfs_btree.h | 13 +++++++--
+ 3 files changed, 45 insertions(+), 42 deletions(-)
+
+diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
+index dd6672b81c26..7eac21a310bf 100644
+--- a/fs/xfs/libxfs/xfs_bmap.c
++++ b/fs/xfs/libxfs/xfs_bmap.c
+@@ -646,8 +646,8 @@ xfs_bmap_btree_to_extents(
+ cbno = be64_to_cpu(*pp);
+ *logflagsp = 0;
+ #ifdef DEBUG
+- if ((error = xfs_btree_check_lptr(cur, cbno, 1)))
+- return error;
++ XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
++ xfs_btree_check_lptr(cur, cbno, 1));
+ #endif
+ error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, XFS_BMAP_BTREE_REF,
+ &xfs_bmbt_buf_ops);
+diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
+index 5bfb88261c7e..ae19f242c237 100644
+--- a/fs/xfs/libxfs/xfs_btree.c
++++ b/fs/xfs/libxfs/xfs_btree.c
+@@ -177,59 +177,53 @@ xfs_btree_check_block(
+ return xfs_btree_check_sblock(cur, block, level, bp);
+ }
+
+-/*
+- * Check that (long) pointer is ok.
+- */
+-int /* error (0 or EFSCORRUPTED) */
++/* Check that this long pointer is valid and points within the fs. */
++bool
+ xfs_btree_check_lptr(
+- struct xfs_btree_cur *cur, /* btree cursor */
+- xfs_fsblock_t bno, /* btree block disk address */
+- int level) /* btree block level */
++ struct xfs_btree_cur *cur,
++ xfs_fsblock_t fsbno,
++ int level)
+ {
+- XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
+- level > 0 &&
+- bno != NULLFSBLOCK &&
+- XFS_FSB_SANITY_CHECK(cur->bc_mp, bno));
+- return 0;
++ if (level <= 0)
++ return false;
++ return xfs_verify_fsbno(cur->bc_mp, fsbno);
+ }
+
+-#ifdef DEBUG
+-/*
+- * Check that (short) pointer is ok.
+- */
+-STATIC int /* error (0 or EFSCORRUPTED) */
++/* Check that this short pointer is valid and points within the AG. */
++bool
+ xfs_btree_check_sptr(
+- struct xfs_btree_cur *cur, /* btree cursor */
+- xfs_agblock_t bno, /* btree block disk address */
+- int level) /* btree block level */
++ struct xfs_btree_cur *cur,
++ xfs_agblock_t agbno,
++ int level)
+ {
+- xfs_agblock_t agblocks = cur->bc_mp->m_sb.sb_agblocks;
+-
+- XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
+- level > 0 &&
+- bno != NULLAGBLOCK &&
+- bno != 0 &&
+- bno < agblocks);
+- return 0;
++ if (level <= 0)
++ return false;
++ return xfs_verify_agbno(cur->bc_mp, cur->bc_private.a.agno, agbno);
+ }
+
++#ifdef DEBUG
+ /*
+- * Check that block ptr is ok.
++ * Check that a given (indexed) btree pointer at a certain level of a
++ * btree is valid and doesn't point past where it should.
+ */
+-STATIC int /* error (0 or EFSCORRUPTED) */
++int
+ xfs_btree_check_ptr(
+- struct xfs_btree_cur *cur, /* btree cursor */
+- union xfs_btree_ptr *ptr, /* btree block disk address */
+- int index, /* offset from ptr to check */
+- int level) /* btree block level */
++ struct xfs_btree_cur *cur,
++ union xfs_btree_ptr *ptr,
++ int index,
++ int level)
+ {
+ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
+- return xfs_btree_check_lptr(cur,
+- be64_to_cpu((&ptr->l)[index]), level);
++ XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
++ xfs_btree_check_lptr(cur,
++ be64_to_cpu((&ptr->l)[index]), level));
+ } else {
+- return xfs_btree_check_sptr(cur,
+- be32_to_cpu((&ptr->s)[index]), level);
++ XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
++ xfs_btree_check_sptr(cur,
++ be32_to_cpu((&ptr->s)[index]), level));
+ }
++
++ return 0;
+ }
+ #endif
+
+diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
+index f2a88c3b1159..8f52eda8eb82 100644
+--- a/fs/xfs/libxfs/xfs_btree.h
++++ b/fs/xfs/libxfs/xfs_btree.h
+@@ -269,10 +269,19 @@ xfs_btree_check_block(
+ /*
+ * Check that (long) pointer is ok.
+ */
+-int /* error (0 or EFSCORRUPTED) */
++bool /* error (0 or EFSCORRUPTED) */
+ xfs_btree_check_lptr(
+ struct xfs_btree_cur *cur, /* btree cursor */
+- xfs_fsblock_t ptr, /* btree block disk address */
++ xfs_fsblock_t fsbno, /* btree block disk address */
++ int level); /* btree block level */
++
++/*
++ * Check that (short) pointer is ok.
++ */
++bool /* error (0 or EFSCORRUPTED) */
++xfs_btree_check_sptr(
++ struct xfs_btree_cur *cur, /* btree cursor */
++ xfs_agblock_t agbno, /* btree block disk address */
+ int level); /* btree block level */
+
+ /*
+--
+2.16.4
+
diff --git a/patches.fixes/xfs-remove-unneeded-parameter-from-XFS_TEST_ERROR.patch b/patches.fixes/xfs-remove-unneeded-parameter-from-XFS_TEST_ERROR.patch
new file mode 100644
index 0000000000..2299b68e7d
--- /dev/null
+++ b/patches.fixes/xfs-remove-unneeded-parameter-from-XFS_TEST_ERROR.patch
@@ -0,0 +1,306 @@
+From 9e24cfd044853e0e46e7149b91b7bb09effb0a79 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Tue, 20 Jun 2017 17:54:47 -0700
+Subject: [PATCH] xfs: remove unneeded parameter from XFS_TEST_ERROR
+Git-commit: 9e24cfd044853e0e46e7149b91b7bb09effb0a79
+Patch-mainline: v4.13-rc1
+References: bsc#1123663
+
+Since we moved the injected error frequency controls to the mountpoint,
+we can get rid of the last argument to XFS_TEST_ERROR.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_ag_resv.c | 3 +--
+ fs/xfs/libxfs/xfs_alloc.c | 6 ++----
+ fs/xfs/libxfs/xfs_bmap.c | 13 ++++++-------
+ fs/xfs/libxfs/xfs_btree.c | 6 ++----
+ fs/xfs/libxfs/xfs_dir2.c | 3 +--
+ fs/xfs/libxfs/xfs_ialloc.c | 3 +--
+ fs/xfs/libxfs/xfs_inode_buf.c | 3 +--
+ fs/xfs/libxfs/xfs_refcount.c | 6 ++----
+ fs/xfs/libxfs/xfs_rmap.c | 3 +--
+ fs/xfs/xfs_error.h | 4 ++--
+ fs/xfs/xfs_inode.c | 11 +++++------
+ fs/xfs/xfs_iomap.c | 2 +-
+ fs/xfs/xfs_log.c | 3 +--
+ 13 files changed, 26 insertions(+), 40 deletions(-)
+
+--- a/fs/xfs/libxfs/xfs_ag_resv.c
++++ b/fs/xfs/libxfs/xfs_ag_resv.c
+@@ -111,8 +111,7 @@
+
+ /* Critically low if less than 10% or max btree height remains. */
+ return XFS_TEST_ERROR(avail < orig / 10 || avail < XFS_BTREE_MAXLEVELS,
+- pag->pag_mount, XFS_ERRTAG_AG_RESV_CRITICAL,
+- XFS_RANDOM_AG_RESV_CRITICAL);
++ pag->pag_mount, XFS_ERRTAG_AG_RESV_CRITICAL);
+ }
+
+ /*
+--- a/fs/xfs/libxfs/xfs_alloc.c
++++ b/fs/xfs/libxfs/xfs_alloc.c
+@@ -2454,8 +2454,7 @@
+ !xfs_buf_verify_cksum(bp, XFS_AGF_CRC_OFF))
+ xfs_buf_ioerror(bp, -EFSBADCRC);
+ else if (XFS_TEST_ERROR(!xfs_agf_verify(mp, bp), mp,
+- XFS_ERRTAG_ALLOC_READ_AGF,
+- XFS_RANDOM_ALLOC_READ_AGF))
++ XFS_ERRTAG_ALLOC_READ_AGF))
+ xfs_buf_ioerror(bp, -EFSCORRUPTED);
+
+ if (bp->b_error)
+@@ -2842,8 +2841,7 @@
+ ASSERT(type != XFS_AG_RESV_AGFL);
+
+ if (XFS_TEST_ERROR(false, mp,
+- XFS_ERRTAG_FREE_EXTENT,
+- XFS_RANDOM_FREE_EXTENT))
++ XFS_ERRTAG_FREE_EXTENT))
+ return -EIO;
+
+ error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
+--- a/fs/xfs/libxfs/xfs_bmap.c
++++ b/fs/xfs/libxfs/xfs_bmap.c
+@@ -3992,7 +3992,7 @@
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
+- mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
++ mp, XFS_ERRTAG_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp);
+ return -EFSCORRUPTED;
+ }
+@@ -4473,7 +4473,7 @@
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
+- mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
++ mp, XFS_ERRTAG_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp);
+ return -EFSCORRUPTED;
+ }
+@@ -4694,7 +4694,7 @@
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
+- mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
++ mp, XFS_ERRTAG_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT("xfs_bmapi_remap", XFS_ERRLEVEL_LOW, mp);
+ return -EFSCORRUPTED;
+ }
+@@ -6077,7 +6077,7 @@
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
+- mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
++ mp, XFS_ERRTAG_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT("xfs_bmap_shift_extents",
+ XFS_ERRLEVEL_LOW, mp);
+ return -EFSCORRUPTED;
+@@ -6229,7 +6229,7 @@
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
+- mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
++ mp, XFS_ERRTAG_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT("xfs_bmap_split_extent_at",
+ XFS_ERRLEVEL_LOW, mp);
+ return -EFSCORRUPTED;
+@@ -6486,8 +6486,7 @@
+ return -EFSCORRUPTED;
+
+ if (XFS_TEST_ERROR(false, tp->t_mountp,
+- XFS_ERRTAG_BMAP_FINISH_ONE,
+- XFS_RANDOM_BMAP_FINISH_ONE))
++ XFS_ERRTAG_BMAP_FINISH_ONE))
+ return -EIO;
+
+ switch (type) {
+--- a/fs/xfs/libxfs/xfs_btree.c
++++ b/fs/xfs/libxfs/xfs_btree.c
+@@ -101,8 +101,7 @@
+ be64_to_cpu(block->bb_u.l.bb_rightsib)));
+
+ if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp,
+- XFS_ERRTAG_BTREE_CHECK_LBLOCK,
+- XFS_RANDOM_BTREE_CHECK_LBLOCK))) {
++ XFS_ERRTAG_BTREE_CHECK_LBLOCK))) {
+ if (bp)
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+ XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+@@ -153,8 +152,7 @@
+ block->bb_u.s.bb_rightsib;
+
+ if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp,
+- XFS_ERRTAG_BTREE_CHECK_SBLOCK,
+- XFS_RANDOM_BTREE_CHECK_SBLOCK))) {
++ XFS_ERRTAG_BTREE_CHECK_SBLOCK))) {
+ if (bp)
+ trace_xfs_btree_corrupt(bp, _RET_IP_);
+ XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+--- a/fs/xfs/libxfs/xfs_dir2.c
++++ b/fs/xfs/libxfs/xfs_dir2.c
+@@ -218,8 +218,7 @@
+ agblkno != 0 &&
+ ioff < (1 << mp->m_sb.sb_inopblog) &&
+ XFS_AGINO_TO_INO(mp, agno, agino) == ino;
+- if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
+- XFS_RANDOM_DIR_INO_VALIDATE))) {
++ if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) {
+ xfs_warn(mp, "Invalid inode number 0x%Lx",
+ (unsigned long long) ino);
+ XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
+--- a/fs/xfs/libxfs/xfs_ialloc.c
++++ b/fs/xfs/libxfs/xfs_ialloc.c
+@@ -2542,8 +2542,7 @@
+ !xfs_buf_verify_cksum(bp, XFS_AGI_CRC_OFF))
+ xfs_buf_ioerror(bp, -EFSBADCRC);
+ else if (XFS_TEST_ERROR(!xfs_agi_verify(bp), mp,
+- XFS_ERRTAG_IALLOC_READ_AGI,
+- XFS_RANDOM_IALLOC_READ_AGI))
++ XFS_ERRTAG_IALLOC_READ_AGI))
+ xfs_buf_ioerror(bp, -EFSCORRUPTED);
+
+ if (bp->b_error)
+--- a/fs/xfs/libxfs/xfs_inode_buf.c
++++ b/fs/xfs/libxfs/xfs_inode_buf.c
+@@ -105,8 +105,7 @@
+ di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
+ xfs_dinode_good_version(mp, dip->di_version);
+ if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
+- XFS_ERRTAG_ITOBP_INOTOBP,
+- XFS_RANDOM_ITOBP_INOTOBP))) {
++ XFS_ERRTAG_ITOBP_INOTOBP))) {
+ if (readahead) {
+ bp->b_flags &= ~XBF_DONE;
+ xfs_buf_ioerror(bp, -EIO);
+--- a/fs/xfs/libxfs/xfs_refcount.c
++++ b/fs/xfs/libxfs/xfs_refcount.c
+@@ -813,8 +813,7 @@
+ */
+ if (cur->bc_private.a.priv.refc.nr_ops > 2 &&
+ XFS_TEST_ERROR(false, cur->bc_mp,
+- XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE,
+- XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE))
++ XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE))
+ return false;
+
+ if (cur->bc_private.a.priv.refc.nr_ops == 0)
+@@ -1076,8 +1075,7 @@
+ blockcount);
+
+ if (XFS_TEST_ERROR(false, mp,
+- XFS_ERRTAG_REFCOUNT_FINISH_ONE,
+- XFS_RANDOM_REFCOUNT_FINISH_ONE))
++ XFS_ERRTAG_REFCOUNT_FINISH_ONE))
+ return -EIO;
+
+ /*
+--- a/fs/xfs/libxfs/xfs_rmap.c
++++ b/fs/xfs/libxfs/xfs_rmap.c
+@@ -2086,8 +2086,7 @@
+ startoff, blockcount, state);
+
+ if (XFS_TEST_ERROR(false, mp,
+- XFS_ERRTAG_RMAP_FINISH_ONE,
+- XFS_RANDOM_RMAP_FINISH_ONE))
++ XFS_ERRTAG_RMAP_FINISH_ONE))
+ return -EIO;
+
+ /*
+--- a/fs/xfs/xfs_error.h
++++ b/fs/xfs/xfs_error.h
+@@ -135,7 +135,7 @@
+ extern void xfs_errortag_del(struct xfs_mount *mp);
+ extern bool xfs_errortag_test(struct xfs_mount *mp, const char *expression,
+ const char *file, int line, unsigned int error_tag);
+-#define XFS_TEST_ERROR(expr, mp, tag, rf) \
++#define XFS_TEST_ERROR(expr, mp, tag) \
+ ((expr) || xfs_errortag_test((mp), #expr, __FILE__, __LINE__, (tag)))
+
+ extern int xfs_errortag_set(struct xfs_mount *mp, unsigned int error_tag,
+@@ -145,7 +145,7 @@
+ #else
+ #define xfs_errortag_init(mp) (0)
+ #define xfs_errortag_del(mp)
+-#define XFS_TEST_ERROR(expr, mp, tag, rf) (expr)
++#define XFS_TEST_ERROR(expr, mp, tag) (expr)
+ #define xfs_errortag_set(mp, tag, val) (ENOSYS)
+ #define xfs_errortag_add(mp, tag) (ENOSYS)
+ #define xfs_errortag_clearall(mp) (ENOSYS)
+--- a/fs/xfs/xfs_inode.c
++++ b/fs/xfs/xfs_inode.c
+@@ -3489,7 +3489,7 @@
+ dip = xfs_buf_offset(bp, ip->i_imap.im_boffset);
+
+ if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC),
+- mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
++ mp, XFS_ERRTAG_IFLUSH_1)) {
+ xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+ "%s: Bad inode %Lu magic number 0x%x, ptr 0x%p",
+ __func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip);
+@@ -3499,7 +3499,7 @@
+ if (XFS_TEST_ERROR(
+ (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
+ (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
+- mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) {
++ mp, XFS_ERRTAG_IFLUSH_3)) {
+ xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+ "%s: Bad regular inode %Lu, ptr 0x%p",
+ __func__, ip->i_ino, ip);
+@@ -3510,7 +3510,7 @@
+ (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
+ (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
+ (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL),
+- mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) {
++ mp, XFS_ERRTAG_IFLUSH_4)) {
+ xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+ "%s: Bad directory inode %Lu, ptr 0x%p",
+ __func__, ip->i_ino, ip);
+@@ -3518,8 +3518,7 @@
+ }
+ }
+ if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents >
+- ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5,
+- XFS_RANDOM_IFLUSH_5)) {
++ ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
+ xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+ "%s: detected corrupt incore inode %Lu, "
+ "total extents = %d, nblocks = %Ld, ptr 0x%p",
+@@ -3529,7 +3528,7 @@
+ goto corrupt_out;
+ }
+ if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize,
+- mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) {
++ mp, XFS_ERRTAG_IFLUSH_6)) {
+ xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
+ "%s: bad inode %Lu, forkoff 0x%x, ptr 0x%p",
+ __func__, ip->i_ino, ip->i_d.di_forkoff, ip);
+--- a/fs/xfs/xfs_iomap.c
++++ b/fs/xfs/xfs_iomap.c
+@@ -543,7 +543,7 @@
+ if (unlikely(XFS_TEST_ERROR(
+ (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
+ XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
+- mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
++ mp, XFS_ERRTAG_BMAPIFORMAT))) {
+ XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+ error = -EFSCORRUPTED;
+ goto out_unlock;
+--- a/fs/xfs/xfs_log.c
++++ b/fs/xfs/xfs_log.c
+@@ -1189,8 +1189,7 @@
+ * IOABORT state. The IOABORT state is only set in DEBUG mode to inject
+ * CRC errors into log recovery.
+ */
+- if (XFS_TEST_ERROR(bp->b_error, l->l_mp, XFS_ERRTAG_IODONE_IOERR,
+- XFS_RANDOM_IODONE_IOERR) ||
++ if (XFS_TEST_ERROR(bp->b_error, l->l_mp, XFS_ERRTAG_IODONE_IOERR) ||
+ iclog->ic_state & XLOG_STATE_IOABORT) {
+ if (iclog->ic_state & XLOG_STATE_IOABORT)
+ iclog->ic_state &= ~XLOG_STATE_IOABORT;
diff --git a/patches.fixes/xfs-rename-MAXPATHLEN-to-XFS_SYMLINK_MAXLEN.patch b/patches.fixes/xfs-rename-MAXPATHLEN-to-XFS_SYMLINK_MAXLEN.patch
new file mode 100644
index 0000000000..19cb718dda
--- /dev/null
+++ b/patches.fixes/xfs-rename-MAXPATHLEN-to-XFS_SYMLINK_MAXLEN.patch
@@ -0,0 +1,138 @@
+From 6eb0b8df9f74f33d1a69100117630a7a87a9cc96 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Fri, 7 Jul 2017 08:37:26 -0700
+Subject: [PATCH] xfs: rename MAXPATHLEN to XFS_SYMLINK_MAXLEN
+Git-commit: 6eb0b8df9f74f33d1a69100117630a7a87a9cc96
+Patch-mainline: v4.13-rc1
+References: bsc#1123663
+
+XFS has a maximum symlink target length of 1024 bytes; this is a
+holdover from the Irix days. Unfortunately, the constant establishing
+this is 'MAXPATHLEN' and is /not/ the same as the Linux MAXPATHLEN,
+which is 4096.
+
+The kernel enforces its 1024 byte MAXPATHLEN on symlink targets, but
+xfsprogs picks up the (Linux) system 4096 byte MAXPATHLEN, which means
+that xfs_repair doesn't complain about oversized symlinks.
+
+Since this is an on-disk format constraint, put the define in the XFS
+namespace and move everything over to use the new name.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_format.h | 1 +
+ fs/xfs/libxfs/xfs_symlink_remote.c | 2 +-
+ fs/xfs/libxfs/xfs_trans_resv.c | 4 ++--
+ fs/xfs/xfs_iops.c | 2 +-
+ fs/xfs/xfs_linux.h | 1 -
+ fs/xfs/xfs_symlink.c | 6 +++---
+ 6 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
+index e204a942e5bf..23229f0c5b15 100644
+--- a/fs/xfs/libxfs/xfs_format.h
++++ b/fs/xfs/libxfs/xfs_format.h
+@@ -1211,6 +1211,7 @@ struct xfs_dsymlink_hdr {
+
+ #define XFS_SYMLINK_CRC_OFF offsetof(struct xfs_dsymlink_hdr, sl_crc)
+
++#define XFS_SYMLINK_MAXLEN 1024
+ /*
+ * The maximum pathlen is 1024 bytes. Since the minimum file system
+ * blocksize is 512 bytes, we can get a max of 3 extents back from
+diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c
+index 2e2c6716b623..c484877129a0 100644
+--- a/fs/xfs/libxfs/xfs_symlink_remote.c
++++ b/fs/xfs/libxfs/xfs_symlink_remote.c
+@@ -114,7 +114,7 @@ xfs_symlink_verify(
+ if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
+ return false;
+ if (be32_to_cpu(dsl->sl_offset) +
+- be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN)
++ be32_to_cpu(dsl->sl_bytes) >= XFS_SYMLINK_MAXLEN)
+ return false;
+ if (dsl->sl_owner == 0)
+ return false;
+diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c
+index b456cca1bfb2..6bd916bd35e2 100644
+--- a/fs/xfs/libxfs/xfs_trans_resv.c
++++ b/fs/xfs/libxfs/xfs_trans_resv.c
+@@ -477,14 +477,14 @@ xfs_calc_mkdir_reservation(
+ /*
+ * Making a new symplink is the same as creating a new file, but
+ * with the added blocks for remote symlink data which can be up to 1kB in
+- * length (MAXPATHLEN).
++ * length (XFS_SYMLINK_MAXLEN).
+ */
+ STATIC uint
+ xfs_calc_symlink_reservation(
+ struct xfs_mount *mp)
+ {
+ return xfs_calc_create_reservation(mp) +
+- xfs_calc_buf_res(1, MAXPATHLEN);
++ xfs_calc_buf_res(1, XFS_SYMLINK_MAXLEN);
+ }
+
+ /*
+diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
+index 077e2b2ac773..469c9fa4c178 100644
+--- a/fs/xfs/xfs_iops.c
++++ b/fs/xfs/xfs_iops.c
+@@ -460,7 +460,7 @@ xfs_vn_get_link(
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
+- link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
++ link = kmalloc(XFS_SYMLINK_MAXLEN+1, GFP_KERNEL);
+ if (!link)
+ goto out_err;
+
+diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
+index ecdae42267d3..44abaecd1481 100644
+--- a/fs/xfs/xfs_linux.h
++++ b/fs/xfs/xfs_linux.h
+@@ -143,7 +143,6 @@ typedef __u32 xfs_nlink_t;
+ #define __return_address __builtin_return_address(0)
+
+ #define XFS_PROJID_DEFAULT 0
+-#define MAXPATHLEN 1024
+
+ #define MIN(a,b) (min(a,b))
+ #define MAX(a,b) (max(a,b))
+diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
+index 493804857d67..12cd9cf7de41 100644
+--- a/fs/xfs/xfs_symlink.c
++++ b/fs/xfs/xfs_symlink.c
+@@ -143,7 +143,7 @@ xfs_readlink(
+ if (!pathlen)
+ goto out;
+
+- if (pathlen < 0 || pathlen > MAXPATHLEN) {
++ if (pathlen < 0 || pathlen > XFS_SYMLINK_MAXLEN) {
+ xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)",
+ __func__, (unsigned long long) ip->i_ino,
+ (long long) pathlen);
+@@ -202,7 +202,7 @@ xfs_symlink(
+ * Check component lengths of the target path name.
+ */
+ pathlen = strlen(target_path);
+- if (pathlen >= MAXPATHLEN) /* total string too long */
++ if (pathlen >= XFS_SYMLINK_MAXLEN) /* total string too long */
+ return -ENAMETOOLONG;
+
+ udqp = gdqp = NULL;
+@@ -559,7 +559,7 @@ xfs_inactive_symlink(
+ return 0;
+ }
+
+- if (pathlen < 0 || pathlen > MAXPATHLEN) {
++ if (pathlen < 0 || pathlen > XFS_SYMLINK_MAXLEN) {
+ xfs_alert(mp, "%s: inode (0x%llx) bad symlink length (%d)",
+ __func__, (unsigned long long)ip->i_ino, pathlen);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+--
+2.16.4
+
diff --git a/patches.fixes/xfs-sanity-check-the-unused-space-before-trying-to-u.patch b/patches.fixes/xfs-sanity-check-the-unused-space-before-trying-to-u.patch
new file mode 100644
index 0000000000..9f1ce38986
--- /dev/null
+++ b/patches.fixes/xfs-sanity-check-the-unused-space-before-trying-to-u.patch
@@ -0,0 +1,321 @@
+From 6915ef35c0350e87a104cb4c4ab2121c81ca7a34 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Fri, 23 Mar 2018 10:06:51 -0700
+Subject: [PATCH] xfs: sanity-check the unused space before trying to use it
+Git-commit: 6915ef35c0350e87a104cb4c4ab2121c81ca7a34
+Patch-mainline: v4.17-rc1
+References: bsc#1123663
+
+In xfs_dir2_data_use_free, we examine on-disk metadata and ASSERT if
+it doesn't make sense. Since a carefully crafted fuzzed image can cause
+the kernel to crash after blowing a bunch of assertions, let's move
+those checks into a validator function and rig everything up to return
+EFSCORRUPTED to userspace. Found by lastbit fuzzing ltail.bestcount via
+xfs/391.
+
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Reviewed-by: Brian Foster <bfoster@redhat.com>
+Acked-by: Anthony Iliopoulos <ailiopoulos@suse.com>
+
+---
+ fs/xfs/libxfs/xfs_dir2.h | 2 -
+ fs/xfs/libxfs/xfs_dir2_block.c | 59 ++++++++++++++++++-------------
+ fs/xfs/libxfs/xfs_dir2_data.c | 78 +++++++++++++++++++++++++++++++----------
+ fs/xfs/libxfs/xfs_dir2_leaf.c | 10 +++--
+ fs/xfs/libxfs/xfs_dir2_node.c | 11 ++++-
+ 5 files changed, 111 insertions(+), 49 deletions(-)
+
+--- a/fs/xfs/libxfs/xfs_dir2.h
++++ b/fs/xfs/libxfs/xfs_dir2.h
+@@ -173,7 +173,7 @@
+ extern void xfs_dir2_data_make_free(struct xfs_da_args *args,
+ struct xfs_buf *bp, xfs_dir2_data_aoff_t offset,
+ xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
+-extern void xfs_dir2_data_use_free(struct xfs_da_args *args,
++extern int xfs_dir2_data_use_free(struct xfs_da_args *args,
+ struct xfs_buf *bp, struct xfs_dir2_data_unused *dup,
+ xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,
+ int *needlogp, int *needscanp);
+--- a/fs/xfs/libxfs/xfs_dir2_block.c
++++ b/fs/xfs/libxfs/xfs_dir2_block.c
+@@ -450,15 +450,19 @@
+ * No stale entries, will use enddup space to hold new leaf.
+ */
+ if (!btp->stale) {
++ xfs_dir2_data_aoff_t aoff;
++
+ /*
+ * Mark the space needed for the new leaf entry, now in use.
+ */
+- xfs_dir2_data_use_free(args, bp, enddup,
+- (xfs_dir2_data_aoff_t)
+- ((char *)enddup - (char *)hdr + be16_to_cpu(enddup->length) -
+- sizeof(*blp)),
+- (xfs_dir2_data_aoff_t)sizeof(*blp),
+- &needlog, &needscan);
++ aoff = (xfs_dir2_data_aoff_t)((char *)enddup - (char *)hdr +
++ be16_to_cpu(enddup->length) - sizeof(*blp));
++ error = xfs_dir2_data_use_free(args, bp, enddup, aoff,
++ (xfs_dir2_data_aoff_t)sizeof(*blp), &needlog,
++ &needscan);
++ if (error)
++ return error;
++
+ /*
+ * Update the tail (entry count).
+ */
+@@ -540,9 +544,11 @@
+ /*
+ * Mark space for the data entry used.
+ */
+- xfs_dir2_data_use_free(args, bp, dup,
+- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
+- (xfs_dir2_data_aoff_t)len, &needlog, &needscan);
++ error = xfs_dir2_data_use_free(args, bp, dup,
++ (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
++ (xfs_dir2_data_aoff_t)len, &needlog, &needscan);
++ if (error)
++ return error;
+ /*
+ * Create the new data entry.
+ */
+@@ -996,8 +1002,10 @@
+ /*
+ * Use up the space at the end of the block (blp/btp).
+ */
+- xfs_dir2_data_use_free(args, dbp, dup, args->geo->blksize - size, size,
+- &needlog, &needscan);
++ error = xfs_dir2_data_use_free(args, dbp, dup,
++ args->geo->blksize - size, size, &needlog, &needscan);
++ if (error)
++ return error;
+ /*
+ * Initialize the block tail.
+ */
+@@ -1109,18 +1117,14 @@
+ * Add block 0 to the inode.
+ */
+ error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);
+- if (error) {
+- kmem_free(sfp);
+- return error;
+- }
++ if (error)
++ goto out_free;
+ /*
+ * Initialize the data block, then convert it to block format.
+ */
+ error = xfs_dir3_data_init(args, blkno, &bp);
+- if (error) {
+- kmem_free(sfp);
+- return error;
+- }
++ if (error)
++ goto out_free;
+ xfs_dir3_block_init(mp, tp, bp, dp);
+ hdr = bp->b_addr;
+
+@@ -1135,8 +1139,10 @@
+ */
+ dup = dp->d_ops->data_unused_p(hdr);
+ needlog = needscan = 0;
+- xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
+- i, &needlog, &needscan);
++ error = xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
++ i, &needlog, &needscan);
++ if (error)
++ goto out_free;
+ ASSERT(needscan == 0);
+ /*
+ * Fill in the tail.
+@@ -1149,9 +1155,11 @@
+ /*
+ * Remove the freespace, we'll manage it.
+ */
+- xfs_dir2_data_use_free(args, bp, dup,
+- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
+- be16_to_cpu(dup->length), &needlog, &needscan);
++ error = xfs_dir2_data_use_free(args, bp, dup,
++ (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
++ be16_to_cpu(dup->length), &needlog, &needscan);
++ if (error)
++ goto out_free;
+ /*
+ * Create entry for .
+ */
+@@ -1255,4 +1263,7 @@
+ xfs_dir2_block_log_tail(tp, bp);
+ xfs_dir3_data_check(dp, bp);
+ return 0;
++out_free:
++ kmem_free(sfp);
++ return error;
+ }
+--- a/fs/xfs/libxfs/xfs_dir2_data.c
++++ b/fs/xfs/libxfs/xfs_dir2_data.c
+@@ -910,10 +910,51 @@
+ *needscanp = needscan;
+ }
+
++/* Check our free data for obvious signs of corruption. */
++static inline xfs_failaddr_t
++xfs_dir2_data_check_free(
++ struct xfs_dir2_data_hdr *hdr,
++ struct xfs_dir2_data_unused *dup,
++ xfs_dir2_data_aoff_t offset,
++ xfs_dir2_data_aoff_t len)
++{
++ if (hdr->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC) &&
++ hdr->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC) &&
++ hdr->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) &&
++ hdr->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC))
++ return __this_address;
++ if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG)
++ return __this_address;
++ if (offset < (char *)dup - (char *)hdr)
++ return __this_address;
++ if (offset + len > (char *)dup + be16_to_cpu(dup->length) - (char *)hdr)
++ return __this_address;
++ if ((char *)dup - (char *)hdr !=
++ be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)))
++ return __this_address;
++ return NULL;
++}
++
++/* Sanity-check a new bestfree entry. */
++static inline xfs_failaddr_t
++xfs_dir2_data_check_new_free(
++ struct xfs_dir2_data_hdr *hdr,
++ struct xfs_dir2_data_free *dfp,
++ struct xfs_dir2_data_unused *newdup)
++{
++ if (dfp == NULL)
++ return __this_address;
++ if (dfp->length != newdup->length)
++ return __this_address;
++ if (be16_to_cpu(dfp->offset) != (char *)newdup - (char *)hdr)
++ return __this_address;
++ return NULL;
++}
++
+ /*
+ * Take a byte range out of an existing unused space and make it un-free.
+ */
+-void
++int
+ xfs_dir2_data_use_free(
+ struct xfs_da_args *args,
+ struct xfs_buf *bp,
+@@ -925,23 +966,19 @@
+ {
+ xfs_dir2_data_hdr_t *hdr; /* data block header */
+ xfs_dir2_data_free_t *dfp; /* bestfree pointer */
++ xfs_dir2_data_unused_t *newdup; /* new unused entry */
++ xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
++ struct xfs_dir2_data_free *bf;
++ xfs_failaddr_t fa;
+ int matchback; /* matches end of freespace */
+ int matchfront; /* matches start of freespace */
+ int needscan; /* need to regen bestfree */
+- xfs_dir2_data_unused_t *newdup; /* new unused entry */
+- xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
+ int oldlen; /* old unused entry's length */
+- struct xfs_dir2_data_free *bf;
+
+ hdr = bp->b_addr;
+- ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
+- hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
+- hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
+- hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
+- ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
+- ASSERT(offset >= (char *)dup - (char *)hdr);
+- ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
+- ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
++ fa = xfs_dir2_data_check_free(hdr, dup, offset, len);
++ if (fa)
++ goto corrupt;
+ /*
+ * Look up the entry in the bestfree table.
+ */
+@@ -986,9 +1023,9 @@
+ xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
+ dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
+ needlogp);
+- ASSERT(dfp != NULL);
+- ASSERT(dfp->length == newdup->length);
+- ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
++ fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
++ if (fa)
++ goto corrupt;
+ /*
+ * If we got inserted at the last slot,
+ * that means we don't know if there was a better
+@@ -1014,9 +1051,9 @@
+ xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
+ dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
+ needlogp);
+- ASSERT(dfp != NULL);
+- ASSERT(dfp->length == newdup->length);
+- ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
++ fa = xfs_dir2_data_check_new_free(hdr, dfp, newdup);
++ if (fa)
++ goto corrupt;
+ /*
+ * If we got inserted at the last slot,
+ * that means we don't know if there was a better
+@@ -1062,4 +1099,9 @@
+ }
+ }
+ *needscanp = needscan;
++ return 0;
++corrupt:
++ xfs_corruption_error(__func__, XFS_ERRLEVEL_LOW, args->dp->i_mount,
++ hdr, __FILE__, __LINE__, fa);
++ return -EFSCORRUPTED;
+ }
+--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
++++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
+@@ -850,9 +850,13 @@
+ /*
+ * Mark the initial part of our freespace in use for the new entry.
+ */
+- xfs_dir2_data_use_free(args, dbp, dup,
+- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
+- &needlog, &needscan);
++ error = xfs_dir2_data_use_free(args, dbp, dup,
++ (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
++ length, &needlog, &needscan);
++ if (error) {
++ xfs_trans_brelse(tp, lbp);
++ return error;
++ }
+ /*
+ * Initialize our new entry (at last).
+ */
+--- a/fs/xfs/libxfs/xfs_dir2_node.c
++++ b/fs/xfs/libxfs/xfs_dir2_node.c
+@@ -1713,6 +1713,7 @@
+ __be16 *bests;
+ struct xfs_dir3_icfree_hdr freehdr;
+ struct xfs_dir2_data_free *bf;
++ xfs_dir2_data_aoff_t aoff;
+
+ dp = args->dp;
+ mp = dp->i_mount;
+@@ -2007,9 +2008,13 @@
+ /*
+ * Mark the first part of the unused space, inuse for us.
+ */
+- xfs_dir2_data_use_free(args, dbp, dup,
+- (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
+- &needlog, &needscan);
++ aoff = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
++ error = xfs_dir2_data_use_free(args, dbp, dup, aoff, length,
++ &needlog, &needscan);
++ if (error) {
++ xfs_trans_brelse(tp, dbp);
++ return error;
++ }
+ /*
+ * Fill in the new entry and log it.
+ */
diff --git a/series.conf b/series.conf
index fbcff9d74f..1c6fb6e1c9 100644
--- a/series.conf
+++ b/series.conf
@@ -3561,13 +3561,17 @@
patches.fixes/xfs-release-bli-from-transaction-properly-on-fs-shut.patch
patches.fixes/xfs-remove-bli-from-AIL-before-release-on-transactio.patch
patches.fixes/xfs-remove-double-underscore-integer-types.patch
+ patches.fixes/xfs-export-various-function-for-the-online-scrubber.patch
patches.fixes/xfs-check-if-an-inode-is-cached-and-allocated.patch
patches.fixes/xfs-reflink-find-shared-should-take-a-transaction.patch
+ patches.fixes/xfs-make-errortag-a-per-mountpoint-structure.patch
+ patches.fixes/xfs-remove-unneeded-parameter-from-XFS_TEST_ERROR.patch
patches.fixes/xfs-rewrite-xfs_dq_get_next_id-using-xfs_iext_lookup.patch
patches.fixes/vfs-Add-page_cache_seek_hole_data-helper.patch
patches.fixes/vfs-Add-iomap_seek_hole-and-iomap_seek_data-helpers.patch
patches.fixes/xfs-Switch-to-iomap-for-SEEK_HOLE-SEEK_DATA.patch
patches.fixes/xfs-fix-contiguous-dquot-chunk-iteration-livelock.patch
+ patches.fixes/xfs-rename-MAXPATHLEN-to-XFS_SYMLINK_MAXLEN.patch
patches.drivers/ipmi_ssif-unlock-on-allocation-failure
patches.drivers/0007-ipmi_ssif-remove-redundant-null-check-on-array-clien.patch
patches.drivers/0008-ipmi-Use-the-proper-default-value-for-register-size-.patch
@@ -4133,6 +4137,7 @@
patches.suse/KVM-nVMX-Fix-loss-of-L2-s-NMI-blocking-state.patch
patches.suse/KVM-s390-take-srcu-lock-when-getting-setting-storage.patch
patches.suse/KVM-LAPIC-Fix-reentrancy-issues-with-preempt-notifie.patch
+ patches.fixes/xfs-check-_btree_check_block-value.patch
patches.fixes/xfs-fix-quotacheck-dquot-id-overflow-infinite-loop.patch
patches.fixes/0001-NFS-Optimize-fallocate-by-refreshing-mapping-when-ne.patch
patches.fixes/perf-x86-intel-uncore-fix-skylake-upi-pmu-event-masks.patch
@@ -8232,6 +8237,9 @@
patches.fixes/0027-xfs-remove-all-xfs_bmbt_set_-helpers-except-for-xfs_.patch
patches.fixes/0028-xfs-remove-xfs_bmbt_get_state.patch
patches.fixes/xfs-return-a-distinct-error-code-value-for-IGET_INCO.patch
+ patches.fixes/xfs-create-block-pointer-check-functions.patch
+ patches.fixes/xfs-refactor-btree-pointer-checks.patch
+ patches.fixes/xfs-refactor-btree-block-header-checking-functions.patch
patches.fixes/0029-xfs-add-a-xfs_bmap_fork_to_state-helper.patch
patches.fixes/0030-xfs-make-better-use-of-the-state-variable-in-xfs_bma.patch
patches.fixes/0031-xfs-remove-post-bmap-tracing-in-xfs_bmap_local_to_ex.patch
@@ -14903,6 +14911,7 @@
patches.fixes/xfs-convert-XFS_AGFL_SIZE-to-a-helper-function.patch
patches.fixes/xfs-remove-xfs_zero_range.patch
patches.fixes/xfs-detect-agfl-count-corruption-and-reset-agfl.patch
+ patches.fixes/xfs-sanity-check-the-unused-space-before-trying-to-u.patch
patches.fixes/xfs-catch-inode-allocation-state-mismatch-corruption.patch
patches.suse/btrfs-do-not-check-inode-s-runtime-flags-under-root-orphan_lock.patch
patches.suse/0014-btrfs-tree-checker-Replace-root-parameter-with-fs_in.patch