Commit 067d3f71 authored by Chandan Babu R's avatar Chandan Babu R

Merge tag 'repair-orphanage-6.10_2024-04-15' of...

Merge tag 'repair-orphanage-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeA

xfs: move orphan files to lost and found

Orphaned files are defined to be files with nonzero ondisk link count
but no observable parent directory.  This series enables online repair
to reparent orphaned files into the filesystem directory tree, and wires
up this reparenting ability into the directory, file link count, and
parent pointer repair functions.  This is how we fix files with positive
link count that are not reachable through the directory tree.

This patch will also create the orphanage directory (lost+found) if it
is not present.  In contrast to xfs_repair, we follow e2fsck in creating
the lost+found without group or other-owner access to avoid accidental
disclosure of files that were previously hidden by an 0700 directory.
That's silly security, but people have been known to do it.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>

* tag 'repair-orphanage-6.10_2024-04-15' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: ensure dentry consistency when the orphanage adopts a file
  xfs: move files to orphanage instead of letting nlinks drop to zero
  xfs: move orphan files to the orphanage
parents 9e6b93b7 73597e3e
......@@ -4778,14 +4778,22 @@ Orphaned files are adopted by the orphanage as follows:
The ``xrep_orphanage_iolock_two`` function follows the inode locking
strategy discussed earlier.
3. Call ``xrep_orphanage_compute_blkres`` and ``xrep_orphanage_compute_name``
to compute the new name in the orphanage and the block reservation required.
4. Use ``xrep_orphanage_adoption_prep`` to reserve resources to the repair
3. Use ``xrep_adoption_trans_alloc`` to reserve resources to the repair
transaction.
5. Call ``xrep_orphanage_adopt`` to reparent the orphaned file into the lost
and found, and update the kernel dentry cache.
4. Call ``xrep_orphanage_compute_name`` to compute the new name in the
orphanage.
5. If the adoption is going to happen, call ``xrep_adoption_reparent`` to
reparent the orphaned file into the lost and found and invalidate the dentry
cache.
6. Call ``xrep_adoption_finish`` to commit any filesystem updates, release the
orphanage ILOCK, and clean the scrub transaction. Call
``xrep_adoption_commit`` to commit the updates and the scrub transaction.
7. If a runtime error happens, call ``xrep_adoption_cancel`` to release all
resources.
The proposed patches are in the
`orphanage adoption
......
......@@ -205,6 +205,7 @@ xfs-y += $(addprefix scrub/, \
inode_repair.o \
newbt.o \
nlinks_repair.o \
orphanage.o \
parent_repair.o \
rcbag_btree.o \
rcbag.o \
......
......@@ -42,6 +42,7 @@
#include "scrub/readdir.h"
#include "scrub/reap.h"
#include "scrub/findparent.h"
#include "scrub/orphanage.h"
/*
* Directory Repair
......@@ -115,12 +116,21 @@ struct xrep_dir {
*/
struct xrep_parent_scan_info pscan;
/*
* Context information for attaching this directory to the lost+found
* if this directory does not have a parent.
*/
struct xrep_adoption adoption;
/* How many subdirectories did we find? */
uint64_t subdirs;
/* How many dirents did we find? */
unsigned int dirents;
/* Should we move this directory to the orphanage? */
bool needs_adoption;
/* Directory entry name, plus the trailing null. */
struct xfs_name xname;
unsigned char namebuf[MAXNAMELEN];
......@@ -148,6 +158,10 @@ xrep_setup_directory(
xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS);
error = xrep_orphanage_try_create(sc);
if (error)
return error;
error = xrep_tempfile_create(sc, S_IFDIR);
if (error)
return error;
......@@ -1137,10 +1151,8 @@ xrep_dir_set_nlink(
/*
* The directory is not on the incore unlinked list, which means that
* it needs to be reachable via the directory tree. Update the nlink
* with our observed link count.
*
* XXX: A subsequent patch will handle parentless directories by moving
* them to the lost and found instead of aborting the repair.
* with our observed link count. If the directory has no parent, it
* will be moved to the orphanage.
*/
if (!xfs_inode_on_unlinked_list(dp))
goto reset_nlink;
......@@ -1151,6 +1163,7 @@ xrep_dir_set_nlink(
* inactivate when the last reference drops.
*/
if (rd->dirents == 0) {
rd->needs_adoption = false;
new_nlink = 0;
goto reset_nlink;
}
......@@ -1159,7 +1172,8 @@ xrep_dir_set_nlink(
* The directory is on the unlinked list and we found dirents. This
* directory needs to be reachable via the directory tree. Remove the
* dir from the unlinked list and update nlink with the observed link
* count.
* count. If the directory has no parent, it will be moved to the
* orphanage.
*/
pag = xfs_perag_get(sc->mp, XFS_INO_TO_AGNO(sc->mp, dp->i_ino));
if (!pag) {
......@@ -1195,12 +1209,16 @@ xrep_dir_swap(
return -EFSCORRUPTED;
/*
* If we never found the parent for this directory, we can't fix this
* directory.
* If we never found the parent for this directory, temporarily assign
* the root dir as the parent; we'll move this to the orphanage after
* exchanging the dir contents. We hold the ILOCK of the dir being
* repaired, so we're not worried about racy updates of dotdot.
*/
ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL);
if (rd->pscan.parent_ino == NULLFSINO)
return -EFSCORRUPTED;
if (rd->pscan.parent_ino == NULLFSINO) {
rd->needs_adoption = true;
rd->pscan.parent_ino = rd->sc->mp->m_sb.sb_rootino;
}
/*
* Reset the temporary directory's '..' entry to point to the parent
......@@ -1358,6 +1376,91 @@ xrep_dir_setup_scan(
return error;
}
/*
* Move the current file to the orphanage.
*
* Caller must hold IOLOCK_EXCL on @sc->ip, and no other inode locks. Upon
* successful return, the scrub transaction will have enough extra reservation
* to make the move; it will hold IOLOCK_EXCL and ILOCK_EXCL of @sc->ip and the
* orphanage; and both inodes will be ijoined.
*/
STATIC int
xrep_dir_move_to_orphanage(
struct xrep_dir *rd)
{
struct xfs_scrub *sc = rd->sc;
xfs_ino_t orig_parent, new_parent;
int error;
/*
* We are about to drop the ILOCK on sc->ip to lock the orphanage and
* prepare for the adoption. Therefore, look up the old dotdot entry
* for sc->ip so that we can compare it after we re-lock sc->ip.
*/
error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &orig_parent);
if (error)
return error;
/*
* Drop the ILOCK on the scrub target and commit the transaction.
* Adoption computes its own resource requirements and gathers the
* necessary components.
*/
error = xrep_trans_commit(sc);
if (error)
return error;
xchk_iunlock(sc, XFS_ILOCK_EXCL);
/* If we can take the orphanage's iolock then we're ready to move. */
if (!xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) {
xchk_iunlock(sc, sc->ilock_flags);
error = xrep_orphanage_iolock_two(sc);
if (error)
return error;
}
/* Grab transaction and ILOCK the two files. */
error = xrep_adoption_trans_alloc(sc, &rd->adoption);
if (error)
return error;
error = xrep_adoption_compute_name(&rd->adoption, &rd->xname);
if (error)
return error;
/*
* Now that we've reacquired the ILOCK on sc->ip, look up the dotdot
* entry again. If the parent changed or the child was unlinked while
* the child directory was unlocked, we don't need to move the child to
* the orphanage after all.
*/
error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &new_parent);
if (error)
return error;
/*
* Attach to the orphanage if we still have a linked directory and it
* hasn't been moved.
*/
if (orig_parent == new_parent && VFS_I(sc->ip)->i_nlink > 0) {
error = xrep_adoption_move(&rd->adoption);
if (error)
return error;
}
/*
* Launder the scrub transaction so we can drop the orphanage ILOCK
* and IOLOCK. Return holding the scrub target's ILOCK and IOLOCK.
*/
error = xrep_adoption_trans_roll(&rd->adoption);
if (error)
return error;
xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
return 0;
}
/*
* Repair the directory metadata.
*
......@@ -1396,6 +1499,15 @@ xrep_directory(
if (error)
goto out_teardown;
if (rd->needs_adoption) {
if (!xrep_orphanage_can_adopt(rd->sc))
error = -EFSCORRUPTED;
else
error = xrep_dir_move_to_orphanage(rd);
if (error)
goto out_teardown;
}
out_teardown:
xrep_dir_teardown(sc);
return error;
......
......@@ -24,6 +24,7 @@
#include "scrub/xfile.h"
#include "scrub/xfarray.h"
#include "scrub/iscan.h"
#include "scrub/orphanage.h"
#include "scrub/nlinks.h"
#include "scrub/trace.h"
#include "scrub/readdir.h"
......@@ -44,11 +45,23 @@ int
xchk_setup_nlinks(
struct xfs_scrub *sc)
{
struct xchk_nlink_ctrs *xnc;
int error;
xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS);
sc->buf = kzalloc(sizeof(struct xchk_nlink_ctrs), XCHK_GFP_FLAGS);
if (!sc->buf)
if (xchk_could_repair(sc)) {
error = xrep_setup_nlinks(sc);
if (error)
return error;
}
xnc = kvzalloc(sizeof(struct xchk_nlink_ctrs), XCHK_GFP_FLAGS);
if (!xnc)
return -ENOMEM;
xnc->xname.name = xnc->namebuf;
xnc->sc = sc;
sc->buf = xnc;
return xchk_setup_fs(sc);
}
......@@ -873,9 +886,6 @@ xchk_nlinks_setup_scan(
xfs_agino_t first_agino, last_agino;
int error;
ASSERT(xnc->sc == NULL);
xnc->sc = sc;
mutex_init(&xnc->lock);
/* Retry iget every tenth of a second for up to 30 seconds. */
......
......@@ -28,6 +28,13 @@ struct xchk_nlink_ctrs {
* from other writer threads.
*/
struct xfs_dir_hook dhook;
/* Orphanage reparenting request. */
struct xrep_adoption adoption;
/* Directory entry name, plus the trailing null. */
struct xfs_name xname;
char namebuf[MAXNAMELEN];
};
/*
......
......@@ -24,6 +24,7 @@
#include "scrub/xfile.h"
#include "scrub/xfarray.h"
#include "scrub/iscan.h"
#include "scrub/orphanage.h"
#include "scrub/nlinks.h"
#include "scrub/trace.h"
#include "scrub/tempfile.h"
......@@ -38,6 +39,34 @@
* inode is locked.
*/
/* Set up to repair inode link counts. */
int
xrep_setup_nlinks(
struct xfs_scrub *sc)
{
return xrep_orphanage_try_create(sc);
}
/*
* Inodes that aren't the root directory or the orphanage, have a nonzero link
* count, and no observed parents should be moved to the orphanage.
*/
static inline bool
xrep_nlinks_is_orphaned(
struct xfs_scrub *sc,
struct xfs_inode *ip,
unsigned int actual_nlink,
const struct xchk_nlink *obs)
{
struct xfs_mount *mp = ip->i_mount;
if (obs->parents != 0)
return false;
if (ip == mp->m_rootip || ip == sc->orphanage)
return false;
return actual_nlink != 0;
}
/* Remove an inode from the unlinked list. */
STATIC int
xrep_nlinks_iunlink_remove(
......@@ -66,6 +95,7 @@ xrep_nlinks_repair_inode(
struct xfs_inode *ip = sc->ip;
uint64_t total_links;
uint64_t actual_nlink;
bool orphanage_available = false;
bool dirty = false;
int error;
......@@ -77,14 +107,41 @@ xrep_nlinks_repair_inode(
if (xrep_is_tempfile(ip))
return 0;
/*
* If the filesystem has an orphanage attached to the scrub context,
* prepare for a link count repair that could involve @ip being adopted
* by the lost+found.
*/
if (xrep_orphanage_can_adopt(sc)) {
error = xrep_orphanage_iolock_two(sc);
if (error)
return error;
error = xrep_adoption_trans_alloc(sc, &xnc->adoption);
if (error) {
xchk_iunlock(sc, XFS_IOLOCK_EXCL);
xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
} else {
orphanage_available = true;
}
}
/*
* Either there is no orphanage or we couldn't allocate resources for
* that kind of update. Let's try again with only the resources we
* need for a simple link count update, since that's much more common.
*/
if (!orphanage_available) {
xchk_ilock(sc, XFS_IOLOCK_EXCL);
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0, &sc->tp);
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0,
&sc->tp);
if (error)
return error;
xchk_ilock(sc, XFS_ILOCK_EXCL);
xfs_trans_ijoin(sc->tp, ip, 0);
}
mutex_lock(&xnc->lock);
......@@ -122,6 +179,41 @@ xrep_nlinks_repair_inode(
goto out_trans;
}
/*
* Decide if we're going to move this file to the orphanage, and fix
* up the incore link counts if we are.
*/
if (orphanage_available &&
xrep_nlinks_is_orphaned(sc, ip, actual_nlink, &obs)) {
/* Figure out what name we're going to use here. */
error = xrep_adoption_compute_name(&xnc->adoption, &xnc->xname);
if (error)
goto out_trans;
/*
* Reattach this file to the directory tree by moving it to
* the orphanage per the adoption parameters that we already
* computed.
*/
error = xrep_adoption_move(&xnc->adoption);
if (error)
goto out_trans;
/*
* Re-read the link counts since the reparenting will have
* updated our scan info.
*/
mutex_lock(&xnc->lock);
error = xfarray_load_sparse(xnc->nlinks, ip->i_ino, &obs);
mutex_unlock(&xnc->lock);
if (error)
goto out_trans;
total_links = xchk_nlink_total(ip, &obs);
actual_nlink = VFS_I(ip)->i_nlink;
dirty = true;
}
/*
* If this inode is linked from the directory tree and on the unlinked
* list, remove it from the unlinked list.
......@@ -165,14 +257,19 @@ xrep_nlinks_repair_inode(
xfs_trans_log_inode(sc->tp, ip, XFS_ILOG_CORE);
error = xrep_trans_commit(sc);
xchk_iunlock(sc, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
return error;
goto out_unlock;
out_scanlock:
mutex_unlock(&xnc->lock);
out_trans:
xchk_trans_cancel(sc);
xchk_iunlock(sc, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
out_unlock:
xchk_iunlock(sc, XFS_ILOCK_EXCL);
if (orphanage_available) {
xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
}
xchk_iunlock(sc, XFS_IOLOCK_EXCL);
return error;
}
......@@ -205,10 +302,10 @@ xrep_nlinks(
/*
* We need ftype for an accurate count of the number of child
* subdirectory links. Child subdirectories with a back link (dotdot
* entry) but no forward link are unfixable, so we cannot repair the
* link count of the parent directory based on the back link count
* alone. Filesystems without ftype support are rare (old V4) so we
* just skip out here.
* entry) but no forward link are moved to the orphanage, so we cannot
* repair the link count of the parent directory based on the back link
* count alone. Filesystems without ftype support are rare (old V4) so
* we just skip out here.
*/
if (!xfs_has_ftype(sc->mp))
return -EOPNOTSUPP;
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2021-2024 Oracle. All Rights Reserved.
* Author: Darrick J. Wong <djwong@kernel.org>
*/
#ifndef __XFS_SCRUB_ORPHANAGE_H__
#define __XFS_SCRUB_ORPHANAGE_H__
#ifdef CONFIG_XFS_ONLINE_REPAIR
int xrep_orphanage_create(struct xfs_scrub *sc);
/*
* If we're doing a repair, ensure that the orphanage exists and attach it to
* the scrub context.
*/
static inline int
xrep_orphanage_try_create(
struct xfs_scrub *sc)
{
int error;
ASSERT(sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR);
error = xrep_orphanage_create(sc);
switch (error) {
case 0:
case -ENOENT:
case -ENOTDIR:
case -ENOSPC:
/*
* If the orphanage can't be found or isn't a directory, we'll
* keep going, but we won't be able to attach the file to the
* orphanage if we can't find the parent.
*/
return 0;
}
return error;
}
int xrep_orphanage_iolock_two(struct xfs_scrub *sc);
void xrep_orphanage_ilock(struct xfs_scrub *sc, unsigned int ilock_flags);
bool xrep_orphanage_ilock_nowait(struct xfs_scrub *sc,
unsigned int ilock_flags);
void xrep_orphanage_iunlock(struct xfs_scrub *sc, unsigned int ilock_flags);
void xrep_orphanage_rele(struct xfs_scrub *sc);
/* Information about a request to add a file to the orphanage. */
struct xrep_adoption {
struct xfs_scrub *sc;
/* Name used for the adoption. */
struct xfs_name *xname;
/* Block reservations for orphanage and child (if directory). */
unsigned int orphanage_blkres;
unsigned int child_blkres;
};
bool xrep_orphanage_can_adopt(struct xfs_scrub *sc);
int xrep_adoption_trans_alloc(struct xfs_scrub *sc,
struct xrep_adoption *adopt);
int xrep_adoption_compute_name(struct xrep_adoption *adopt,
struct xfs_name *xname);
int xrep_adoption_move(struct xrep_adoption *adopt);
int xrep_adoption_trans_roll(struct xrep_adoption *adopt);
#else
struct xrep_adoption { /* empty */ };
# define xrep_orphanage_rele(sc) ((void)0)
#endif /* CONFIG_XFS_ONLINE_REPAIR */
#endif /* __XFS_SCRUB_ORPHANAGE_H__ */
......@@ -32,6 +32,8 @@
#include "scrub/iscan.h"
#include "scrub/findparent.h"
#include "scrub/readdir.h"
#include "scrub/tempfile.h"
#include "scrub/orphanage.h"
/*
* Repairing The Directory Parent Pointer
......@@ -57,6 +59,13 @@ struct xrep_parent {
* dotdot entry for this directory.
*/
struct xrep_parent_scan_info pscan;
/* Orphanage reparenting request. */
struct xrep_adoption adoption;
/* Directory entry name, plus the trailing null. */
struct xfs_name xname;
unsigned char namebuf[MAXNAMELEN];
};
/* Tear down all the incore stuff we created. */
......@@ -80,9 +89,10 @@ xrep_setup_parent(
if (!rp)
return -ENOMEM;
rp->sc = sc;
rp->xname.name = rp->namebuf;
sc->buf = rp;
return 0;
return xrep_orphanage_try_create(sc);
}
/*
......@@ -179,6 +189,91 @@ xrep_parent_reset_dotdot(
return xfs_trans_roll(&sc->tp);
}
/*
* Move the current file to the orphanage.
*
* Caller must hold IOLOCK_EXCL on @sc->ip, and no other inode locks. Upon
* successful return, the scrub transaction will have enough extra reservation
* to make the move; it will hold IOLOCK_EXCL and ILOCK_EXCL of @sc->ip and the
* orphanage; and both inodes will be ijoined.
*/
STATIC int
xrep_parent_move_to_orphanage(
struct xrep_parent *rp)
{
struct xfs_scrub *sc = rp->sc;
xfs_ino_t orig_parent, new_parent;
int error;
/*
* We are about to drop the ILOCK on sc->ip to lock the orphanage and
* prepare for the adoption. Therefore, look up the old dotdot entry
* for sc->ip so that we can compare it after we re-lock sc->ip.
*/
error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &orig_parent);
if (error)
return error;
/*
* Drop the ILOCK on the scrub target and commit the transaction.
* Adoption computes its own resource requirements and gathers the
* necessary components.
*/
error = xrep_trans_commit(sc);
if (error)
return error;
xchk_iunlock(sc, XFS_ILOCK_EXCL);
/* If we can take the orphanage's iolock then we're ready to move. */
if (!xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) {
xchk_iunlock(sc, sc->ilock_flags);
error = xrep_orphanage_iolock_two(sc);
if (error)
return error;
}
/* Grab transaction and ILOCK the two files. */
error = xrep_adoption_trans_alloc(sc, &rp->adoption);
if (error)
return error;
error = xrep_adoption_compute_name(&rp->adoption, &rp->xname);
if (error)
return error;
/*
* Now that we've reacquired the ILOCK on sc->ip, look up the dotdot
* entry again. If the parent changed or the child was unlinked while
* the child directory was unlocked, we don't need to move the child to
* the orphanage after all.
*/
error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &new_parent);
if (error)
return error;
/*
* Attach to the orphanage if we still have a linked directory and it
* hasn't been moved.
*/
if (orig_parent == new_parent && VFS_I(sc->ip)->i_nlink > 0) {
error = xrep_adoption_move(&rp->adoption);
if (error)
return error;
}
/*
* Launder the scrub transaction so we can drop the orphanage ILOCK
* and IOLOCK. Return holding the scrub target's ILOCK and IOLOCK.
*/
error = xrep_adoption_trans_roll(&rp->adoption);
if (error)
return error;
xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
return 0;
}
/*
* Commit the new parent pointer structure (currently only the dotdot entry) to
* the file that we're repairing.
......@@ -188,7 +283,8 @@ xrep_parent_rebuild_tree(
struct xrep_parent *rp)
{
if (rp->pscan.parent_ino == NULLFSINO) {
/* Cannot fix orphaned directories yet. */
if (xrep_orphanage_can_adopt(rp->sc))
return xrep_parent_move_to_orphanage(rp);
return -EFSCORRUPTED;
}
......
......@@ -93,6 +93,7 @@ int xrep_setup_ag_refcountbt(struct xfs_scrub *sc);
int xrep_setup_xattr(struct xfs_scrub *sc);
int xrep_setup_directory(struct xfs_scrub *sc);
int xrep_setup_parent(struct xfs_scrub *sc);
int xrep_setup_nlinks(struct xfs_scrub *sc);
/* Repair setup functions */
int xrep_setup_ag_allocbt(struct xfs_scrub *sc);
......@@ -201,6 +202,7 @@ xrep_setup_nothing(
#define xrep_setup_xattr xrep_setup_nothing
#define xrep_setup_directory xrep_setup_nothing
#define xrep_setup_parent xrep_setup_nothing
#define xrep_setup_nlinks xrep_setup_nothing
#define xrep_setup_inode(sc, imap) ((void)0)
......
......@@ -27,6 +27,7 @@
#include "scrub/stats.h"
#include "scrub/xfile.h"
#include "scrub/tempfile.h"
#include "scrub/orphanage.h"
/*
* Online Scrub and Repair
......@@ -217,6 +218,7 @@ xchk_teardown(
}
xrep_tempfile_rele(sc);
xrep_orphanage_rele(sc);
xchk_fsgates_disable(sc);
return error;
}
......
......@@ -105,6 +105,10 @@ struct xfs_scrub {
/* Lock flags for @ip. */
uint ilock_flags;
/* The orphanage, for stashing files that have lost their parent. */
uint orphanage_ilock_flags;
struct xfs_inode *orphanage;
/* A temporary file on this filesystem, for staging new metadata. */
struct xfs_inode *tempip;
uint temp_ilock_flags;
......
......@@ -24,6 +24,7 @@
#include "scrub/xfarray.h"
#include "scrub/quota.h"
#include "scrub/iscan.h"
#include "scrub/orphanage.h"
#include "scrub/nlinks.h"
#include "scrub/fscounters.h"
......
......@@ -2588,6 +2588,34 @@ DEFINE_EVENT(xrep_dirent_class, name, \
DEFINE_XREP_DIRENT_EVENT(xrep_dir_salvage_entry);
DEFINE_XREP_DIRENT_EVENT(xrep_dir_stash_createname);
DEFINE_XREP_DIRENT_EVENT(xrep_dir_replay_createname);
DEFINE_XREP_DIRENT_EVENT(xrep_adoption_reparent);
DECLARE_EVENT_CLASS(xrep_adoption_class,
TP_PROTO(struct xfs_inode *dp, struct xfs_inode *ip, bool moved),
TP_ARGS(dp, ip, moved),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, dir_ino)
__field(xfs_ino_t, child_ino)
__field(bool, moved)
),
TP_fast_assign(
__entry->dev = dp->i_mount->m_super->s_dev;
__entry->dir_ino = dp->i_ino;
__entry->child_ino = ip->i_ino;
__entry->moved = moved;
),
TP_printk("dev %d:%d dir 0x%llx child 0x%llx moved? %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->dir_ino,
__entry->child_ino,
__entry->moved)
);
#define DEFINE_XREP_ADOPTION_EVENT(name) \
DEFINE_EVENT(xrep_adoption_class, name, \
TP_PROTO(struct xfs_inode *dp, struct xfs_inode *ip, bool moved), \
TP_ARGS(dp, ip, moved))
DEFINE_XREP_ADOPTION_EVENT(xrep_adoption_trans_roll);
DECLARE_EVENT_CLASS(xrep_parent_salvage_class,
TP_PROTO(struct xfs_inode *dp, xfs_ino_t ino),
......@@ -2615,6 +2643,74 @@ DEFINE_XREP_PARENT_SALVAGE_EVENT(xrep_dir_salvaged_parent);
DEFINE_XREP_PARENT_SALVAGE_EVENT(xrep_findparent_dirent);
DEFINE_XREP_PARENT_SALVAGE_EVENT(xrep_findparent_from_dcache);
TRACE_EVENT(xrep_nlinks_set_record,
TP_PROTO(struct xfs_mount *mp, xfs_ino_t ino,
const struct xchk_nlink *obs),
TP_ARGS(mp, ino, obs),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(xfs_nlink_t, parents)
__field(xfs_nlink_t, backrefs)
__field(xfs_nlink_t, children)
),
TP_fast_assign(
__entry->dev = mp->m_super->s_dev;
__entry->ino = ino;
__entry->parents = obs->parents;
__entry->backrefs = obs->backrefs;
__entry->children = obs->children;
),
TP_printk("dev %d:%d ino 0x%llx parents %u backrefs %u children %u",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->parents,
__entry->backrefs,
__entry->children)
);
DECLARE_EVENT_CLASS(xrep_dentry_class,
TP_PROTO(struct xfs_mount *mp, const struct dentry *dentry),
TP_ARGS(mp, dentry),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(unsigned int, flags)
__field(unsigned long, ino)
__field(bool, positive)
__field(unsigned long, parent_ino)
__field(unsigned int, namelen)
__dynamic_array(char, name, dentry->d_name.len)
),
TP_fast_assign(
__entry->dev = mp->m_super->s_dev;
__entry->flags = dentry->d_flags;
__entry->positive = d_is_positive(dentry);
if (dentry->d_parent && d_inode(dentry->d_parent))
__entry->parent_ino = d_inode(dentry->d_parent)->i_ino;
else
__entry->parent_ino = -1UL;
__entry->ino = d_inode(dentry) ? d_inode(dentry)->i_ino : 0;
__entry->namelen = dentry->d_name.len;
memcpy(__get_str(name), dentry->d_name.name, dentry->d_name.len);
),
TP_printk("dev %d:%d flags 0x%x positive? %d parent_ino 0x%lx ino 0x%lx name '%.*s'",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->flags,
__entry->positive,
__entry->parent_ino,
__entry->ino,
__entry->namelen,
__get_str(name))
);
#define DEFINE_REPAIR_DENTRY_EVENT(name) \
DEFINE_EVENT(xrep_dentry_class, name, \
TP_PROTO(struct xfs_mount *mp, const struct dentry *dentry), \
TP_ARGS(mp, dentry))
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_child);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_alias);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_check_dentry);
DEFINE_REPAIR_DENTRY_EVENT(xrep_adoption_invalidate_child);
#endif /* IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR) */
#endif /* _TRACE_XFS_SCRUB_TRACE_H */
......
......@@ -914,10 +914,10 @@ xfs_droplink(
/*
* Increment the link count on an inode & log the change.
*/
static void
void
xfs_bumplink(
xfs_trans_t *tp,
xfs_inode_t *ip)
struct xfs_trans *tp,
struct xfs_inode *ip)
{
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
......
......@@ -625,6 +625,7 @@ void xfs_end_io(struct work_struct *work);
int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
void xfs_iunlock2_remapping(struct xfs_inode *ip1, struct xfs_inode *ip2);
void xfs_bumplink(struct xfs_trans *tp, struct xfs_inode *ip);
static inline bool
xfs_inode_unlinked_incomplete(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment