mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 08:15:07 -04:00
ocfs2: cluster: avoid lock order inversion in o2hb_region_pin() from drop_item
o2hb_heartbeat_group_drop_item() is called from configfs rmdir with the
parent directory's inode_lock held. It calls o2hb_region_pin() ->
o2nm_depend_item() -> configfs_depend_item(), which acquires the configfs
root inode_lock. This creates a parent -> root inode_lock nesting that
could deadlock against paths taking root -> parent (e.g. subsystem
unregistration).
Fix this by using configfs_depend_item_unlocked() when o2hb_region_pin()
is called from a configfs callback context. This variant skips the root
inode_lock when caller and target are in the same subsystem, which is safe
because VFS already holds a lock preventing unregistration.
Add o2nm_depend_item_unlocked() wrapper and a from_callback parameter to
o2hb_region_pin() to select the appropriate variant.
Link: https://lore.kernel.org/20260722124933.430554-3-joseph.qi@linux.alibaba.com
Fixes: 58a3158a5d ("ocfs2/cluster: Pin/unpin o2hb regions")
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
@@ -146,7 +146,7 @@ static unsigned int o2hb_dependent_users;
|
||||
* In global heartbeat mode, we pin/unpin all o2hb regions. This solution
|
||||
* works for both file system and userdlm domains.
|
||||
*/
|
||||
static int o2hb_region_pin(const char *region_uuid);
|
||||
static int o2hb_region_pin(const char *region_uuid, bool from_callback);
|
||||
static void o2hb_region_unpin(const char *region_uuid);
|
||||
|
||||
/* Only sets a new threshold if there are no active regions.
|
||||
@@ -2188,7 +2188,7 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
|
||||
|
||||
if (bitmap_weight(o2hb_quorum_region_bitmap,
|
||||
O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
|
||||
o2hb_region_pin(NULL);
|
||||
o2hb_region_pin(NULL, true);
|
||||
|
||||
unlock:
|
||||
spin_unlock(&o2hb_live_lock);
|
||||
@@ -2330,7 +2330,7 @@ EXPORT_SYMBOL_GPL(o2hb_setup_callback);
|
||||
* In local, we only pin the matching region. In global we pin all the active
|
||||
* regions.
|
||||
*/
|
||||
static int o2hb_region_pin(const char *region_uuid)
|
||||
static int o2hb_region_pin(const char *region_uuid, bool from_callback)
|
||||
{
|
||||
int ret = 0, found;
|
||||
struct o2hb_region *reg, *pinned;
|
||||
@@ -2385,7 +2385,10 @@ static int o2hb_region_pin(const char *region_uuid)
|
||||
spin_unlock(&o2hb_live_lock);
|
||||
|
||||
/* Ignore ENOENT only for local hb (userdlm domain) */
|
||||
ret = o2nm_depend_item(&pinned->hr_item);
|
||||
if (from_callback)
|
||||
ret = o2nm_depend_item_unlocked(&pinned->hr_item);
|
||||
else
|
||||
ret = o2nm_depend_item(&pinned->hr_item);
|
||||
|
||||
spin_lock(&o2hb_live_lock);
|
||||
if (!ret) {
|
||||
@@ -2483,8 +2486,8 @@ static int o2hb_region_inc_user(const char *region_uuid)
|
||||
|
||||
/* local heartbeat */
|
||||
if (!o2hb_global_heartbeat_active()) {
|
||||
ret = o2hb_region_pin(region_uuid);
|
||||
goto unlock;
|
||||
ret = o2hb_region_pin(region_uuid, false);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2497,7 +2500,7 @@ static int o2hb_region_inc_user(const char *region_uuid)
|
||||
|
||||
if (bitmap_weight(o2hb_quorum_region_bitmap,
|
||||
O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
|
||||
ret = o2hb_region_pin(NULL);
|
||||
ret = o2hb_region_pin(NULL, false);
|
||||
|
||||
unlock:
|
||||
spin_unlock(&o2hb_live_lock);
|
||||
|
||||
@@ -778,6 +778,12 @@ int o2nm_depend_item(struct config_item *item)
|
||||
return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
|
||||
}
|
||||
|
||||
int o2nm_depend_item_unlocked(struct config_item *item)
|
||||
{
|
||||
return configfs_depend_item_unlocked(&o2nm_cluster_group.cs_subsys,
|
||||
item);
|
||||
}
|
||||
|
||||
void o2nm_undepend_item(struct config_item *item)
|
||||
{
|
||||
configfs_undepend_item(item);
|
||||
|
||||
@@ -64,6 +64,7 @@ void o2nm_node_get(struct o2nm_node *node);
|
||||
void o2nm_node_put(struct o2nm_node *node);
|
||||
|
||||
int o2nm_depend_item(struct config_item *item);
|
||||
int o2nm_depend_item_unlocked(struct config_item *item);
|
||||
void o2nm_undepend_item(struct config_item *item);
|
||||
int o2nm_depend_node(u8 node_num);
|
||||
void o2nm_undepend_node(u8 node_num);
|
||||
|
||||
Reference in New Issue
Block a user