@@ -2392,6 +2392,7 @@ process_dinode_int(
struct xfs_dinode *dino = *dinop;
xfs_agino_t unlinked_ino;
struct xfs_perag *pag;
+ bool is_meta = false;
*dirty = *isa_dir = 0;
*used = is_used;
@@ -2971,6 +2972,18 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "),
if (collect_rmaps)
record_inode_reflink_flag(mp, dino, agno, ino, lino);
+ /* Does this inode think it was metadata? */
+ if (dino->di_version >= 3 &&
+ (dino->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADATA))) {
+ struct ino_tree_node *irec;
+ int off;
+
+ irec = find_inode_rec(mp, agno, ino);
+ off = get_inode_offset(mp, lino, irec);
+ set_inode_is_meta(irec, off);
+ is_meta = true;
+ }
+
/*
* check data fork -- if it's bad, clear the inode
*/
@@ -3057,6 +3070,14 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "),
*used = is_free;
*isa_dir = 0;
blkmap_free(dblkmap);
+ if (is_meta) {
+ struct ino_tree_node *irec;
+ int off;
+
+ irec = find_inode_rec(mp, agno, ino);
+ off = get_inode_offset(mp, lino, irec);
+ clear_inode_is_meta(irec, off);
+ }
return 1;
}
@@ -271,6 +271,7 @@ typedef struct ino_tree_node {
uint64_t ino_isa_dir; /* bit == 1 if a directory */
uint64_t ino_was_rl; /* bit == 1 if reflink flag set */
uint64_t ino_is_rl; /* bit == 1 if reflink flag should be set */
+ uint64_t ino_is_meta; /* bit == 1 if metadata */
uint8_t nlink_size;
union ino_nlink disk_nlinks; /* on-disk nlinks, set in P3 */
union {
@@ -538,6 +539,24 @@ static inline int inode_is_rl(struct ino_tree_node *irec, int offset)
return (irec->ino_is_rl & IREC_MASK(offset)) != 0;
}
+/*
+ * set/clear/test was inode marked as metadata
+ */
+static inline void set_inode_is_meta(struct ino_tree_node *irec, int offset)
+{
+ irec->ino_is_meta |= IREC_MASK(offset);
+}
+
+static inline void clear_inode_is_meta(struct ino_tree_node *irec, int offset)
+{
+ irec->ino_is_meta &= ~IREC_MASK(offset);
+}
+
+static inline int inode_is_meta(struct ino_tree_node *irec, int offset)
+{
+ return (irec->ino_is_meta & IREC_MASK(offset)) != 0;
+}
+
/*
* add_inode_reached() is set on inode I only if I has been reached
* by an inode P claiming to be the parent and if I is a directory,
@@ -257,6 +257,7 @@ alloc_ino_node(
irec->ino_isa_dir = 0;
irec->ino_was_rl = 0;
irec->ino_is_rl = 0;
+ irec->ino_is_meta = 0;
irec->ir_free = (xfs_inofree_t) - 1;
irec->ir_sparse = 0;
irec->ino_un.ex_data = NULL;
@@ -557,8 +557,10 @@ phase2(
*/
ino_rec = set_inode_used_alloc(mp, 0,
XFS_INO_TO_AGINO(mp, sb->sb_rootino));
- for (j = 1; j < inuse; j++)
+ for (j = 1; j < inuse; j++) {
set_inode_used(ino_rec, j);
+ set_inode_is_meta(ino_rec, j);
+ }
for (j = inuse; j < XFS_INODES_PER_CHUNK; j++)
set_inode_free(ino_rec, j);
@@ -594,6 +596,7 @@ phase2(
else
do_warn(_("would correct\n"));
}
+ set_inode_is_meta(ino_rec, j);
j++;
}
@@ -605,6 +608,7 @@ phase2(
else
do_warn(_("would correct\n"));
}
+ set_inode_is_meta(ino_rec, j);
j++;
if (is_inode_free(ino_rec, j)) {
@@ -615,6 +619,7 @@ phase2(
else
do_warn(_("would correct\n"));
}
+ set_inode_is_meta(ino_rec, j);
j++;
}
@@ -1610,6 +1610,38 @@ longform_dir2_entry_check_data(
continue;
}
+ /*
+ * Regular directories cannot point to metadata files. If
+ * we find such a thing, blow out the entry.
+ */
+ if (!xfs_is_metadir_inode(ip) &&
+ inode_is_meta(irec, ino_offset)) {
+ nbad++;
+ if (entry_junked(
+ _("entry \"%s\" in regular dir %" PRIu64" points to a metadata inode %" PRIu64 ", "),
+ fname, ip->i_ino, inum, NULLFSINO)) {
+ dep->name[0] = '/';
+ libxfs_dir2_data_log_entry(&da, bp, dep);
+ }
+ continue;
+ }
+
+ /*
+ * Metadata directories cannot point to regular files. If
+ * we find such a thing, blow out the entry.
+ */
+ if (xfs_is_metadir_inode(ip) &&
+ !inode_is_meta(irec, ino_offset)) {
+ nbad++;
+ if (entry_junked(
+ _("entry \"%s\" in metadata dir %" PRIu64" points to a regular inode %" PRIu64 ", "),
+ fname, ip->i_ino, inum, NULLFSINO)) {
+ dep->name[0] = '/';
+ libxfs_dir2_data_log_entry(&da, bp, dep);
+ }
+ continue;
+ }
+
/*
* check if this inode is lost+found dir in the root
*/
@@ -2521,6 +2553,37 @@ shortform_dir2_entry_check(
ino_dirty);
continue;
}
+
+ /*
+ * Regular directories cannot point to metadata files. If
+ * we find such a thing, blow out the entry.
+ */
+ if (!xfs_is_metadir_inode(ip) &&
+ inode_is_meta(irec, ino_offset)) {
+ do_warn(
+ _("entry \"%s\" in regular dir %" PRIu64" points to a metadata inode %" PRIu64 ", "),
+ fname, ip->i_ino, lino);
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
+ &max_size, &i, &bytes_deleted,
+ ino_dirty);
+ continue;
+ }
+
+ /*
+ * Metadata directories cannot point to regular files. If
+ * we find such a thing, blow out the entry.
+ */
+ if (xfs_is_metadir_inode(ip) &&
+ !inode_is_meta(irec, ino_offset)) {
+ do_warn(
+ _("entry \"%s\" in metadata dir %" PRIu64" points to a regular inode %" PRIu64 ", "),
+ fname, ip->i_ino, lino);
+ next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
+ &max_size, &i, &bytes_deleted,
+ ino_dirty);
+ continue;
+ }
+
/*
* check if this inode is lost+found dir in the root
*/