|
27 | 27 | #include "xfs_parent.h"
|
28 | 28 | #include "xfs_attr.h"
|
29 | 29 | #include "xfs_bmap.h"
|
| 30 | +#include "xfs_ag.h" |
30 | 31 | #include "scrub/xfs_scrub.h"
|
31 | 32 | #include "scrub/scrub.h"
|
32 | 33 | #include "scrub/common.h"
|
@@ -156,6 +157,9 @@ struct xrep_parent {
|
156 | 157 |
|
157 | 158 | /* Have we seen any live updates of parent pointers recently? */
|
158 | 159 | bool saw_pptr_updates;
|
| 160 | + |
| 161 | + /* Number of parents we found after all other repairs */ |
| 162 | + unsigned long long parents; |
159 | 163 | };
|
160 | 164 |
|
161 | 165 | struct xrep_parent_xattr {
|
@@ -1370,6 +1374,102 @@ xrep_parent_rebuild_tree(
|
1370 | 1374 | return 0;
|
1371 | 1375 | }
|
1372 | 1376 |
|
| 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 | + |
1373 | 1473 | /* Set up the filesystem scan so we can look for parents. */
|
1374 | 1474 | STATIC int
|
1375 | 1475 | xrep_parent_setup_scan(
|
@@ -1494,6 +1594,13 @@ xrep_parent(
|
1494 | 1594 | error = xrep_parent_rebuild_tree(rp);
|
1495 | 1595 | if (error)
|
1496 | 1596 | 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); |
1497 | 1604 |
|
1498 | 1605 | out_teardown:
|
1499 | 1606 | xrep_parent_teardown(rp);
|
|
0 commit comments