summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2020-10-25 17:16:06 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2020-10-26 18:32:31 -0700
commitbfe6ffd16865f1c5bfef696447ea691f656d1b02 (patch)
tree57aa8744ca4b4969fbcbc97a8c8014a1793f8038
parent0e99beb79524ac10087f53169490a010a648f9eb (diff)
xfs: put metadata inodes in a separate lockdep class
Metadata inodes are not supposed to be exposed to userspace, which eliminates most conflicts with vfs rwseasm, page cache locks, etc. This means that we actually /can/ do things like copy data to userspace while holding a metadata inode's ILOCK, since, uh.... well what happens if we copy rt fsmap data to an rt file, which then causes an rt allocation and therfore needs the rtrmap ilock...? Confused-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/xfs_iops.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 793ff08a9933..6289b3f3268c 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -41,6 +41,15 @@
static struct lock_class_key xfs_nondir_ilock_class;
static struct lock_class_key xfs_dir_ilock_class;
+/*
+ * 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;
+
static int
xfs_initxattrs(
struct inode *inode,
@@ -1330,6 +1339,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;
@@ -1350,9 +1360,19 @@ xfs_setup_inode(
*/
lockdep_set_class(&inode->i_rwsem,
&inode->i_sb->s_type->i_mutex_dir_key);
- lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class);
+ if (is_meta)
+ lockdep_set_class(&ip->i_lock.mr_lock,
+ &xfs_metadata_dir_ilock_class);
+ else
+ lockdep_set_class(&ip->i_lock.mr_lock,
+ &xfs_dir_ilock_class);
} else {
- lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class);
+ if (is_meta)
+ lockdep_set_class(&ip->i_lock.mr_lock,
+ &xfs_metadata_file_ilock_class);
+ else
+ lockdep_set_class(&ip->i_lock.mr_lock,
+ &xfs_nondir_ilock_class);
}
/*