- When an NFS client mounts a FUSE-backed export, the NFS server tells the client whether the filesystem supports user xattrs.
- The server does this by calling
xattr_supports_user_prefix()in xattr.c, which loops over the superblock's xattr handlers looking for one whose prefix starts with"user.". - FUSE registers a single catch-all handler with
.prefix = ""(empty string) in xattr.c. This handler delegates everything to userspace — it handles all namespaces, includinguser.*. - But
strncmp("", "user.", 5)doesn't match, soxattr_supports_user_prefix()returns-EOPNOTSUPP. - The NFS server encodes
Xattr_support = 0innfsd4_encode_fattr4_xattr_support()(nfs4xdr.c), and the NFS client disables all xattr operations.
In xattr_supports_user_prefix(), after the existing strncmp check, we add: if the handler's prefix is empty (!*prefix), it's a catch-all that covers all namespaces including user.* — return success.
xattr_resolve_name() in xattr.c strips the matched prefix from the xattr name before passing it to the handler's .get/.set callbacks. With the existing catch-all (.prefix = ""), nothing is stripped — "user.myattr" reaches the FUSE daemon as "user.myattr".
If you add a handler with .prefix = "user.", xattr_resolve_name() strips "user." and passes just "myattr" to fuse_xattr_get/fuse_xattr_set, which then sends "myattr" to the FUSE daemon. The daemon expects the full name "user.myattr" — so the operation silently breaks or fails.
| File | Function | Role |
|---|---|---|
| xattr.c | xattr_supports_user_prefix() |
Fixed here. Checks if a filesystem supports user.* xattrs |
| xattr.c | xattr_resolve_name() |
Matches an xattr name to a handler and strips the prefix — why adding a FUSE handler breaks things |
| xattr.c | fuse_xattr_handler (.prefix = "") |
The catch-all handler that wasn't being recognized |
| nfs4xdr.c | nfsd4_encode_fattr4_xattr_support() |
NFS server calls xattr_supports_user_prefix() and reports result to client |