2024-02-22 20:30:58 +00:00
|
|
|
/* 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_NLINKS_H__
|
|
|
|
#define __XFS_SCRUB_NLINKS_H__
|
|
|
|
|
|
|
|
/* Live link count control structure. */
|
|
|
|
struct xchk_nlink_ctrs {
|
|
|
|
struct xfs_scrub *sc;
|
|
|
|
|
|
|
|
/* Shadow link count data and its mutex. */
|
|
|
|
struct xfarray *nlinks;
|
|
|
|
struct mutex lock;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The collection step uses a separate iscan context from the compare
|
|
|
|
* step because the collection iscan coordinates live updates to the
|
|
|
|
* observation data while this scanner is running. The compare iscan
|
|
|
|
* is secondary and can be reinitialized as needed.
|
|
|
|
*/
|
|
|
|
struct xchk_iscan collect_iscan;
|
|
|
|
struct xchk_iscan compare_iscan;
|
2024-02-22 20:30:59 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Hook into directory updates so that we can receive live updates
|
|
|
|
* from other writer threads.
|
|
|
|
*/
|
|
|
|
struct xfs_dir_hook dhook;
|
2024-04-15 21:54:56 +00:00
|
|
|
|
|
|
|
/* Orphanage reparenting request. */
|
|
|
|
struct xrep_adoption adoption;
|
|
|
|
|
|
|
|
/* Directory entry name, plus the trailing null. */
|
|
|
|
struct xfs_name xname;
|
|
|
|
char namebuf[MAXNAMELEN];
|
2024-02-22 20:30:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In-core link counts for a given inode in the filesystem.
|
|
|
|
*
|
|
|
|
* For an empty rootdir, the directory entries and the field to which they are
|
|
|
|
* accounted are as follows:
|
|
|
|
*
|
|
|
|
* Root directory:
|
|
|
|
*
|
|
|
|
* . points to self (root.child)
|
|
|
|
* .. points to self (root.parent)
|
|
|
|
* f1 points to a child file (f1.parent)
|
|
|
|
* d1 points to a child dir (d1.parent, root.child)
|
|
|
|
*
|
|
|
|
* Subdirectory d1:
|
|
|
|
*
|
|
|
|
* . points to self (d1.child)
|
|
|
|
* .. points to root dir (root.backref)
|
|
|
|
* f2 points to child file (f2.parent)
|
|
|
|
* f3 points to root.f1 (f1.parent)
|
|
|
|
*
|
|
|
|
* root.nlink == 3 (root.dot, root.dotdot, root.d1)
|
|
|
|
* d1.nlink == 2 (root.d1, d1.dot)
|
|
|
|
* f1.nlink == 2 (root.f1, d1.f3)
|
|
|
|
* f2.nlink == 1 (d1.f2)
|
|
|
|
*/
|
|
|
|
struct xchk_nlink {
|
|
|
|
/* Count of forward links from parent directories to this file. */
|
|
|
|
xfs_nlink_t parents;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Count of back links to this parent directory from child
|
|
|
|
* subdirectories.
|
|
|
|
*/
|
|
|
|
xfs_nlink_t backrefs;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Count of forward links from this directory to all child files and
|
|
|
|
* the number of dot entries. Should be zero for non-directories.
|
|
|
|
*/
|
|
|
|
xfs_nlink_t children;
|
|
|
|
|
|
|
|
/* Record state flags */
|
|
|
|
unsigned int flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This incore link count has been written at least once. We never want to
|
|
|
|
* store an xchk_nlink that looks uninitialized.
|
|
|
|
*/
|
|
|
|
#define XCHK_NLINK_WRITTEN (1U << 0)
|
|
|
|
|
2024-02-22 20:31:00 +00:00
|
|
|
/* Already checked this link count record. */
|
2024-02-22 20:30:58 +00:00
|
|
|
#define XCHK_NLINK_COMPARE_SCANNED (1U << 1)
|
|
|
|
|
2024-02-22 20:31:00 +00:00
|
|
|
/* Already made a repair with this link count record. */
|
|
|
|
#define XREP_NLINK_DIRTY (1U << 2)
|
|
|
|
|
2024-02-22 20:30:58 +00:00
|
|
|
/* Compute total link count, using large enough variables to detect overflow. */
|
|
|
|
static inline uint64_t
|
|
|
|
xchk_nlink_total(struct xfs_inode *ip, const struct xchk_nlink *live)
|
|
|
|
{
|
|
|
|
uint64_t ret = live->parents;
|
|
|
|
|
|
|
|
/* Add one link count for the dot entry of any linked directory. */
|
|
|
|
if (ip && S_ISDIR(VFS_I(ip)->i_mode) && VFS_I(ip)->i_nlink)
|
|
|
|
ret++;
|
|
|
|
return ret + live->children;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* __XFS_SCRUB_NLINKS_H__ */
|