Skip to content

Commit a46aaa7

Browse files
committed
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: hfs-linux-kernel/hfs-linux-kernel#184 cc: John Paul Adrian Glaubitz <[email protected]> cc: Yangtao Li <[email protected]> cc: [email protected] Signed-off-by: Viacheslav Dubeyko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Viacheslav Dubeyko <[email protected]>
1 parent e89b572 commit a46aaa7

3 files changed

Lines changed: 38 additions & 13 deletions

File tree

fs/hfsplus/attributes.c

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,22 @@ int hfsplus_find_attr(struct super_block *sb, u32 cnid,
153153
if (err)
154154
goto failed_find_attr;
155155
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)
157161
goto failed_find_attr;
158162
} else {
159163
err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL);
160164
if (err)
161165
goto failed_find_attr;
162166
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)
164172
goto failed_find_attr;
165173
}
166174

@@ -174,6 +182,9 @@ int hfsplus_attr_exists(struct inode *inode, const char *name)
174182
struct super_block *sb = inode->i_sb;
175183
struct hfs_find_data fd;
176184

185+
hfs_dbg("name %s, ino %ld\n",
186+
name ? name : NULL, inode->i_ino);
187+
177188
if (!HFSPLUS_SB(sb)->attr_tree)
178189
return 0;
179190

@@ -293,15 +304,16 @@ int hfsplus_create_attr(struct inode *inode,
293304
static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
294305
struct hfs_find_data *fd)
295306
{
296-
int err = 0;
307+
int err;
297308
__be32 found_cnid, record_type;
298309

310+
found_cnid = U32_MAX;
299311
hfs_bnode_read(fd->bnode, &found_cnid,
300312
fd->keyoffset +
301313
offsetof(struct hfsplus_attr_key, cnid),
302314
sizeof(__be32));
303315
if (cnid != be32_to_cpu(found_cnid))
304-
return -ENOENT;
316+
return -ENODATA;
305317

306318
hfs_bnode_read(fd->bnode, &record_type,
307319
fd->entryoffset, sizeof(record_type));
@@ -330,7 +342,7 @@ static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
330342
hfsplus_mark_inode_dirty(HFSPLUS_ATTR_TREE_I(inode->i_sb),
331343
HFSPLUS_I_ATTR_DIRTY);
332344
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
333-
return err;
345+
return 0;
334346
}
335347

336348
static
@@ -354,7 +366,10 @@ int hfsplus_delete_attr_nolock(struct inode *inode, const char *name,
354366
}
355367

356368
err = hfs_brec_find(fd, hfs_find_rec_by_key);
357-
if (err)
369+
if (err == -ENOENT) {
370+
/* file exists but xattr is absent */
371+
return -ENODATA;
372+
} else if (err)
358373
return err;
359374

360375
err = __hfsplus_delete_attr(inode, inode->i_ino, fd);
@@ -414,9 +429,14 @@ int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
414429

415430
for (;;) {
416431
err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd);
417-
if (err) {
418-
if (err != -ENOENT)
419-
pr_err("xattr search failed\n");
432+
if (err == -ENOENT || err == -ENODATA) {
433+
/*
434+
* xattr has not been found
435+
*/
436+
err = -ENODATA;
437+
goto end_delete_all;
438+
} else if (err) {
439+
pr_err("xattr search failed\n");
420440
goto end_delete_all;
421441
}
422442

fs/hfsplus/hfsplus_fs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,12 @@ hfsplus_btree_lock_class(struct hfs_btree *tree)
571571
static inline
572572
bool is_bnode_offset_valid(struct hfs_bnode *node, u32 off)
573573
{
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;
575580

576581
if (!is_valid) {
577582
pr_err("requested invalid offset: "

fs/hfsplus/xattr.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -562,10 +562,10 @@ ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
562562

563563
res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
564564
if (res) {
565-
if (res == -ENOENT)
565+
if (res == -ENOENT || res == -ENODATA)
566566
res = -ENODATA;
567567
else
568-
pr_err("xattr searching failed\n");
568+
pr_err("xattr search failed\n");
569569
goto out;
570570
}
571571

@@ -757,7 +757,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
757757

758758
err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
759759
if (err) {
760-
if (err == -ENOENT) {
760+
if (err == -ENOENT || err == -ENODATA) {
761761
res = 0;
762762
goto end_listxattr;
763763
} else {

0 commit comments

Comments
 (0)