btrfs-progs: check/original: detect directory inode with nlinks >= 2

Linux VFS doesn't allow directory to have hard links, thus for btrfs
on-disk directory inode items, their nlinks should never go beyond 1.

Lowmem mode already has the check and will report it without problem.
Only original mode needs this update.

Reported-by: Pepperpoint <pepperpoint@mb.ardentcoding.com>
Link: https://lore.kernel.org/linux-btrfs/162648632340.7.1932907459648384384.10178178@mb.ardentcoding.com/
Reviewed-by: Su Yue <l@damenly.su>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2021-07-18 20:54:48 +08:00 committed by David Sterba
parent e9c2942f38
commit 478e98cd01
2 changed files with 8 additions and 0 deletions

View File

@ -623,6 +623,9 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
rec->imode & ~07777); rec->imode & ~07777);
if (errors & I_ERR_INVALID_GEN) if (errors & I_ERR_INVALID_GEN)
fprintf(stderr, ", invalid inode generation or transid"); fprintf(stderr, ", invalid inode generation or transid");
if (errors & I_ERR_INVALID_NLINK)
fprintf(stderr, ", directory has invalid nlink %d",
rec->nlink);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
/* Print the holes if needed */ /* Print the holes if needed */
@ -909,6 +912,10 @@ static int process_inode_item(struct extent_buffer *eb,
if (S_ISLNK(rec->imode) && if (S_ISLNK(rec->imode) &&
flags & (BTRFS_INODE_IMMUTABLE | BTRFS_INODE_APPEND)) flags & (BTRFS_INODE_IMMUTABLE | BTRFS_INODE_APPEND))
rec->errors |= I_ERR_ODD_INODE_FLAGS; rec->errors |= I_ERR_ODD_INODE_FLAGS;
/* Directory should never have hard link */
if (S_ISDIR(rec->imode) && rec->nlink >= 2)
rec->errors |= I_ERR_INVALID_NLINK;
/* /*
* We don't have accurate root info to determine the correct * We don't have accurate root info to determine the correct
* inode generation uplimit, use super_generation + 1 anyway * inode generation uplimit, use super_generation + 1 anyway

View File

@ -186,6 +186,7 @@ struct unaligned_extent_rec_t {
#define I_ERR_MISMATCH_DIR_HASH (1 << 18) #define I_ERR_MISMATCH_DIR_HASH (1 << 18)
#define I_ERR_INVALID_IMODE (1 << 19) #define I_ERR_INVALID_IMODE (1 << 19)
#define I_ERR_INVALID_GEN (1 << 20) #define I_ERR_INVALID_GEN (1 << 20)
#define I_ERR_INVALID_NLINK (1 << 21)
struct inode_record { struct inode_record {
struct list_head backrefs; struct list_head backrefs;