Skip to content

Commit 6dca66d

Browse files
committed
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 <[email protected]> cc: Yangtao Li <[email protected]> cc: [email protected] Signed-off-by: Viacheslav Dubeyko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Viacheslav Dubeyko <[email protected]>
1 parent d47059d commit 6dca66d

4 files changed

Lines changed: 18 additions & 8 deletions

File tree

fs/hfsplus/bnode.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,10 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
420420
tree->root = 0;
421421
tree->depth = 0;
422422
}
423+
424+
spin_lock(&tree->hash_lock);
423425
set_bit(HFS_BNODE_DELETED, &node->flags);
426+
spin_unlock(&tree->hash_lock);
424427
}
425428

426429
static inline int hfs_bnode_hash(u32 num)

fs/hfsplus/btree.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,8 @@ int hfs_bmap_reserve(struct hfs_btree *tree, u32 rsvd_nodes)
500500
u32 count;
501501
int res;
502502

503+
lockdep_assert_held(&tree->tree_lock);
504+
503505
if (rsvd_nodes <= 0)
504506
return 0;
505507

@@ -529,6 +531,8 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
529531
u8 *data, byte, m;
530532
int i, res;
531533

534+
lockdep_assert_held(&tree->tree_lock);
535+
532536
res = hfs_bmap_reserve(tree, 1);
533537
if (res)
534538
return ERR_PTR(res);
@@ -607,6 +611,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
607611
hfs_dbg("node %u\n", node->this);
608612
BUG_ON(!node->this);
609613
tree = node->tree;
614+
lockdep_assert_held(&tree->tree_lock);
610615
nidx = node->this;
611616
node = hfs_bnode_find(tree, 0);
612617
if (IS_ERR(node))

fs/hfsplus/inode.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -720,20 +720,19 @@ int hfsplus_cat_write_inode(struct inode *inode)
720720
sizeof(struct hfsplus_cat_file));
721721
}
722722

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+
723730
set_bit(HFSPLUS_I_CAT_DIRTY,
724731
&HFSPLUS_I(HFSPLUS_CAT_TREE_I(inode->i_sb))->flags);
725732
set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
726733
out:
727734
hfs_find_exit(&fd);
728735

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-
737736
return res;
738737
}
739738

fs/hfsplus/super.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ static int hfsplus_system_write_inode(struct inode *inode)
153153
}
154154
hfsplus_inode_write_fork(inode, fork);
155155
if (tree) {
156+
mutex_lock_nested(&tree->tree_lock,
157+
hfsplus_btree_lock_class(tree));
156158
int err = hfs_btree_write(tree);
159+
mutex_unlock(&tree->tree_lock);
157160

158161
if (err) {
159162
pr_err("b-tree write err: %d, ino %lu\n",

0 commit comments

Comments
 (0)