|
@@ -1,19 +1,7 @@
|
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
|
/*
|
|
|
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
|
|
|
* All Rights Reserved.
|
|
|
- *
|
|
|
- * This program is free software; you can redistribute it and/or
|
|
|
- * modify it under the terms of the GNU General Public License as
|
|
|
- * published by the Free Software Foundation.
|
|
|
- *
|
|
|
- * This program is distributed in the hope that it would be useful,
|
|
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
- * GNU General Public License for more details.
|
|
|
- *
|
|
|
- * You should have received a copy of the GNU General Public License
|
|
|
- * along with this program; if not, write the Free Software Foundation,
|
|
|
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
*/
|
|
|
#include "xfs.h"
|
|
|
#include "xfs_fs.h"
|
|
@@ -234,7 +222,6 @@ xfs_btree_check_sptr(
|
|
|
return xfs_verify_agbno(cur->bc_mp, cur->bc_private.a.agno, agbno);
|
|
|
}
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
/*
|
|
|
* Check that a given (indexed) btree pointer at a certain level of a
|
|
|
* btree is valid and doesn't point past where it should.
|
|
@@ -247,17 +234,31 @@ xfs_btree_check_ptr(
|
|
|
int level)
|
|
|
{
|
|
|
if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
|
|
|
- XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
|
|
|
- xfs_btree_check_lptr(cur,
|
|
|
- be64_to_cpu((&ptr->l)[index]), level));
|
|
|
+ if (xfs_btree_check_lptr(cur, be64_to_cpu((&ptr->l)[index]),
|
|
|
+ level))
|
|
|
+ return 0;
|
|
|
+ xfs_err(cur->bc_mp,
|
|
|
+"Inode %llu fork %d: Corrupt btree %d pointer at level %d index %d.",
|
|
|
+ cur->bc_private.b.ip->i_ino,
|
|
|
+ cur->bc_private.b.whichfork, cur->bc_btnum,
|
|
|
+ level, index);
|
|
|
} else {
|
|
|
- XFS_WANT_CORRUPTED_RETURN(cur->bc_mp,
|
|
|
- xfs_btree_check_sptr(cur,
|
|
|
- be32_to_cpu((&ptr->s)[index]), level));
|
|
|
+ if (xfs_btree_check_sptr(cur, be32_to_cpu((&ptr->s)[index]),
|
|
|
+ level))
|
|
|
+ return 0;
|
|
|
+ xfs_err(cur->bc_mp,
|
|
|
+"AG %u: Corrupt btree %d pointer at level %d index %d.",
|
|
|
+ cur->bc_private.a.agno, cur->bc_btnum,
|
|
|
+ level, index);
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return -EFSCORRUPTED;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef DEBUG
|
|
|
+# define xfs_btree_debug_check_ptr xfs_btree_check_ptr
|
|
|
+#else
|
|
|
+# define xfs_btree_debug_check_ptr(...) (0)
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
@@ -988,22 +989,30 @@ xfs_btree_readahead(
|
|
|
return xfs_btree_readahead_sblock(cur, lr, block);
|
|
|
}
|
|
|
|
|
|
-STATIC xfs_daddr_t
|
|
|
+STATIC int
|
|
|
xfs_btree_ptr_to_daddr(
|
|
|
struct xfs_btree_cur *cur,
|
|
|
- union xfs_btree_ptr *ptr)
|
|
|
+ union xfs_btree_ptr *ptr,
|
|
|
+ xfs_daddr_t *daddr)
|
|
|
{
|
|
|
- if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
|
|
|
- ASSERT(ptr->l != cpu_to_be64(NULLFSBLOCK));
|
|
|
+ xfs_fsblock_t fsbno;
|
|
|
+ xfs_agblock_t agbno;
|
|
|
+ int error;
|
|
|
|
|
|
- return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l));
|
|
|
- } else {
|
|
|
- ASSERT(cur->bc_private.a.agno != NULLAGNUMBER);
|
|
|
- ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK));
|
|
|
+ error = xfs_btree_check_ptr(cur, ptr, 0, 1);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
|
|
|
- return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno,
|
|
|
- be32_to_cpu(ptr->s));
|
|
|
+ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
|
|
|
+ fsbno = be64_to_cpu(ptr->l);
|
|
|
+ *daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno);
|
|
|
+ } else {
|
|
|
+ agbno = be32_to_cpu(ptr->s);
|
|
|
+ *daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno,
|
|
|
+ agbno);
|
|
|
}
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1018,8 +1027,11 @@ xfs_btree_readahead_ptr(
|
|
|
union xfs_btree_ptr *ptr,
|
|
|
xfs_extlen_t count)
|
|
|
{
|
|
|
- xfs_buf_readahead(cur->bc_mp->m_ddev_targp,
|
|
|
- xfs_btree_ptr_to_daddr(cur, ptr),
|
|
|
+ xfs_daddr_t daddr;
|
|
|
+
|
|
|
+ if (xfs_btree_ptr_to_daddr(cur, ptr, &daddr))
|
|
|
+ return;
|
|
|
+ xfs_buf_readahead(cur->bc_mp->m_ddev_targp, daddr,
|
|
|
cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops);
|
|
|
}
|
|
|
|
|
@@ -1282,11 +1294,14 @@ xfs_btree_get_buf_block(
|
|
|
{
|
|
|
struct xfs_mount *mp = cur->bc_mp;
|
|
|
xfs_daddr_t d;
|
|
|
+ int error;
|
|
|
|
|
|
/* need to sort out how callers deal with failures first */
|
|
|
ASSERT(!(flags & XBF_TRYLOCK));
|
|
|
|
|
|
- d = xfs_btree_ptr_to_daddr(cur, ptr);
|
|
|
+ error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
*bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
|
|
|
mp->m_bsize, flags);
|
|
|
|
|
@@ -1317,7 +1332,9 @@ xfs_btree_read_buf_block(
|
|
|
/* need to sort out how callers deal with failures first */
|
|
|
ASSERT(!(flags & XBF_TRYLOCK));
|
|
|
|
|
|
- d = xfs_btree_ptr_to_daddr(cur, ptr);
|
|
|
+ error = xfs_btree_ptr_to_daddr(cur, ptr, &d);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d,
|
|
|
mp->m_bsize, flags, bpp,
|
|
|
cur->bc_ops->buf_ops);
|
|
@@ -1764,6 +1781,7 @@ xfs_btree_lookup_get_block(
|
|
|
struct xfs_btree_block **blkp) /* return btree block */
|
|
|
{
|
|
|
struct xfs_buf *bp; /* buffer pointer for btree block */
|
|
|
+ xfs_daddr_t daddr;
|
|
|
int error = 0;
|
|
|
|
|
|
/* special case the root block if in an inode */
|
|
@@ -1780,7 +1798,10 @@ xfs_btree_lookup_get_block(
|
|
|
* Otherwise throw it away and get a new one.
|
|
|
*/
|
|
|
bp = cur->bc_bufs[level];
|
|
|
- if (bp && XFS_BUF_ADDR(bp) == xfs_btree_ptr_to_daddr(cur, pp)) {
|
|
|
+ error = xfs_btree_ptr_to_daddr(cur, pp, &daddr);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+ if (bp && XFS_BUF_ADDR(bp) == daddr) {
|
|
|
*blkp = XFS_BUF_TO_BLOCK(bp);
|
|
|
return 0;
|
|
|
}
|
|
@@ -1896,7 +1917,13 @@ xfs_btree_lookup(
|
|
|
high = xfs_btree_get_numrecs(block);
|
|
|
if (!high) {
|
|
|
/* Block is empty, must be an empty leaf. */
|
|
|
- ASSERT(level == 0 && cur->bc_nlevels == 1);
|
|
|
+ if (level != 0 || cur->bc_nlevels != 1) {
|
|
|
+ XFS_CORRUPTION_ERROR(__func__,
|
|
|
+ XFS_ERRLEVEL_LOW,
|
|
|
+ cur->bc_mp, block,
|
|
|
+ sizeof(*block));
|
|
|
+ return -EFSCORRUPTED;
|
|
|
+ }
|
|
|
|
|
|
cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE;
|
|
|
*stat = 0;
|
|
@@ -1946,11 +1973,10 @@ xfs_btree_lookup(
|
|
|
keyno = 1;
|
|
|
pp = xfs_btree_ptr_addr(cur, keyno, block);
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
- error = xfs_btree_check_ptr(cur, pp, 0, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, pp, 0, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
-#endif
|
|
|
+
|
|
|
cur->bc_ptrs[level] = keyno;
|
|
|
}
|
|
|
}
|
|
@@ -2354,11 +2380,11 @@ xfs_btree_lshift(
|
|
|
|
|
|
lpp = xfs_btree_ptr_addr(cur, lrecs, left);
|
|
|
rpp = xfs_btree_ptr_addr(cur, 1, right);
|
|
|
-#ifdef DEBUG
|
|
|
- error = xfs_btree_check_ptr(cur, rpp, 0, level);
|
|
|
+
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, rpp, 0, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
-#endif
|
|
|
+
|
|
|
xfs_btree_copy_keys(cur, lkp, rkp, 1);
|
|
|
xfs_btree_copy_ptrs(cur, lpp, rpp, 1);
|
|
|
|
|
@@ -2393,15 +2419,14 @@ xfs_btree_lshift(
|
|
|
XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1);
|
|
|
if (level > 0) {
|
|
|
/* It's a nonleaf. operate on keys and ptrs */
|
|
|
-#ifdef DEBUG
|
|
|
int i; /* loop index */
|
|
|
|
|
|
for (i = 0; i < rrecs; i++) {
|
|
|
- error = xfs_btree_check_ptr(cur, rpp, i + 1, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, rpp, i + 1, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
xfs_btree_shift_keys(cur,
|
|
|
xfs_btree_key_addr(cur, 2, right),
|
|
|
-1, rrecs);
|
|
@@ -2541,22 +2566,18 @@ xfs_btree_rshift(
|
|
|
rkp = xfs_btree_key_addr(cur, 1, right);
|
|
|
rpp = xfs_btree_ptr_addr(cur, 1, right);
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
for (i = rrecs - 1; i >= 0; i--) {
|
|
|
- error = xfs_btree_check_ptr(cur, rpp, i, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, rpp, i, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
xfs_btree_shift_keys(cur, rkp, 1, rrecs);
|
|
|
xfs_btree_shift_ptrs(cur, rpp, 1, rrecs);
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
- error = xfs_btree_check_ptr(cur, lpp, 0, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, lpp, 0, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
-#endif
|
|
|
|
|
|
/* Now put the new data in, and log it. */
|
|
|
xfs_btree_copy_keys(cur, rkp, lkp, 1);
|
|
@@ -2661,9 +2682,7 @@ __xfs_btree_split(
|
|
|
int rrecs;
|
|
|
int src_index;
|
|
|
int error; /* error return value */
|
|
|
-#ifdef DEBUG
|
|
|
int i;
|
|
|
-#endif
|
|
|
|
|
|
XFS_BTREE_STATS_INC(cur, split);
|
|
|
|
|
@@ -2729,13 +2748,11 @@ __xfs_btree_split(
|
|
|
rkp = xfs_btree_key_addr(cur, 1, right);
|
|
|
rpp = xfs_btree_ptr_addr(cur, 1, right);
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
for (i = src_index; i < rrecs; i++) {
|
|
|
- error = xfs_btree_check_ptr(cur, lpp, i, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, lpp, i, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
/* Copy the keys & pointers to the new block. */
|
|
|
xfs_btree_copy_keys(cur, rkp, lkp, rrecs);
|
|
@@ -2923,9 +2940,7 @@ xfs_btree_new_iroot(
|
|
|
union xfs_btree_ptr nptr; /* new block addr */
|
|
|
int level; /* btree level */
|
|
|
int error; /* error return code */
|
|
|
-#ifdef DEBUG
|
|
|
int i; /* loop counter */
|
|
|
-#endif
|
|
|
|
|
|
XFS_BTREE_STATS_INC(cur, newroot);
|
|
|
|
|
@@ -2972,20 +2987,18 @@ xfs_btree_new_iroot(
|
|
|
xfs_btree_copy_keys(cur, ckp, kp, xfs_btree_get_numrecs(cblock));
|
|
|
|
|
|
cpp = xfs_btree_ptr_addr(cur, 1, cblock);
|
|
|
-#ifdef DEBUG
|
|
|
for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
|
|
|
- error = xfs_btree_check_ptr(cur, pp, i, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, pp, i, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
xfs_btree_copy_ptrs(cur, cpp, pp, xfs_btree_get_numrecs(cblock));
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
- error = xfs_btree_check_ptr(cur, &nptr, 0, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, &nptr, 0, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
-#endif
|
|
|
+
|
|
|
xfs_btree_copy_ptrs(cur, pp, &nptr, 1);
|
|
|
|
|
|
xfs_iroot_realloc(cur->bc_private.b.ip,
|
|
@@ -3229,9 +3242,7 @@ xfs_btree_insrec(
|
|
|
int ptr; /* key/record index */
|
|
|
int numrecs;/* number of records */
|
|
|
int error; /* error return value */
|
|
|
-#ifdef DEBUG
|
|
|
int i;
|
|
|
-#endif
|
|
|
xfs_daddr_t old_bn;
|
|
|
|
|
|
ncur = NULL;
|
|
@@ -3321,22 +3332,18 @@ xfs_btree_insrec(
|
|
|
kp = xfs_btree_key_addr(cur, ptr, block);
|
|
|
pp = xfs_btree_ptr_addr(cur, ptr, block);
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
for (i = numrecs - ptr; i >= 0; i--) {
|
|
|
- error = xfs_btree_check_ptr(cur, pp, i, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, pp, i, level);
|
|
|
if (error)
|
|
|
return error;
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
xfs_btree_shift_keys(cur, kp, 1, numrecs - ptr + 1);
|
|
|
xfs_btree_shift_ptrs(cur, pp, 1, numrecs - ptr + 1);
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
- error = xfs_btree_check_ptr(cur, ptrp, 0, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, ptrp, 0, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
-#endif
|
|
|
|
|
|
/* Now put the new data in, bump numrecs and log it. */
|
|
|
xfs_btree_copy_keys(cur, kp, key, 1);
|
|
@@ -3524,8 +3531,8 @@ xfs_btree_kill_iroot(
|
|
|
int error;
|
|
|
#ifdef DEBUG
|
|
|
union xfs_btree_ptr ptr;
|
|
|
- int i;
|
|
|
#endif
|
|
|
+ int i;
|
|
|
|
|
|
ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
|
|
|
ASSERT(cur->bc_nlevels > 1);
|
|
@@ -3581,13 +3588,13 @@ xfs_btree_kill_iroot(
|
|
|
|
|
|
pp = xfs_btree_ptr_addr(cur, 1, block);
|
|
|
cpp = xfs_btree_ptr_addr(cur, 1, cblock);
|
|
|
-#ifdef DEBUG
|
|
|
+
|
|
|
for (i = 0; i < numrecs; i++) {
|
|
|
- error = xfs_btree_check_ptr(cur, cpp, i, level - 1);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, cpp, i, level - 1);
|
|
|
if (error)
|
|
|
return error;
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
xfs_btree_copy_ptrs(cur, pp, cpp, numrecs);
|
|
|
|
|
|
error = xfs_btree_free_block(cur, cbp);
|
|
@@ -3721,13 +3728,11 @@ xfs_btree_delrec(
|
|
|
lkp = xfs_btree_key_addr(cur, ptr + 1, block);
|
|
|
lpp = xfs_btree_ptr_addr(cur, ptr + 1, block);
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
for (i = 0; i < numrecs - ptr; i++) {
|
|
|
- error = xfs_btree_check_ptr(cur, lpp, i, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, lpp, i, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
if (ptr < numrecs) {
|
|
|
xfs_btree_shift_keys(cur, lkp, -1, numrecs - ptr);
|
|
@@ -4060,13 +4065,13 @@ xfs_btree_delrec(
|
|
|
lpp = xfs_btree_ptr_addr(cur, lrecs + 1, left);
|
|
|
rkp = xfs_btree_key_addr(cur, 1, right);
|
|
|
rpp = xfs_btree_ptr_addr(cur, 1, right);
|
|
|
-#ifdef DEBUG
|
|
|
+
|
|
|
for (i = 1; i < rrecs; i++) {
|
|
|
- error = xfs_btree_check_ptr(cur, rpp, i, level);
|
|
|
+ error = xfs_btree_debug_check_ptr(cur, rpp, i, level);
|
|
|
if (error)
|
|
|
goto error0;
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
xfs_btree_copy_keys(cur, lkp, rkp, rrecs);
|
|
|
xfs_btree_copy_ptrs(cur, lpp, rpp, rrecs);
|
|
|
|