]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
hfsplus: fix generic/533 test-case failure
authorViacheslav Dubeyko <slava@dubeyko.com>
Thu, 12 Mar 2026 22:19:21 +0000 (15:19 -0700)
committerViacheslav Dubeyko <slava@dubeyko.com>
Mon, 16 Mar 2026 22:28:02 +0000 (15:28 -0700)
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>
fs/hfsplus/attributes.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/xattr.c

index 6585bcea731c3e517ff281145b35ad31fc03a46b..704635c65e9a429a69e3cbe3b8dc69841e41d47c 100644 (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 @@ failed_init_create_attr:
 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;
                }
 
index 420dc920e097ef7d4cbc1ec371df93974fbecbfa..caba698814feb0fd2231a14175c25cd8e87751f8 100644 (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: "
index a824bcaac172b08fc1ed1ab9c07db296742cae17..89e2e7e46e96773dae21889327363374f317e176 100644 (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 {