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>
This commit is contained in:
Viacheslav Dubeyko 2026-03-12 15:19:21 -07:00
parent e89b5724aa
commit a46aaa76ad
3 changed files with 38 additions and 13 deletions

View File

@ -153,14 +153,22 @@ int hfsplus_find_attr(struct super_block *sb, u32 cnid,
if (err)
goto failed_find_attr;
err = hfs_brec_find(fd, hfs_find_rec_by_key);
if (err)
if (err == -ENOENT) {
/* file exists but xattr is absent */
err = -ENODATA;
goto failed_find_attr;
} else if (err)
goto failed_find_attr;
} else {
err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL);
if (err)
goto failed_find_attr;
err = hfs_brec_find(fd, hfs_find_1st_rec_by_cnid);
if (err)
if (err == -ENOENT) {
/* file exists but xattr is absent */
err = -ENODATA;
goto failed_find_attr;
} else if (err)
goto failed_find_attr;
}
@ -174,6 +182,9 @@ int hfsplus_attr_exists(struct inode *inode, const char *name)
struct super_block *sb = inode->i_sb;
struct hfs_find_data fd;
hfs_dbg("name %s, ino %ld\n",
name ? name : NULL, inode->i_ino);
if (!HFSPLUS_SB(sb)->attr_tree)
return 0;
@ -293,15 +304,16 @@ int hfsplus_create_attr(struct inode *inode,
static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
struct hfs_find_data *fd)
{
int err = 0;
int err;
__be32 found_cnid, record_type;
found_cnid = U32_MAX;
hfs_bnode_read(fd->bnode, &found_cnid,
fd->keyoffset +
offsetof(struct hfsplus_attr_key, cnid),
sizeof(__be32));
if (cnid != be32_to_cpu(found_cnid))
return -ENOENT;
return -ENODATA;
hfs_bnode_read(fd->bnode, &record_type,
fd->entryoffset, sizeof(record_type));
@ -330,7 +342,7 @@ static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
hfsplus_mark_inode_dirty(HFSPLUS_ATTR_TREE_I(inode->i_sb),
HFSPLUS_I_ATTR_DIRTY);
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
return err;
return 0;
}
static
@ -354,7 +366,10 @@ int hfsplus_delete_attr_nolock(struct inode *inode, const char *name,
}
err = hfs_brec_find(fd, hfs_find_rec_by_key);
if (err)
if (err == -ENOENT) {
/* file exists but xattr is absent */
return -ENODATA;
} else if (err)
return err;
err = __hfsplus_delete_attr(inode, inode->i_ino, fd);
@ -414,9 +429,14 @@ int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
for (;;) {
err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd);
if (err) {
if (err != -ENOENT)
pr_err("xattr search failed\n");
if (err == -ENOENT || err == -ENODATA) {
/*
* xattr has not been found
*/
err = -ENODATA;
goto end_delete_all;
} else if (err) {
pr_err("xattr search failed\n");
goto end_delete_all;
}

View File

@ -571,7 +571,12 @@ hfsplus_btree_lock_class(struct hfs_btree *tree)
static inline
bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off)
{
bool is_valid = off < node->tree->node_size;
bool is_valid;
if (!node || !node->tree)
return false;
is_valid = off < node->tree->node_size;
if (!is_valid) {
pr_err("requested invalid offset: "

View File

@ -562,10 +562,10 @@ ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
if (res) {
if (res == -ENOENT)
if (res == -ENOENT || res == -ENODATA)
res = -ENODATA;
else
pr_err("xattr searching failed\n");
pr_err("xattr search failed\n");
goto out;
}
@ -757,7 +757,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
if (err) {
if (err == -ENOENT) {
if (err == -ENOENT || err == -ENODATA) {
res = 0;
goto end_listxattr;
} else {