From nobody Fri Jul 24 22:52:03 2026 Received: from out30-98.freemail.mail.aliyun.com (out30-98.freemail.mail.aliyun.com [115.124.30.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BDD5A288C2C for ; Wed, 22 Jul 2026 12:49:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.98 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784724588; cv=none; b=ZybpmlefC18zW2aixgCQQ7AwJqvHV9Z3N4h3kL8sfMCVJBTPwqqc893dbIJtrw4G7wYeoqWFKE065BLoLsVeOEHbAra+T7ni2YW5h++Lu4HMMXPD5//rkPcYziX4PXuBPCfGxOl9pWdXgVyOY7RapdoPAg3zNmA/K7647zbjzH0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784724588; c=relaxed/simple; bh=n+6V8MZEYNuMTfZWJYrG5/uWwDugg2aHPFbVBzCQOiQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=LsL1dxgysUuvc9aWKMayXxp197S7ZFCDaJ9iWZy04MNNHIyl9Ycb1TxtqFwCjIxdVzKbxwMopElnZvqGZvhOJoAHU9bYJ0ohfcl6hlyvXtbHbTM4sqaoo+1zdhopLINJHPE/WmCIWv1O/NDS4wrlk512pLtBIFWwVqCfq0qSP1s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=D5a4Axsl; arc=none smtp.client-ip=115.124.30.98 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="D5a4Axsl" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1784724575; h=From:To:Subject:Date:Message-Id:MIME-Version:Content-Type; bh=TlQBqXEKz2cBa162EBIUo9/YwhoWB5RUudVNVJH4xag=; b=D5a4AxslEehvtqrTKPZiIUfrf78QJlUw+F+tMuNunEAMHse/Rn4eE9iumWC1My7XwQJCNSF77RJzXpZIRQghuUzxKmA3148Nq6SYigpnKxxYr20Wj5m0ID1OLc0nv2GO72pIEy+yD+wBcT9bjV2KKeAP+Qg6V3D9UZpcWqVUagU= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R191e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam011083073210;MF=joseph.qi@linux.alibaba.com;NM=1;PH=DS;RN=6;SR=0;TI=SMTPD_---0X7dOckD_1784724574; Received: from localhost(mailfrom:joseph.qi@linux.alibaba.com fp:SMTPD_---0X7dOckD_1784724574 cluster:ay36) by smtp.aliyun-inc.com; Wed, 22 Jul 2026 20:49:34 +0800 From: Joseph Qi To: Andrew Morton , Mark Fasheh , Joel Becker , Heming Zhao Cc: ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/3] ocfs2: cluster: don't sleep while holding o2hb_live_lock in o2hb_region_pin() Date: Wed, 22 Jul 2026 20:49:31 +0800 Message-Id: <20260722124933.430554-2-joseph.qi@linux.alibaba.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260722124933.430554-1-joseph.qi@linux.alibaba.com> References: <20260722124933.430554-1-joseph.qi@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable o2hb_region_pin() is always called with the o2hb_live_lock spinlock held (from o2hb_region_inc_user() and o2hb_heartbeat_group_drop_item()), but it calls o2nm_depend_item() -> configfs_depend_item(), which sleeps: it pins the configfs filesystem and takes the configfs root inode rwsem. Under CONFIG_DEBUG_ATOMIC_SLEEP this triggers: BUG: sleeping function called from invalid context at kernel/locking/rwse= m.c in_atomic(): 1, ... name: mount.ocfs2 down_write configfs_depend_item o2hb_region_pin o2hb_region_inc_user o2hb_register_callback dlm_register_domain_handlers ... ocfs2_dlm_init ocfs2_mount_volume ocfs2_fill_super Rework o2hb_region_pin() to pin one region at a time with the lock dropped across the sleeping call: under o2hb_live_lock find the next eligible region and take a config_item reference to keep it alive, drop the lock, call o2nm_depend_item(), then retake the lock and record the pin. The config_item_put() is done with the lock released as well, since o2hb_region_release() also acquires o2hb_live_lock and can sleep. The region list may change while unlocked, so the scan restarts from the top after each pin. Local heartbeat still pins only the matching region; global heartbeat pins all eligible regions. The unpin path is unaffected: configfs_undepend_item() only takes a spinlock and does not sleep. Fixes: 58a3158a5d17 ("ocfs2/cluster: Pin/unpin o2hb regions") Signed-off-by: Joseph Qi --- fs/ocfs2/cluster/heartbeat.c | 126 ++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 25 deletions(-) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 29542edbc992c..5ca1d9c0c6575 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -43,6 +43,14 @@ static DECLARE_RWSEM(o2hb_callback_sem); * whenever any of the threads sees activity from the node in its region. */ static DEFINE_SPINLOCK(o2hb_live_lock); +/* + * Serializes region pin/unpin dependency management (o2hb_dependent_users + * and the o2nm_depend_item()/o2nm_undepend_item() calls). o2hb_region_pin= () + * has to drop o2hb_live_lock across the sleeping o2nm_depend_item(), so t= he + * spinlock alone can no longer keep pin and unpin mutually exclusive; this + * mutex, taken outside o2hb_live_lock, does. + */ +static DEFINE_MUTEX(o2hb_dependency_mutex); static struct list_head o2hb_live_slots[O2NM_MAX_NODES]; static unsigned long o2hb_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)]; static LIST_HEAD(o2hb_node_events); @@ -2172,6 +2180,7 @@ static void o2hb_heartbeat_group_drop_item(struct con= fig_group *group, * If global heartbeat active and there are dependent users, * pin all regions if quorum region count <=3D CUT_OFF */ + mutex_lock(&o2hb_dependency_mutex); spin_lock(&o2hb_live_lock); =20 if (!o2hb_dependent_users) @@ -2183,6 +2192,7 @@ static void o2hb_heartbeat_group_drop_item(struct con= fig_group *group, =20 unlock: spin_unlock(&o2hb_live_lock); + mutex_unlock(&o2hb_dependency_mutex); } =20 static ssize_t o2hb_heartbeat_group_dead_threshold_show(struct config_item= *item, @@ -2322,46 +2332,108 @@ EXPORT_SYMBOL_GPL(o2hb_setup_callback); */ static int o2hb_region_pin(const char *region_uuid) { - int ret =3D 0, found =3D 0; - struct o2hb_region *reg; + int ret =3D 0, found; + struct o2hb_region *reg, *pinned; char *uuid; =20 assert_spin_locked(&o2hb_live_lock); =20 - list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) { - if (reg->hr_item_dropped) - continue; + do { + found =3D 0; + pinned =3D NULL; =20 - uuid =3D config_item_name(®->hr_item); + list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) { + if (reg->hr_item_dropped) + continue; =20 - /* local heartbeat */ - if (region_uuid) { - if (strcmp(region_uuid, uuid)) + uuid =3D config_item_name(®->hr_item); + + /* local heartbeat */ + if (region_uuid) { + if (strcmp(region_uuid, uuid)) + continue; + found =3D 1; + } + + if (reg->hr_item_pinned || reg->hr_item_dropped) { + if (found) + break; continue; - found =3D 1; + } + + /* + * Found a region that needs pinning. Take a reference + * so it stays alive while we drop the lock below. + */ + pinned =3D reg; + config_item_get(®->hr_item); + break; } =20 - if (reg->hr_item_pinned || reg->hr_item_dropped) - goto skip_pin; + if (!pinned) + break; + + uuid =3D config_item_name(&pinned->hr_item); + + /* + * o2nm_depend_item() -> configfs_depend_item() can sleep (it + * takes the configfs root inode rwsem), so it must not run + * under o2hb_live_lock. Drop the lock across it; @pinned is + * kept alive by the reference taken above. The region list may + * change while unlocked, so we rescan from the top afterwards. + */ + spin_unlock(&o2hb_live_lock); =20 /* Ignore ENOENT only for local hb (userdlm domain) */ - ret =3D o2nm_depend_item(®->hr_item); + ret =3D o2nm_depend_item(&pinned->hr_item); + + spin_lock(&o2hb_live_lock); if (!ret) { - mlog(ML_CLUSTER, "Pin region %s\n", uuid); - reg->hr_item_pinned =3D 1; - } else { - if (ret =3D=3D -ENOENT && found) - ret =3D 0; - else { - mlog(ML_ERROR, "Pin region %s fails with %d\n", - uuid, ret); + /* + * o2hb_live_lock was dropped across o2nm_depend_item(). + * o2hb_set_quorum_device() runs in the heartbeat thread + * without o2hb_dependency_mutex, so for global heartbeat + * it may have crossed O2HB_PIN_CUT_OFF and unpinned the + * regions while we slept. If that happened this pin is + * no longer wanted; undo it and stop rather than + * resurrecting it on the rescan below. + */ + if (!region_uuid && + bitmap_weight(o2hb_quorum_region_bitmap, + O2NM_MAX_REGIONS) > O2HB_PIN_CUT_OFF) { + o2nm_undepend_item(&pinned->hr_item); + spin_unlock(&o2hb_live_lock); + config_item_put(&pinned->hr_item); + spin_lock(&o2hb_live_lock); break; } + mlog(ML_CLUSTER, "Pin region %s\n", uuid); + pinned->hr_item_pinned =3D 1; + } else if (ret =3D=3D -ENOENT && (found || !region_uuid)) { + /* + * For local hb (found): ignore ENOENT from userdlm + * domains as before. For global hb (!region_uuid): + * the region may have been detached from configfs + * while the lock was dropped =E2=80=94 skip it and continue + * pinning the remaining regions. + */ + ret =3D 0; + } else { + mlog(ML_ERROR, "Pin region %s fails with %d\n", + uuid, ret); } -skip_pin: - if (found) - break; - } + + /* + * config_item_put() may drop the last reference and run + * o2hb_region_release(), which also grabs o2hb_live_lock and + * can sleep, so it must happen with the lock released. + */ + spin_unlock(&o2hb_live_lock); + config_item_put(&pinned->hr_item); + spin_lock(&o2hb_live_lock); + + /* local hb pins a single matching region */ + } while (!ret && !region_uuid); =20 return ret; } @@ -2406,6 +2478,7 @@ static int o2hb_region_inc_user(const char *region_uu= id) { int ret =3D 0; =20 + mutex_lock(&o2hb_dependency_mutex); spin_lock(&o2hb_live_lock); =20 /* local heartbeat */ @@ -2428,11 +2501,13 @@ static int o2hb_region_inc_user(const char *region_= uuid) =20 unlock: spin_unlock(&o2hb_live_lock); + mutex_unlock(&o2hb_dependency_mutex); return ret; } =20 static void o2hb_region_dec_user(const char *region_uuid) { + mutex_lock(&o2hb_dependency_mutex); spin_lock(&o2hb_live_lock); =20 /* local heartbeat */ @@ -2451,6 +2526,7 @@ static void o2hb_region_dec_user(const char *region_u= uid) =20 unlock: spin_unlock(&o2hb_live_lock); + mutex_unlock(&o2hb_dependency_mutex); } =20 int o2hb_register_callback(const char *region_uuid, --=20 2.39.3 From nobody Fri Jul 24 22:52:03 2026 Received: from out30-113.freemail.mail.aliyun.com (out30-113.freemail.mail.aliyun.com [115.124.30.113]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3D0562F360A for ; Wed, 22 Jul 2026 12:49:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.113 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784724586; cv=none; b=L4lMByZeso9psGnO0IrFQQGZchngRRUmn+T2SDmEiwvwlxJ7v4WZbBkHmV4v9DpoUCifnT/+Q226kqG0uhmmexfFE1LpI22dVGb4Lw2jmbcsSPsk8YLgffX7rENIOlnD1lUuBEAlzrPBUbYD+gGx3ex9oeHGvWmAiPbqavHEWRc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784724586; c=relaxed/simple; bh=cxHikLnOINPUdEmPCdbaVwlYo6YTatvM/crhEXy5RTI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=C5wG2+AHTCnxK6M0TIWwO4lpLOP6jl191mdVqwDRcV9cTGk0+CQAVI5DTLOQ1bwbxb303rGx7ztnIQDPPRBK7KgW7EiZkzUg1LroiCLB9/MR2muRDppPPb535oWKONAy1yhqRpkd9/Gub6SmP6mbnfbetuEinwQG21ui9B2IYuI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=xzPTGsZR; arc=none smtp.client-ip=115.124.30.113 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="xzPTGsZR" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1784724576; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=PEqRa9WNHp2UTn+NgMgPVbwjvcuLfhIBSAHM6BSit+0=; b=xzPTGsZRWDTgXCjPIK1l3UgAY/cDx1QdsfAovwve6FgfXs/DhHSFHZ54QlEQuu8w4rX7JYCjhTGm3IonftpsdARJ1xtsZBupy72ivhC+IyScjEMmM7HTVYmqDHhk/KHSxEbsk1ahnkMH2kEVMBHxvbE/RZA/FL7EgO0pBDYSEPI= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R111e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033037033178;MF=joseph.qi@linux.alibaba.com;NM=1;PH=DS;RN=6;SR=0;TI=SMTPD_---0X7dMO6v_1784724575; Received: from localhost(mailfrom:joseph.qi@linux.alibaba.com fp:SMTPD_---0X7dMO6v_1784724575 cluster:ay36) by smtp.aliyun-inc.com; Wed, 22 Jul 2026 20:49:35 +0800 From: Joseph Qi To: Andrew Morton , Mark Fasheh , Joel Becker , Heming Zhao Cc: ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/3] ocfs2: cluster: avoid lock order inversion in o2hb_region_pin() from drop_item Date: Wed, 22 Jul 2026 20:49:32 +0800 Message-Id: <20260722124933.430554-3-joseph.qi@linux.alibaba.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260722124933.430554-1-joseph.qi@linux.alibaba.com> References: <20260722124933.430554-1-joseph.qi@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Fixes: 58a3158a5d17 ("ocfs2/cluster: Pin/unpin o2hb regions") Signed-off-by: Joseph Qi --- fs/ocfs2/cluster/heartbeat.c | 17 ++++++++++------- fs/ocfs2/cluster/nodemanager.c | 6 ++++++ fs/ocfs2/cluster/nodemanager.h | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 5ca1d9c0c6575..b9395835523e2 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -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); =20 /* Only sets a new threshold if there are no active regions. @@ -2188,7 +2188,7 @@ static void o2hb_heartbeat_group_drop_item(struct con= fig_group *group, =20 if (bitmap_weight(o2hb_quorum_region_bitmap, O2NM_MAX_REGIONS) <=3D O2HB_PIN_CUT_OFF) - o2hb_region_pin(NULL); + o2hb_region_pin(NULL, true); =20 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 act= ive * regions. */ -static int o2hb_region_pin(const char *region_uuid) +static int o2hb_region_pin(const char *region_uuid, bool from_callback) { int ret =3D 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); =20 /* Ignore ENOENT only for local hb (userdlm domain) */ - ret =3D o2nm_depend_item(&pinned->hr_item); + if (from_callback) + ret =3D o2nm_depend_item_unlocked(&pinned->hr_item); + else + ret =3D o2nm_depend_item(&pinned->hr_item); =20 spin_lock(&o2hb_live_lock); if (!ret) { @@ -2483,8 +2486,8 @@ static int o2hb_region_inc_user(const char *region_uu= id) =20 /* local heartbeat */ if (!o2hb_global_heartbeat_active()) { - ret =3D o2hb_region_pin(region_uuid); - goto unlock; + ret =3D o2hb_region_pin(region_uuid, false); + goto unlock; } =20 /* @@ -2497,7 +2500,7 @@ static int o2hb_region_inc_user(const char *region_uu= id) =20 if (bitmap_weight(o2hb_quorum_region_bitmap, O2NM_MAX_REGIONS) <=3D O2HB_PIN_CUT_OFF) - ret =3D o2hb_region_pin(NULL); + ret =3D o2hb_region_pin(NULL, false); =20 unlock: spin_unlock(&o2hb_live_lock); diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index e1f8f577ce5d6..ebdf0bdbb8c69 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -778,6 +778,12 @@ int o2nm_depend_item(struct config_item *item) return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item); } =20 +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); diff --git a/fs/ocfs2/cluster/nodemanager.h b/fs/ocfs2/cluster/nodemanager.h index 39006005427b6..ca3483fb54504 100644 --- a/fs/ocfs2/cluster/nodemanager.h +++ b/fs/ocfs2/cluster/nodemanager.h @@ -64,6 +64,7 @@ void o2nm_node_get(struct o2nm_node *node); void o2nm_node_put(struct o2nm_node *node); =20 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); --=20 2.39.3 From nobody Fri Jul 24 22:52:03 2026 Received: from out30-112.freemail.mail.aliyun.com (out30-112.freemail.mail.aliyun.com [115.124.30.112]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AD52A29D29F for ; Wed, 22 Jul 2026 12:49:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.112 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784724587; cv=none; b=nWGZULA0q57njdrix+4vEtvIaRoRrbmmI7e1QWKzHztOOdNg4WhlkOeSNLDonir6s3sEAoGhPf1c7L/9axiGlGUr7TK1PgxoPhhHBheDmR2csn84SuQlpfARzq/9GtGyxf2NoGL79VuINI77bcj7XqI39Ln01nM7ctFeVxCspxo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784724587; c=relaxed/simple; bh=83qqL9QaHl68BIuBD49IV/hhUYTFYLjlIYe2Z5E+xlQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Z0ICDLqnpXkpLiIICFzogBnauewTGyhWQBJHHdV/HYbZBEI6T+pc9ZiPDoUupV/mvR6EQKO/qDf2qvmQYzBdt/4gVe4PRGL5zFEFVS0UBDnfGI2KVBu3UdHNN66iQ1O+tr5xa8Qq6F7O995BgxAfegzMI5QBLmrMnUjLkrRmkFg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=q1I2IbWu; arc=none smtp.client-ip=115.124.30.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="q1I2IbWu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1784724577; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=UbcvKoanBvsJ2FJe5h8pWBVsZaTGcDaSpk9vsfukem4=; b=q1I2IbWuXFCREyVOOvrk9lbHc6aGUEab2kVpLSAOOLNxSBi2jwsOLdaVpvEl/epU1GQEa004qN89kxDUn/sy8pXSiD2VM4mw7yxzvXdSzrDk/VnPEXdrAhoZ76DWY9zda21SGpAsxusd56AaPQHIyg4gkPZ0MgHfo7ju1B3b9uY= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R291e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033045098064;MF=joseph.qi@linux.alibaba.com;NM=1;PH=DS;RN=6;SR=0;TI=SMTPD_---0X7dKx4Q_1784724576; Received: from localhost(mailfrom:joseph.qi@linux.alibaba.com fp:SMTPD_---0X7dKx4Q_1784724576 cluster:ay36) by smtp.aliyun-inc.com; Wed, 22 Jul 2026 20:49:36 +0800 From: Joseph Qi To: Andrew Morton , Mark Fasheh , Joel Becker , Heming Zhao Cc: ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 3/3] ocfs2: cluster: fix o2hb_dependent_users leak on pin failure Date: Wed, 22 Jul 2026 20:49:33 +0800 Message-Id: <20260722124933.430554-4-joseph.qi@linux.alibaba.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260722124933.430554-1-joseph.qi@linux.alibaba.com> References: <20260722124933.430554-1-joseph.qi@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In o2hb_region_inc_user(), o2hb_dependent_users is incremented unconditionally before calling o2hb_region_pin(). If the pin fails, the counter is never decremented and any partially-pinned regions are never unpinned, since the caller does not call o2hb_region_dec_user() on error. The leaked counter causes subsequent o2hb_region_inc_user() calls to skip pinning entirely (the > 1 check), leaving heartbeat regions unprotected. Fix by rolling back on failure: call o2hb_region_unpin(NULL) to release any partially-pinned regions and decrement o2hb_dependent_users to restore the pre-increment state. Fixes: 58a3158a5d17 ("ocfs2/cluster: Pin/unpin o2hb regions") Signed-off-by: Joseph Qi --- fs/ocfs2/cluster/heartbeat.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index b9395835523e2..c25aa2ff3ebc2 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -2499,8 +2499,13 @@ static int o2hb_region_inc_user(const char *region_u= uid) goto unlock; =20 if (bitmap_weight(o2hb_quorum_region_bitmap, - O2NM_MAX_REGIONS) <=3D O2HB_PIN_CUT_OFF) + O2NM_MAX_REGIONS) <=3D O2HB_PIN_CUT_OFF) { ret =3D o2hb_region_pin(NULL, false); + if (ret) { + o2hb_region_unpin(NULL); + o2hb_dependent_users--; + } + } =20 unlock: spin_unlock(&o2hb_live_lock); --=20 2.39.3