Commit 5e66d2d9 authored by NeilBrown's avatar NeilBrown Committed by Anna Schumaker
Browse files

nfsd: factor out __fh_verify to allow NULL rqstp to be passed



__fh_verify() offers an interface like fh_verify() but doesn't require
a struct svc_rqst *, instead it also takes the specific parts as
explicit required arguments.  So it is safe to call __fh_verify() with
a NULL rqstp, but the net, cred, and client args must not be NULL.

__fh_verify() does not use SVC_NET(), nor does the functions it calls.

Rather than using rqstp->rq_client pass the client and gssclient
explicitly to __fh_verify and then to nfsd_set_fh_dentry().

Lastly, it should be noted that the previous commit prepared for 4
associated tracepoints to only be used if rqstp is not NULL (this is a
stop-gap that should be properly fixed so localio also benefits from
the utility these tracepoints provide when debugging fh_verify
issues).

Signed-off-by: default avatarNeilBrown <neilb@suse.de>
Co-developed-by: default avatarMike Snitzer <snitzer@kernel.org>
Signed-off-by: default avatarMike Snitzer <snitzer@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarAnna Schumaker <anna.schumaker@oracle.com>
parent 71c61a00
Loading
Loading
Loading
Loading
+60 −31
Original line number Diff line number Diff line
@@ -142,7 +142,11 @@ static inline __be32 check_pseudo_root(struct dentry *dentry,
 * dentry.  On success, the results are used to set fh_export and
 * fh_dentry.
 */
static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct net *net,
				 struct svc_cred *cred,
				 struct auth_domain *client,
				 struct auth_domain *gssclient,
				 struct svc_fh *fhp)
{
	struct knfsd_fh	*fh = &fhp->fh_handle;
	struct fid *fid = NULL;
@@ -184,8 +188,8 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
	data_left -= len;
	if (data_left < 0)
		return error;
	exp = rqst_exp_find(&rqstp->rq_chandle, SVC_NET(rqstp),
			    rqstp->rq_client, rqstp->rq_gssclient,
	exp = rqst_exp_find(rqstp ? &rqstp->rq_chandle : NULL,
			    net, client, gssclient,
			    fh->fh_fsid_type, fh->fh_fsid);
	fid = (struct fid *)(fh->fh_fsid + len);

@@ -220,7 +224,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
		put_cred(override_creds(new));
		put_cred(new);
	} else {
		error = nfsd_setuser_and_check_port(rqstp, &rqstp->rq_cred, exp);
		error = nfsd_setuser_and_check_port(rqstp, cred, exp);
		if (error)
			goto out;
	}
@@ -295,42 +299,33 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
}

/**
 * fh_verify - filehandle lookup and access checking
 * @rqstp: pointer to current rpc request
 * __fh_verify - filehandle lookup and access checking
 * @rqstp: RPC transaction context, or NULL
 * @net: net namespace in which to perform the export lookup
 * @cred: RPC user credential
 * @client: RPC auth domain
 * @gssclient: RPC GSS auth domain, or NULL
 * @fhp: filehandle to be verified
 * @type: expected type of object pointed to by filehandle
 * @access: type of access needed to object
 *
 * Look up a dentry from the on-the-wire filehandle, check the client's
 * access to the export, and set the current task's credentials.
 *
 * Regardless of success or failure of fh_verify(), fh_put() should be
 * called on @fhp when the caller is finished with the filehandle.
 *
 * fh_verify() may be called multiple times on a given filehandle, for
 * example, when processing an NFSv4 compound.  The first call will look
 * up a dentry using the on-the-wire filehandle.  Subsequent calls will
 * skip the lookup and just perform the other checks and possibly change
 * the current task's credentials.
 *
 * @type specifies the type of object expected using one of the S_IF*
 * constants defined in include/linux/stat.h.  The caller may use zero
 * to indicate that it doesn't care, or a negative integer to indicate
 * that it expects something not of the given type.
 *
 * @access is formed from the NFSD_MAY_* constants defined in
 * fs/nfsd/vfs.h.
 * See fh_verify() for further descriptions of @fhp, @type, and @access.
 */
__be32
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
static __be32
__fh_verify(struct svc_rqst *rqstp,
	    struct net *net, struct svc_cred *cred,
	    struct auth_domain *client,
	    struct auth_domain *gssclient,
	    struct svc_fh *fhp, umode_t type, int access)
{
	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
	struct svc_export *exp = NULL;
	struct dentry	*dentry;
	__be32		error;

	if (!fhp->fh_dentry) {
		error = nfsd_set_fh_dentry(rqstp, fhp);
		error = nfsd_set_fh_dentry(rqstp, net, cred, client,
					   gssclient, fhp);
		if (error)
			goto out;
	}
@@ -359,7 +354,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
	if (error)
		goto out;

	error = nfsd_setuser_and_check_port(rqstp, &rqstp->rq_cred, exp);
	error = nfsd_setuser_and_check_port(rqstp, cred, exp);
	if (error)
		goto out;

@@ -389,7 +384,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)

skip_pseudoflavor_check:
	/* Finally, check access permissions. */
	error = nfsd_permission(&rqstp->rq_cred, exp, dentry, access);
	error = nfsd_permission(cred, exp, dentry, access);
out:
	trace_nfsd_fh_verify_err(rqstp, fhp, type, access, error);
	if (error == nfserr_stale)
@@ -397,6 +392,40 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
	return error;
}

/**
 * fh_verify - filehandle lookup and access checking
 * @rqstp: pointer to current rpc request
 * @fhp: filehandle to be verified
 * @type: expected type of object pointed to by filehandle
 * @access: type of access needed to object
 *
 * Look up a dentry from the on-the-wire filehandle, check the client's
 * access to the export, and set the current task's credentials.
 *
 * Regardless of success or failure of fh_verify(), fh_put() should be
 * called on @fhp when the caller is finished with the filehandle.
 *
 * fh_verify() may be called multiple times on a given filehandle, for
 * example, when processing an NFSv4 compound.  The first call will look
 * up a dentry using the on-the-wire filehandle.  Subsequent calls will
 * skip the lookup and just perform the other checks and possibly change
 * the current task's credentials.
 *
 * @type specifies the type of object expected using one of the S_IF*
 * constants defined in include/linux/stat.h.  The caller may use zero
 * to indicate that it doesn't care, or a negative integer to indicate
 * that it expects something not of the given type.
 *
 * @access is formed from the NFSD_MAY_* constants defined in
 * fs/nfsd/vfs.h.
 */
__be32
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
{
	return __fh_verify(rqstp, SVC_NET(rqstp), &rqstp->rq_cred,
			   rqstp->rq_client, rqstp->rq_gssclient,
			   fhp, type, access);
}

/*
 * Compose a file handle for an NFS reply.