hfs_bnode_split() determines the split point by scanning the node's offset table for the first record whose data offset exceeds a threshold derived from node_size / 2. When all record data fits within the first half of the node, no record offset exceeds the threshold, the loop exhausts all records, and the function returns -ENOSPC even though the node can be validly split. This causes xattr insertions to fail silently. The failing code path is exercised by xfstests generic/070 and generic/642 during xattr stress operations. Fix this by re-scanning with a threshold based on the actual data midpoint when the position-based scan exhausts. If the re-scan also exhausts, fall back to splitting off the last record. Reported-by: Viacheslav Dubeyko Signed-off-by: Shardul Bankar --- fs/hfsplus/brec.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index e3df89284079..cfc909c808a4 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c @@ -282,12 +282,32 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd) old_rec_off -= rec_size; if (++num_recs < node->num_recs) continue; - hfs_bnode_put(node); - hfs_bnode_unlink(new_node); - hfs_bnode_put(new_node); - if (next_node) - hfs_bnode_put(next_node); - return ERR_PTR(-ENOSPC); + /* + * All data fits within the node_size/2 threshold, + * so re-scan using the actual data midpoint. + */ + size = hfs_bnode_read_u16(node, tree->node_size - + (node->num_recs + 1) * rec_size); + size = ((int)node_desc_size + size) / 2; + old_rec_off = tree->node_size - (2 * rec_size); + num_recs = 1; + for (;;) { + data_start = hfs_bnode_read_u16(node, + old_rec_off); + if (data_start > size) + break; + old_rec_off -= rec_size; + if (++num_recs < node->num_recs) + continue; + /* last record holds most of the data */ + num_recs = node->num_recs - 1; + old_rec_off = tree->node_size - + (num_recs + 1) * rec_size; + data_start = hfs_bnode_read_u16(node, + old_rec_off); + break; + } + break; } if (fd->record + 1 < num_recs) { -- 2.34.1