From: Cen Zhang <zzzccc427@gmail.com>
To: mark@fasheh.com, jlbec@evilplan.org, joseph.qi@linux.alibaba.com
Cc: heming.zhao@suse.com, ocfs2-devel@lists.linux.dev,
linux-kernel@vger.kernel.org, stable@vger.kernel.org,
baijiaju1990@gmail.com, jjzuming@gmail.com, zzzccc427@gmail.com
Subject: [PATCH] ocfs2/cluster: serialize heartbeat block count with device setup
Date: Tue, 20 Oct 2026 21:16:26 +0800 [thread overview]
Message-ID: <pm-ocfs2-objects-candidate-0077-v6-eb25e73523a3cb94fae0@gmail.com> (raw)
A heartbeat region's hr_blocks must match the number of slots allocated
in hr_slots until its thread stops. o2hb_region_blocks_store() checks
hr_bdev_file before updating hr_blocks, but neither operation is
serialized with device publication in o2hb_region_dev_store().
Writes to blocks and dev through separate configfs opens can overlap.
The buffer mutex is per open, and both callbacks hold frag_sem for read.
With an initial count N, the following order is possible:
blocks writer device writer
------------- -------------
check hr_bdev_file == NULL
publish hr_bdev_file
allocate N slots in o2hb_map_slot_data()
start o2hb_thread() and return
store hr_blocks = M, M > N
return
After both writes finish, normal region removal calls kthread_stop().
o2hb_thread() iterates over the enlarged count and passes &hr_slots[N]
to o2hb_shutdown_slot(), which reads ds_node_num beyond the allocation.
Recheck the device guard and update hr_blocks under o2hb_live_lock, and
publish the device file under the same lock. Open the device into a
local pointer to keep the sleeping open outside the spinlock. A blocks
write then either completes before publication and determines the slot
count, or sees the published file and returns -EINVAL. Clear the file
under the same lock after failed-start cleanup has stopped the thread
and unmapped the slots, so configuration can resume safely.
KASAN report as below:
BUG: KASAN: slab-out-of-bounds in o2hb_thread+0xc62/0xe90
Read of size 1 at addr ffff888107829ac0 by task o2hb-pmbd-regio/497
CPU: 3 UID: 0 PID: 497 Comm: o2hb-pmbd-regio Not tainted 7.3.0-rc4-next-20260921-pmb-ocfs2-functional-v1+ #1 PREEMPT(lazy)
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x93/0xd0
print_report+0xce/0x630
? o2hb_thread+0xc62/0xe90
? srso_alias_return_thunk+0x5/0xfbef5
? __virt_addr_valid+0x20e/0x420
? o2hb_thread+0xc62/0xe90
kasan_report+0xe0/0x110
? o2hb_thread+0xc62/0xe90
o2hb_thread+0xc62/0xe90
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_o2hb_thread+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? srso_alias_return_thunk+0x5/0xfbef5
? srso_alias_return_thunk+0x5/0xfbef5
? __lock_acquire+0x5a3/0x2140
? srso_alias_return_thunk+0x5/0xfbef5
? lockdep_hardirqs_on_prepare+0xeb/0x1a0
? srso_alias_return_thunk+0x5/0xfbef5
? trace_hardirqs_on+0x18/0x160
? srso_alias_return_thunk+0x5/0xfbef5
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_o2hb_thread+0x10/0x10
? kthread+0x351/0x460
kthread+0x351/0x460
? srso_alias_return_thunk+0x5/0xfbef5
? __pfx_kthread+0x10/0x10
ret_from_fork+0x659/0x940
? __pfx_ret_from_fork+0x10/0x10
? srso_alias_return_thunk+0x5/0xfbef5
? __switch_to+0x74f/0xf70
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1a/0x30
</TASK>
Allocated by task 496:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_noprof+0x2de/0x780
o2hb_region_dev_store+0x7c4/0x1c70
configfs_write_iter+0x2f9/0x4f0
vfs_write+0x639/0x1010
ksys_write+0x111/0x200
do_syscall_64+0x114/0x620
entry_SYSCALL_64_after_hwframe+0x77/0x7f
The buggy address belongs to the object at ffff888107829a80
which belongs to the cache kmalloc-64 of size 64
The buggy address is located 8 bytes to the right of
allocated 56-byte region [ffff888107829a80, ffff888107829ab8)
(Page and memory-state dump omitted.)
Fixes: a7f6a5fb4bde ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem")
Cc: <stable@vger.kernel.org>
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: LLM
---
fs/ocfs2/cluster/heartbeat.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index b45adc39aacc..7448ee53aebe 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1746,7 +1746,13 @@ static ssize_t o2hb_region_blocks_store(struct config_item *item,
if (tmp > O2NM_MAX_NODES || tmp == 0)
return -ERANGE;
+ spin_lock(&o2hb_live_lock);
+ if (reg->hr_bdev_file) {
+ spin_unlock(&o2hb_live_lock);
+ return -EINVAL;
+ }
reg->hr_blocks = (unsigned int)tmp;
+ spin_unlock(&o2hb_live_lock);
return count;
}
@@ -1878,6 +1884,7 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
{
struct o2hb_region *reg = to_o2hb_region(item);
struct task_struct *hb_task;
+ struct file *bdev_file;
long fd;
int sectsize;
char *p = (char *)page;
@@ -1911,13 +1918,22 @@ static ssize_t o2hb_region_dev_store(struct config_item *item,
if (!S_ISBLK(fd_file(f)->f_mapping->host->i_mode))
return -EINVAL;
- reg->hr_bdev_file = bdev_file_open_by_dev(fd_file(f)->f_mapping->host->i_rdev,
- BLK_OPEN_WRITE | BLK_OPEN_READ, NULL, NULL);
- if (IS_ERR(reg->hr_bdev_file)) {
- ret = PTR_ERR(reg->hr_bdev_file);
- reg->hr_bdev_file = NULL;
- return ret;
+ bdev_file =
+ bdev_file_open_by_dev(fd_file(f)->f_mapping->host->i_rdev,
+ BLK_OPEN_WRITE | BLK_OPEN_READ,
+ NULL, NULL);
+ if (IS_ERR(bdev_file))
+ return PTR_ERR(bdev_file);
+
+ /* Freeze hr_blocks before allocating the slot array. */
+ spin_lock(&o2hb_live_lock);
+ if (reg->hr_bdev_file) {
+ spin_unlock(&o2hb_live_lock);
+ fput(bdev_file);
+ return -EINVAL;
}
+ reg->hr_bdev_file = bdev_file;
+ spin_unlock(&o2hb_live_lock);
sectsize = bdev_logical_block_size(reg_bdev(reg));
if (sectsize != reg->hr_block_bytes) {
@@ -2036,7 +2052,9 @@ out:
o2hb_unmap_slot_data(reg);
fput(reg->hr_bdev_file);
+ spin_lock(&o2hb_live_lock);
reg->hr_bdev_file = NULL;
+ spin_unlock(&o2hb_live_lock);
}
return ret;
}
reply other threads:[~2026-10-20 13:16 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pm-ocfs2-objects-candidate-0077-v6-eb25e73523a3cb94fae0@gmail.com \
--to=zzzccc427@gmail.com \
--cc=baijiaju1990@gmail.com \
--cc=heming.zhao@suse.com \
--cc=jjzuming@gmail.com \
--cc=jlbec@evilplan.org \
--cc=joseph.qi@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mark@fasheh.com \
--cc=ocfs2-devel@lists.linux.dev \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®