Skip to content

Commit 3f50ddb

Browse files
author
Darrick J. Wong
committed
xfs: repair link count of nondirectories after rebuilding parent pointers
Since the parent pointer scrubber does not exhaustively search the filesystem for missing parent pointers, it doesn't have a good way to determine that there are pointers missing from an otherwise uncorrupt xattr structure. Instead, for nondirectories it employs a heuristic of comparing the file link count to the number of parent pointers found. However, we don't want this heuristic flagging a false corruption after a repair has actually scanned the entire filesystem to rebuild the parent pointers. Therefore, reset the file link count in this one case because we actually know the correct link count. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent 7be3d20 commit 3f50ddb

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

fs/xfs/scrub/parent_repair.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "xfs_parent.h"
2828
#include "xfs_attr.h"
2929
#include "xfs_bmap.h"
30+
#include "xfs_ag.h"
3031
#include "scrub/xfs_scrub.h"
3132
#include "scrub/scrub.h"
3233
#include "scrub/common.h"
@@ -156,6 +157,9 @@ struct xrep_parent {
156157

157158
/* Have we seen any live updates of parent pointers recently? */
158159
bool saw_pptr_updates;
160+
161+
/* Number of parents we found after all other repairs */
162+
unsigned long long parents;
159163
};
160164

161165
struct xrep_parent_xattr {
@@ -1370,6 +1374,102 @@ xrep_parent_rebuild_tree(
13701374
return 0;
13711375
}
13721376

1377+
/* Count the number of parent pointers. */
1378+
STATIC int
1379+
xrep_parent_count_pptr(
1380+
struct xfs_scrub *sc,
1381+
struct xfs_inode *ip,
1382+
unsigned int attr_flags,
1383+
const unsigned char *name,
1384+
unsigned int namelen,
1385+
const void *value,
1386+
unsigned int valuelen,
1387+
void *priv)
1388+
{
1389+
struct xrep_parent *rp = priv;
1390+
int error;
1391+
1392+
if (!(attr_flags & XFS_ATTR_PARENT))
1393+
return 0;
1394+
1395+
error = xfs_parent_from_attr(sc->mp, attr_flags, name, namelen, value,
1396+
valuelen, NULL, NULL);
1397+
if (error)
1398+
return error;
1399+
1400+
rp->parents++;
1401+
return 0;
1402+
}
1403+
1404+
/*
1405+
* After all parent pointer rebuilding and adoption activity completes, reset
1406+
* the link count of this nondirectory, having scanned the fs to rebuild all
1407+
* parent pointers.
1408+
*/
1409+
STATIC int
1410+
xrep_parent_set_nondir_nlink(
1411+
struct xrep_parent *rp)
1412+
{
1413+
struct xfs_scrub *sc = rp->sc;
1414+
struct xfs_inode *ip = sc->ip;
1415+
struct xfs_perag *pag;
1416+
bool joined = false;
1417+
int error;
1418+
1419+
/* Count parent pointers so we can reset the file link count. */
1420+
rp->parents = 0;
1421+
error = xchk_xattr_walk(sc, ip, xrep_parent_count_pptr, NULL, rp);
1422+
if (error)
1423+
return error;
1424+
1425+
if (rp->parents > 0 && xfs_inode_on_unlinked_list(ip)) {
1426+
xfs_trans_ijoin(sc->tp, sc->ip, 0);
1427+
joined = true;
1428+
1429+
/*
1430+
* The file is on the unlinked list but we found parents.
1431+
* Remove the file from the unlinked list.
1432+
*/
1433+
pag = xfs_perag_get(sc->mp, XFS_INO_TO_AGNO(sc->mp, ip->i_ino));
1434+
if (!pag) {
1435+
ASSERT(0);
1436+
return -EFSCORRUPTED;
1437+
}
1438+
1439+
error = xfs_iunlink_remove(sc->tp, pag, ip);
1440+
xfs_perag_put(pag);
1441+
if (error)
1442+
return error;
1443+
} else if (rp->parents == 0 && !xfs_inode_on_unlinked_list(ip)) {
1444+
xfs_trans_ijoin(sc->tp, sc->ip, 0);
1445+
joined = true;
1446+
1447+
/*
1448+
* The file is not on the unlinked list but we found no
1449+
* parents. Add the file to the unlinked list.
1450+
*/
1451+
error = xfs_iunlink(sc->tp, ip);
1452+
if (error)
1453+
return error;
1454+
}
1455+
1456+
/* Set the correct link count. */
1457+
if (VFS_I(ip)->i_nlink != rp->parents) {
1458+
if (!joined) {
1459+
xfs_trans_ijoin(sc->tp, sc->ip, 0);
1460+
joined = true;
1461+
}
1462+
1463+
set_nlink(VFS_I(ip), min_t(unsigned long long, rp->parents,
1464+
XFS_NLINK_PINNED));
1465+
}
1466+
1467+
/* Log the inode to keep it moving forward if we dirtied anything. */
1468+
if (joined)
1469+
xfs_trans_log_inode(sc->tp, ip, XFS_ILOG_CORE);
1470+
return 0;
1471+
}
1472+
13731473
/* Set up the filesystem scan so we can look for parents. */
13741474
STATIC int
13751475
xrep_parent_setup_scan(
@@ -1494,6 +1594,13 @@ xrep_parent(
14941594
error = xrep_parent_rebuild_tree(rp);
14951595
if (error)
14961596
goto out_teardown;
1597+
if (xfs_has_parent(sc->mp) && !S_ISDIR(VFS_I(sc->ip)->i_mode)) {
1598+
error = xrep_parent_set_nondir_nlink(rp);
1599+
if (error)
1600+
goto out_teardown;
1601+
}
1602+
1603+
error = xrep_defer_finish(sc);
14971604

14981605
out_teardown:
14991606
xrep_parent_teardown(rp);

0 commit comments

Comments
 (0)