From 099aa9afcae194928de23871fa8f6cdeeb37812f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 16 Jul 2024 16:16:52 +0200 Subject: [PATCH] xfs: don't create one lockdep class per RTG lockdep_unregister_key is rather expensive because it does a synchronize_rcu. To avoid slowdowns with lots of RTGs try to avoid using it. Signed-off-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_rtgroup.c | 52 ++++++++++++++++++++++++++++++------- fs/xfs/libxfs/xfs_rtgroup.h | 2 -- fs/xfs/xfs_inode.h | 4 ++- fs/xfs/xfs_iops.c | 2 +- fs/xfs/xfs_iops.h | 2 -- fs/xfs/xfs_rtalloc.c | 13 ++-------- 6 files changed, 48 insertions(+), 27 deletions(-) diff --git a/fs/xfs/libxfs/xfs_rtgroup.c b/fs/xfs/libxfs/xfs_rtgroup.c index e48f8ffd18a5..fababe13a8c7 100644 --- a/fs/xfs/libxfs/xfs_rtgroup.c +++ b/fs/xfs/libxfs/xfs_rtgroup.c @@ -166,8 +166,6 @@ xfs_initialize_rtgroups( /* Place kernel structure only init below this point. */ spin_lock_init(&rtg->rtg_state_lock); init_waitqueue_head(&rtg->rtg_active_wq); - memset(&rtg->lock_class, 0, sizeof(rtg->lock_class)); - lockdep_register_key(&rtg->lock_class); xfs_defer_drain_init(&rtg->rtg_intents_drain); xfs_hooks_init(&rtg->rtg_rmap_update_hooks); #endif /* __KERNEL__ */ @@ -210,7 +208,6 @@ xfs_free_unused_rtgroup_range( if (!rtg) break; #ifdef __KERNEL__ - lockdep_unregister_key(&rtg->lock_class); xfs_defer_drain_free(&rtg->rtg_intents_drain); #endif kfree(rtg); @@ -247,7 +244,6 @@ xfs_free_rtgroups( ASSERT(rtg); XFS_IS_CORRUPT(mp, atomic_read(&rtg->rtg_ref) != 0); #ifdef __KERNEL__ - lockdep_unregister_key(&rtg->lock_class); xfs_defer_drain_free(&rtg->rtg_intents_drain); #endif @@ -525,6 +521,46 @@ static const struct xfs_rtginode_ops xfs_rtginode_ops[] = { }, }; +#ifdef CONFIG_PROVE_LOCKING +static struct lock_class_key xfs_rtg_lock_class; + +static int +xfs_rtg_ilock_cmp_fn( + const struct lockdep_map *m1, + const struct lockdep_map *m2) +{ + const struct xfs_inode *ip1 = + container_of(m1, struct xfs_inode, i_lock.dep_map); + const struct xfs_inode *ip2 = + container_of(m2, struct xfs_inode, i_lock.dep_map); + + if (ip1->i_rgno < ip2->i_rgno) + return -1; + if (ip1->i_rgno > ip2->i_rgno) + return 1; + return 0; +} + +/* + * Most of the time each of the RTG inode locks is only taken one at a time. + * But when committing deferred ops more than one of a kind can be taken. + * As the RTG will be committed in rgno order there is not potential for + * deadlocks, and the code here is needed to tell lockdep about this order. + */ +static inline void +xfs_rtg_ilock_lockdep_setup( + struct xfs_inode *ip, + xfs_rgnumber_t rgno, + enum xfs_rtg_inodes type) +{ + ip->i_rgno = rgno; + lockdep_set_class_and_subclass(&ip->i_lock, &xfs_rtg_lock_class, type); + lock_set_cmp_fn(&ip->i_lock, xfs_rtg_ilock_cmp_fn, NULL); +} +#else +#define xfs_rtg_ilock_lockdep_setup(ip, rgno, type) do { } while (0) +#endif /* CONFIG_PROVE_LOCKING */ + const char * xfs_rtginode_name( enum xfs_rtg_inodes type) @@ -576,11 +612,7 @@ xfs_rtginode_load( return -EFSCORRUPTED; } - /* - * Each realtime allocation group has a lockdep class key for the metadata - * inodes. Each metadata inode in a group gets its own subclass. - */ - lockdep_set_class_and_subclass(&ip->i_lock, &rtg->lock_class, type); + xfs_rtg_ilock_lockdep_setup(ip, rtg->rtg_rgno, type); rtg->rtg_inodes[type] = ip; return 0; } @@ -613,7 +645,7 @@ xfs_rtginode_create( if (error) return error; - lockdep_set_class_and_subclass(&upd.ip->i_lock, &rtg->lock_class, type); + xfs_rtg_ilock_lockdep_setup(upd.ip, rtg->rtg_rgno, type); error = ops->create(rtg, upd.ip, upd.tp, init); if (error) diff --git a/fs/xfs/libxfs/xfs_rtgroup.h b/fs/xfs/libxfs/xfs_rtgroup.h index e8d76a818e07..ab44b9ccf1d8 100644 --- a/fs/xfs/libxfs/xfs_rtgroup.h +++ b/fs/xfs/libxfs/xfs_rtgroup.h @@ -50,8 +50,6 @@ struct xfs_rtgroup { /* -- kernel only structures below this line -- */ spinlock_t rtg_state_lock; - struct lock_class_key lock_class; - /* * We use xfs_drain to track the number of deferred log intent items * that have been queued (but not yet processed) so that waiters (e.g. diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 67073dc7b712..655f99f4ff7c 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -57,7 +57,9 @@ typedef struct xfs_inode { uint64_t i_delayed_blks; /* count of delay alloc blks */ /* Space that has been set aside to root a btree in this file. */ uint64_t i_meta_resv_asked; - +#ifdef CONFIG_PROVE_LOCKING + xfs_rgnumber_t i_rgno; +#endif xfs_fsize_t i_disk_size; /* number of bytes in file */ xfs_rfsblock_t i_nblocks; /* # of direct & btree blocks */ prid_t i_projid; /* owner's project id */ diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index b1e8b1eb75b6..9c8c23beec61 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -1272,7 +1272,7 @@ xfs_diflags_to_iflags( inode->i_flags |= flags; } -void +static void xfs_setup_metadata_inode_lock_class( struct xfs_inode *ip) { diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h index 132511234761..3c1a2605ffd2 100644 --- a/fs/xfs/xfs_iops.h +++ b/fs/xfs/xfs_iops.h @@ -20,6 +20,4 @@ extern void xfs_setup_inode(struct xfs_inode *ip); extern void xfs_setup_iops(struct xfs_inode *ip); extern void xfs_diflags_to_iflags(struct xfs_inode *ip, bool init); -void xfs_setup_metadata_inode_lock_class(struct xfs_inode *ip); - #endif /* __XFS_IOPS_H__ */ diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 628e632a5266..92adc7df47e5 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -944,17 +944,8 @@ static inline void xfs_rtgroup_irele( struct xfs_inode **ipp) { - struct xfs_inode *ip = *ipp; - - if (!ip) - return; - - /* - * Detach from the rtgroup's dynamic lockdep class key before we lose - * access to the inode entirely. - */ - xfs_setup_metadata_inode_lock_class(ip); - xfs_irele(ip); + if (*ipp) + xfs_irele(*ipp); *ipp = NULL; } -- 2.51.0