]> www.infradead.org Git - users/hch/misc.git/commitdiff
xfs: hide metadata inodes from everyone because they are special
authorDarrick J. Wong <djwong@kernel.org>
Wed, 29 May 2024 04:11:00 +0000 (21:11 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 24 Jul 2024 05:33:29 +0000 (22:33 -0700)
Metadata inodes are private files and therefore cannot be exposed to
userspace.  This means no bulkstat, no open-by-handle, no linking them
into the directory tree, and no feeding them to LSMs.  As such, we mark
them S_PRIVATE, which stops all that.

While we're at it, put them in a separate lockdep class so that it won't
get confused by "recursive" i_rwsem locking such as what happens when we
write to a rt file and need to allocate from the rt bitmap file.  The
static function that we use to do this will be exported in the rtgroups
patchset.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/scrub/tempfile.c
fs/xfs/xfs_iops.c

index 177f922acfaf1bd443728528d39aaa6da80a632d..6b5b49f4e7a640e225848316c8d73975b60447d6 100644 (file)
@@ -844,6 +844,14 @@ xrep_is_tempfile(
        const struct xfs_inode  *ip)
 {
        const struct inode      *inode = &ip->i_vnode;
+       struct xfs_mount        *mp = ip->i_mount;
+
+       /*
+        * Files in the metadata directory tree also have S_PRIVATE set and
+        * IOP_XATTR unset, so we must distinguish them separately.
+        */
+       if (xfs_has_metadir(mp) && (ip->i_diflags2 & XFS_DIFLAG2_METADIR))
+               return false;
 
        if (IS_PRIVATE(inode) && !(inode->i_opflags & IOP_XATTR))
                return true;
index 07f736c42460b1674b471d8d4f6d8a1c7c959b38..9c8c23beec61d8f919fd066b84a6d8c44f8d79c9 100644 (file)
@@ -1272,6 +1272,35 @@ xfs_diflags_to_iflags(
        inode->i_flags |= flags;
 }
 
+static void
+xfs_setup_metadata_inode_lock_class(
+       struct xfs_inode        *ip)
+{
+       struct inode            *inode = &ip->i_vnode;
+       /*
+        * Metadata directories and files are not exposed to userspace, which
+        * means that they never access any of the VFS IO locks and never
+        * experience page faults.  Give them separate locking classes so that
+        * lockdep will not complain about conflicts that cannot happen.
+        */
+       static struct lock_class_key xfs_metadata_file_ilock_class;
+       static struct lock_class_key xfs_metadata_dir_ilock_class;
+
+       if (S_ISDIR(inode->i_mode)) {
+               /*
+                * We set the i_rwsem class here to avoid potential races with
+                * lockdep_annotate_inode_mutex_key() reinitialising the lock
+                * after a filehandle lookup has already found the inode in
+                * cache before it has been unlocked via unlock_new_inode().
+                */
+               lockdep_set_class(&inode->i_rwsem,
+                                 &inode->i_sb->s_type->i_mutex_dir_key);
+               lockdep_set_class(&ip->i_lock, &xfs_metadata_dir_ilock_class);
+       } else {
+               lockdep_set_class(&ip->i_lock, &xfs_metadata_file_ilock_class);
+       }
+}
+
 /*
  * Initialize the Linux inode.
  *
@@ -1286,6 +1315,7 @@ xfs_setup_inode(
 {
        struct inode            *inode = &ip->i_vnode;
        gfp_t                   gfp_mask;
+       bool                    is_meta = xfs_is_metadata_inode(ip);
 
        inode->i_ino = ip->i_ino;
        inode->i_state |= I_NEW;
@@ -1297,7 +1327,19 @@ xfs_setup_inode(
        i_size_write(inode, ip->i_disk_size);
        xfs_diflags_to_iflags(ip, true);
 
-       if (S_ISDIR(inode->i_mode)) {
+       /*
+        * Mark our metadata files as private so that LSMs and the ACL code
+        * don't try to add their own metadata or reason about these files,
+        * and users cannot ever obtain file handles to them.
+        */
+       if (is_meta) {
+               inode->i_flags |= S_PRIVATE;
+               inode->i_opflags &= ~IOP_XATTR;
+       }
+
+       if (is_meta) {
+               xfs_setup_metadata_inode_lock_class(ip);
+       } else if (S_ISDIR(inode->i_mode)) {
                /*
                 * We set the i_rwsem class here to avoid potential races with
                 * lockdep_annotate_inode_mutex_key() reinitialising the lock