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 generic/533 test-case failure

The xfstests' test-case generic/533 fails to execute
correctly:

FSTYP -- hfsplus
PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025
MKFS_OPTIONS -- /dev/loop51
MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch

generic/533 _check_generic_filesystem: filesystem on /dev/loop50 is inconsistent
(see xfstests-dev/results//generic/533.full for details)

The key reason of the issue is returning -ENOENT error
code from hfsplus_find_attr(), __hfsplus_delete_attr(),
hfsplus_delete_attr_nolock(), hfsplus_delete_all_attrs().
The file exists but we don't have any xattr for this file.
Finally, -ENODATA error code is expected by application logic.

This patch reworks xattr logic of HFS+ by means exchanging
the -ENOENT error code on -ENODATA error code if xattr
has not been found for existing file or folder.

sudo ./check generic/533
FSTYP -- hfsplus
PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #16 SMP PREEMPT_DYNAMIC Wed Mar 11 15:04:58 PDT 2026
MKFS_OPTIONS -- /dev/loop51
MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch

generic/533 33s ... 32s
Ran: generic/533
Passed all 1 tests

Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/184
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/20260312221920.1422683-2-slava@dubeyko.com
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>

+38 -13
+29 -9
fs/hfsplus/attributes.c
··· 153 153 if (err) 154 154 goto failed_find_attr; 155 155 err = hfs_brec_find(fd, hfs_find_rec_by_key); 156 - if (err) 156 + if (err == -ENOENT) { 157 + /* file exists but xattr is absent */ 158 + err = -ENODATA; 159 + goto failed_find_attr; 160 + } else if (err) 157 161 goto failed_find_attr; 158 162 } else { 159 163 err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL); 160 164 if (err) 161 165 goto failed_find_attr; 162 166 err = hfs_brec_find(fd, hfs_find_1st_rec_by_cnid); 163 - if (err) 167 + if (err == -ENOENT) { 168 + /* file exists but xattr is absent */ 169 + err = -ENODATA; 170 + goto failed_find_attr; 171 + } else if (err) 164 172 goto failed_find_attr; 165 173 } 166 174 ··· 181 173 int err = 0; 182 174 struct super_block *sb = inode->i_sb; 183 175 struct hfs_find_data fd; 176 + 177 + hfs_dbg("name %s, ino %ld\n", 178 + name ? name : NULL, inode->i_ino); 184 179 185 180 if (!HFSPLUS_SB(sb)->attr_tree) 186 181 return 0; ··· 304 293 static int __hfsplus_delete_attr(struct inode *inode, u32 cnid, 305 294 struct hfs_find_data *fd) 306 295 { 307 - int err = 0; 296 + int err; 308 297 __be32 found_cnid, record_type; 309 298 299 + found_cnid = U32_MAX; 310 300 hfs_bnode_read(fd->bnode, &found_cnid, 311 301 fd->keyoffset + 312 302 offsetof(struct hfsplus_attr_key, cnid), 313 303 sizeof(__be32)); 314 304 if (cnid != be32_to_cpu(found_cnid)) 315 - return -ENOENT; 305 + return -ENODATA; 316 306 317 307 hfs_bnode_read(fd->bnode, &record_type, 318 308 fd->entryoffset, sizeof(record_type)); ··· 342 330 hfsplus_mark_inode_dirty(HFSPLUS_ATTR_TREE_I(inode->i_sb), 343 331 HFSPLUS_I_ATTR_DIRTY); 344 332 hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY); 345 - return err; 333 + return 0; 346 334 } 347 335 348 336 static ··· 366 354 } 367 355 368 356 err = hfs_brec_find(fd, hfs_find_rec_by_key); 369 - if (err) 357 + if (err == -ENOENT) { 358 + /* file exists but xattr is absent */ 359 + return -ENODATA; 360 + } else if (err) 370 361 return err; 371 362 372 363 err = __hfsplus_delete_attr(inode, inode->i_ino, fd); ··· 429 414 430 415 for (;;) { 431 416 err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd); 432 - if (err) { 433 - if (err != -ENOENT) 434 - pr_err("xattr search failed\n"); 417 + if (err == -ENOENT || err == -ENODATA) { 418 + /* 419 + * xattr has not been found 420 + */ 421 + err = -ENODATA; 422 + goto end_delete_all; 423 + } else if (err) { 424 + pr_err("xattr search failed\n"); 435 425 goto end_delete_all; 436 426 } 437 427
+6 -1
fs/hfsplus/hfsplus_fs.h
··· 571 571 static inline 572 572 bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off) 573 573 { 574 - bool is_valid = off < node->tree->node_size; 574 + bool is_valid; 575 + 576 + if (!node || !node->tree) 577 + return false; 578 + 579 + is_valid = off < node->tree->node_size; 575 580 576 581 if (!is_valid) { 577 582 pr_err("requested invalid offset: "
+3 -3
fs/hfsplus/xattr.c
··· 562 562 563 563 res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); 564 564 if (res) { 565 - if (res == -ENOENT) 565 + if (res == -ENOENT || res == -ENODATA) 566 566 res = -ENODATA; 567 567 else 568 - pr_err("xattr searching failed\n"); 568 + pr_err("xattr search failed\n"); 569 569 goto out; 570 570 } 571 571 ··· 757 757 758 758 err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); 759 759 if (err) { 760 - if (err == -ENOENT) { 760 + if (err == -ENOENT || err == -ENODATA) { 761 761 res = 0; 762 762 goto end_listxattr; 763 763 } else {