nfsd: allow encoding a filehandle into fattr4 without a svc_fh

The current fattr4 encoder requires a svc_fh in order to encode the
filehandle. This is not available in a CB_NOTIFY callback. Add a new
"fhandle" field to struct nfsd4_fattr_args and copy the filehandle into
there from the svc_fh. CB_NOTIFY will populate it via other means.

A filehandle composed this way may still need a MAC appended on signed
exports, so generalize fh_append_mac() to operate on a bare knfsd_fh
(plus its maximum size and net) rather than a svc_fh.

The FSID attribute shares the same attrmask gate as the filehandle, so
do the same for it: add fsid_source_fh() which takes a bare knfsd_fh and
its svc_export, and have the FSID encoder use args->fhandle and
args->exp. fsid_source() becomes a wrapper for the v2/v3 callers. The
now-unused svc_fh pointer is dropped from struct nfsd4_fattr_args.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260616-dir-deleg-v7-15-6cbc7eac0ade@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
This commit is contained in:
Jeff Layton
2026-08-10 09:54:35 -04:00
committed by Chuck Lever
parent 1473f2e50f
commit b809950fbd
3 changed files with 41 additions and 29 deletions
+20 -17
View File
@@ -2719,7 +2719,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
}
static __be32 nfsd4_encode_nfs_fh4(struct xdr_stream *xdr,
struct knfsd_fh *fh_handle)
const struct knfsd_fh *fh_handle)
{
return nfsd4_encode_opaque(xdr, fh_handle->fh_raw, fh_handle->fh_size);
}
@@ -3159,9 +3159,9 @@ out_resource:
struct nfsd4_fattr_args {
struct svc_rqst *rqstp;
struct svc_fh *fhp;
struct svc_export *exp;
struct dentry *dentry;
struct knfsd_fh fhandle;
struct kstat stat;
struct kstatfs statfs;
struct nfs4_acl *acl;
@@ -3309,7 +3309,7 @@ static __be32 nfsd4_encode_fattr4_fsid(struct xdr_stream *xdr,
xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR);
return nfs_ok;
}
switch (fsid_source(args->fhp)) {
switch (fsid_source_fh(&args->fhandle, args->exp)) {
case FSIDSOURCE_FSID:
p = xdr_encode_hyper(p, (u64)args->exp->ex_fsid);
xdr_encode_hyper(p, (u64)0);
@@ -3406,7 +3406,7 @@ static __be32 nfsd4_encode_fattr4_homogeneous(struct xdr_stream *xdr,
static __be32 nfsd4_encode_fattr4_filehandle(struct xdr_stream *xdr,
const struct nfsd4_fattr_args *args)
{
return nfsd4_encode_nfs_fh4(xdr, &args->fhp->fh_handle);
return nfsd4_encode_nfs_fh4(xdr, &args->fhandle);
}
static __be32 nfsd4_encode_fattr4_fileid(struct xdr_stream *xdr,
@@ -4019,19 +4019,22 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
if (err)
goto out_nfserr;
}
if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
!fhp) {
tempfh = kmalloc_obj(struct svc_fh);
status = nfserr_jukebox;
if (!tempfh)
goto out;
fh_init(tempfh, NFS4_FHSIZE);
status = fh_compose(tempfh, exp, dentry, NULL);
if (status)
goto out;
args.fhp = tempfh;
} else
args.fhp = fhp;
if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID))) {
if (!fhp) {
tempfh = kmalloc_obj(struct svc_fh);
status = nfserr_jukebox;
if (!tempfh)
goto out;
fh_init(tempfh, NFS4_FHSIZE);
status = fh_compose(tempfh, exp, dentry, NULL);
if (status)
goto out;
fhp = tempfh;
}
fh_copy_shallow(&args.fhandle, &fhp->fh_handle);
}
if (attrmask[0] & (FATTR4_WORD0_CASE_INSENSITIVE |
FATTR4_WORD0_CASE_PRESERVING)) {
/*
+18 -12
View File
@@ -142,16 +142,15 @@ static inline __be32 check_pseudo_root(struct dentry *dentry,
/* Size of a file handle MAC, in 4-octet words */
#define FH_MAC_WORDS (sizeof(__le64) / 4)
static bool fh_append_mac(struct svc_fh *fhp, struct net *net)
bool fh_append_mac(struct knfsd_fh *fh, int fh_maxsize, struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
struct knfsd_fh *fh = &fhp->fh_handle;
siphash_key_t *fh_key = nn->fh_key;
__le64 hash;
if (!fh_key)
goto out_no_key;
if (fh->fh_size + sizeof(hash) > fhp->fh_maxsize)
if (fh->fh_size + sizeof(hash) > fh_maxsize)
goto out_no_space;
hash = cpu_to_le64(siphash(&fh->fh_raw, fh->fh_size, fh_key));
@@ -165,7 +164,7 @@ out_no_key:
out_no_space:
pr_warn_ratelimited("NFSD: unable to sign filehandles, fh_size %zu would be greater than fh_maxsize %d.\n",
fh->fh_size + sizeof(hash), fhp->fh_maxsize);
fh->fh_size + sizeof(hash), fh_maxsize);
return false;
}
@@ -564,7 +563,8 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
fhp->fh_handle.fh_size += maxsize * 4;
if (exp->ex_flags & NFSEXP_SIGN_FH)
if (!fh_append_mac(fhp, exp->cd->net))
if (!fh_append_mac(&fhp->fh_handle, fhp->fh_maxsize,
exp->cd->net))
fhp->fh_handle.fh_fileid_type = FILEID_INVALID;
} else {
fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
@@ -894,19 +894,20 @@ char * SVCFH_fmt(struct svc_fh *fhp)
return buf;
}
enum fsid_source fsid_source(const struct svc_fh *fhp)
enum fsid_source fsid_source_fh(const struct knfsd_fh *fh,
struct svc_export *exp)
{
if (fhp->fh_handle.fh_version != 1)
if (fh->fh_version != 1)
return FSIDSOURCE_DEV;
switch(fhp->fh_handle.fh_fsid_type) {
switch (fh->fh_fsid_type) {
case FSID_DEV:
case FSID_ENCODE_DEV:
case FSID_MAJOR_MINOR:
if (exp_sb(fhp->fh_export)->s_type->fs_flags & FS_REQUIRES_DEV)
if (exp_sb(exp)->s_type->fs_flags & FS_REQUIRES_DEV)
return FSIDSOURCE_DEV;
break;
case FSID_NUM:
if (fhp->fh_export->ex_flags & NFSEXP_FSID)
if (exp->ex_flags & NFSEXP_FSID)
return FSIDSOURCE_FSID;
break;
default:
@@ -915,13 +916,18 @@ enum fsid_source fsid_source(const struct svc_fh *fhp)
/* either a UUID type filehandle, or the filehandle doesn't
* match the export.
*/
if (fhp->fh_export->ex_flags & NFSEXP_FSID)
if (exp->ex_flags & NFSEXP_FSID)
return FSIDSOURCE_FSID;
if (fhp->fh_export->ex_uuid)
if (exp->ex_uuid)
return FSIDSOURCE_UUID;
return FSIDSOURCE_DEV;
}
enum fsid_source fsid_source(const struct svc_fh *fhp)
{
return fsid_source_fh(&fhp->fh_handle, fhp->fh_export);
}
/**
* nfsd4_change_attribute - Generate an NFSv4 change_attribute value
* @stat: inode attributes
+3
View File
@@ -131,6 +131,8 @@ enum fsid_source {
FSIDSOURCE_FSID,
FSIDSOURCE_UUID,
};
extern enum fsid_source fsid_source_fh(const struct knfsd_fh *fh,
struct svc_export *exp);
extern enum fsid_source fsid_source(const struct svc_fh *fhp);
@@ -226,6 +228,7 @@ __be32 fh_getattr(const struct svc_fh *fhp, struct kstat *stat);
__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
__be32 fh_update(struct svc_fh *);
void fh_put(struct svc_fh *);
bool fh_append_mac(struct knfsd_fh *fh, int fh_maxsize, struct net *net);
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, const struct svc_fh *src)