diff options
| author | Viacheslav Dubeyko <slava@dubeyko.com> | 2026-03-13 01:19:21 +0300 |
|---|---|---|
| committer | Viacheslav Dubeyko <slava@dubeyko.com> | 2026-03-17 01:28:02 +0300 |
| commit | a46aaa76ad21de033f188595173e8ae7afefddc0 (patch) | |
| tree | cd6e1b18880c1599ced93c21259777cac398e4cc | |
| parent | e89b5724aaf362cc84ecacaf56eb09a88e57441e (diff) | |
| download | linux-a46aaa76ad21de033f188595173e8ae7afefddc0.tar.xz | |
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>
| -rw-r--r-- | fs/hfsplus/attributes.c | 38 | ||||
| -rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 7 | ||||
| -rw-r--r-- | fs/hfsplus/xattr.c | 6 |
3 files changed, 38 insertions, 13 deletions
diff --git a/fs/hfsplus/attributes.c b/fs/hfsplus/attributes.c index 6585bcea731c..704635c65e9a 100644 --- a/fs/hfsplus/attributes.c +++ b/fs/hfsplus/attributes.c @@ -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; } diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 420dc920e097..caba698814fe 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -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: " diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c index a824bcaac172..89e2e7e46e96 100644 --- a/fs/hfsplus/xattr.c +++ b/fs/hfsplus/xattr.c @@ -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 { |
