Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hfsplus: fix potential race conditions in b-tree functionality

The HFS_BNODE_DELETED flag is checked in hfs_bnode_put()
under locked tree->hash_lock. This patch adds locking
for the case of setting the HFS_BNODE_DELETED flag in
hfs_bnode_unlink() with the goal to avoid potential
race conditions.

The hfs_btree_write() method should be called under
tree->tree_lock. This patch reworks logic by adding
locking the tree->tree_lock for the calls of
hfs_btree_write() in hfsplus_cat_write_inode() and
hfsplus_system_write_inode().

This patch adds also the lockdep_assert_held() in
hfs_bmap_reserve(), hfs_bmap_alloc(), and hfs_bmap_free().

cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
cc: Yangtao Li <frank.li@vivo.com>
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
Link: https://lore.kernel.org/r/20260403230556.614171-2-slava@dubeyko.com
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>

+18 -8
+3
fs/hfsplus/bnode.c
··· 420 420 tree->root = 0; 421 421 tree->depth = 0; 422 422 } 423 + 424 + spin_lock(&tree->hash_lock); 423 425 set_bit(HFS_BNODE_DELETED, &node->flags); 426 + spin_unlock(&tree->hash_lock); 424 427 } 425 428 426 429 static inline int hfs_bnode_hash(u32 num)
+5
fs/hfsplus/btree.c
··· 500 500 u32 count; 501 501 int res; 502 502 503 + lockdep_assert_held(&tree->tree_lock); 504 + 503 505 if (rsvd_nodes <= 0) 504 506 return 0; 505 507 ··· 530 528 u32 nidx, idx; 531 529 u8 *data, byte, m; 532 530 int i, res; 531 + 532 + lockdep_assert_held(&tree->tree_lock); 533 533 534 534 res = hfs_bmap_reserve(tree, 1); 535 535 if (res) ··· 611 607 hfs_dbg("node %u\n", node->this); 612 608 BUG_ON(!node->this); 613 609 tree = node->tree; 610 + lockdep_assert_held(&tree->tree_lock); 614 611 nidx = node->this; 615 612 node = hfs_bnode_find(tree, 0); 616 613 if (IS_ERR(node))
+7 -8
fs/hfsplus/inode.c
··· 720 720 sizeof(struct hfsplus_cat_file)); 721 721 } 722 722 723 + res = hfs_btree_write(tree); 724 + if (res) { 725 + pr_err("b-tree write err: %d, ino %lu\n", 726 + res, inode->i_ino); 727 + goto out; 728 + } 729 + 723 730 set_bit(HFSPLUS_I_CAT_DIRTY, 724 731 &HFSPLUS_I(HFSPLUS_CAT_TREE_I(inode->i_sb))->flags); 725 732 set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); 726 733 out: 727 734 hfs_find_exit(&fd); 728 - 729 - if (!res) { 730 - res = hfs_btree_write(tree); 731 - if (res) { 732 - pr_err("b-tree write err: %d, ino %lu\n", 733 - res, inode->i_ino); 734 - } 735 - } 736 735 737 736 return res; 738 737 }
+3
fs/hfsplus/super.c
··· 153 153 } 154 154 hfsplus_inode_write_fork(inode, fork); 155 155 if (tree) { 156 + mutex_lock_nested(&tree->tree_lock, 157 + hfsplus_btree_lock_class(tree)); 156 158 int err = hfs_btree_write(tree); 159 + mutex_unlock(&tree->tree_lock); 157 160 158 161 if (err) { 159 162 pr_err("b-tree write err: %d, ino %lu\n",