* [PATCH] ocfs2/cluster: serialize heartbeat block count with device setup
@ 2026-10-20 13:16 Cen Zhang
0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-20 13:16 UTC (permalink / raw)
To: mark, jlbec, joseph.qi
Cc: heming.zhao, ocfs2-devel, linux-kernel, stable, baijiaju1990,
jjzuming, zzzccc427
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;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-20 13:16 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-20 13:16 [PATCH] ocfs2/cluster: serialize heartbeat block count with device setup Cen Zhang
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®