[pnfs] cl_ex_cred questions
William A. (Andy) Adamson
androsadamson at gmail.com
Wed Jun 4 11:18:48 EDT 2008
Hi Benny
Good review. Comments and an attached patch that I think fixes the
situation...
-->Andy
On Wed, Jun 4, 2008 at 7:44 AM, Benny Halevy <bhalevy at panasas.com> wrote:
> Hey Andy and Ricardo,
>
> While porting to 2.6.26 I looked into the renewal cred mechanism,
> originally introduced in these commits:
> c7f59a0f "nfs41: sessions exchange_id AUTH_SYS root cred"
OK, I find this commit in the current origin/nfs41 tree.
> c55e803a "nfs41: Move NULL credential checking from the reclaimer into
> nfs4_init_clientid()."
But I can't find this commit in the current origin/nfs41 tree. :(
> One problem I saw is that there seems to be a leak of the cred
> the caller passes establish_id().
>
> Previously, reclaimer() passed the creds down to nfs4_init_client
> and then dereferenced the cred using put_rpccred.
>
> Then, commit c55e803a moved the responsibility to call put_rpccred
> from the caller to the callee, via ops->establish_clid. *But*, only
> nfs4_init_clientid is doing that, not _nfs4_proc_exchange_id.
Yes for the renewal case. nfs4_proc_exchange_id differs from
nfs4_init_clientid in that the cred passed in is NULL in the initial case
(the non-renewal case). I'll address the renewal case below.
The cred is NULL in the initial case because the reclaimer calls two
functions to try and get a
cred for establish_clid , nfs4_get_renew_cred and
nfs4_get_setclientid_cred; both of these
functions search the struct nfs_client cl_state_owners list which is empty
in the case of exchange_id
and requires at least one cred in the case of nfs4_initclientid which calls
setclient_id which by design is not called until after the first OPEN.
>
> I think this is wrongly coded and the caller should put the creds
> it got. The callee can always take a ref count on the cred if
> it wishes to keep it (and using get_rpccred, not by atomic_inc of
> cr_count as currently coded).
In the initial case where the cred passed into nfs4_proc_exchange_id is
NULL, the rpc layer looks up the cred for the UID, gets/puts_rpccred.
In the renewal case, once we fix it (see below!), you are correct. we will
need to do a put_rpccred in the case when the cred passed to
nfs4_proc_exchange_id is not NULL.
>
> Second question is what creds should exchange_id use?
The creds that were used to mount - e.g. the creds mapped to UID 0. In the
AUTH_GSS case, I believe this means machine creds are required. mountd will
need to pass down AUTH_GSS creds (or the location of the creds via the
keyring) that map to UID 0. Until we have this functionality , only
AUTH_UNIX root credentials are supported.
>
> and what creds it should keep for renewal?
If by renewal you mean re-establishing a clientid via exchange_id, the same
creds - those used to mount.
Currently, it always uses the creds it received from the caller
> to send the exchange_id rpc
The rpc_cred pointer passed to _nfs4_proc_exchang_id is NULL in the
initial case. The rpc code sees the NULL cred, and calls
rpcauth_lookup_cred using the current UID which is 0 due to the fact that
this is the result of a mount system call. This will also work with
AUTH_GSS, since the UID 0 will be mapped to machine credentials.
and if it succeeded and
> clnt->cl_auth->au_flavor == RPC_AUTH_UNIX && current->fsuid == 0
> it gets a new set of creds using rpcauth_lookupcred.
Right. This code set up the 'renewal' cred for future re-establishment of
the clientid - e.g. resend of an exchange_id. When AUTH_GSS is supported,
the RPC_AUTH_UNIX check will be removed.
> Note that we take an extra ref count on these creds
nope. we get a count because we are keeping them around for renewal.
> and that seems to be yet another leak since it's being
> put only once in nfs_free_client...
which is the put that balances the get. so there is no leak here.
>
> Why do we need to call rpcauth_lookupcred(), why not
> just keep the creds used for the successful exchange_id?
rpcauth_lookupcred looks up the cached credential mapped to the UID. It's
just the official way to do the job. Note that the cred pointer passed into
the initial exchange_id is NULL, and therefore can't be used.
>
> What happens if cl_ex_cred is not NULL on entry to
> _nfs4_proc_exchange_id()? Can't this happen?
yes! But only for the nfs4_schedule_state_renewal() path (e.g. RENEWD) which
I'm not sure is even called for v4.1. The nfs4_schedule_state_recovery()
path is indeed broken. Good catch!
Here is where the commit c7f59a0f "nfs41:sessions exchange_id AUTH_SYS root
cred" had it right. it
replaced the nfs4_renew_state call to nfs4_get_state_renewal with a new
nfs4_state_maintenance_ops operation called get_state_renewal_cred which was
set to nfs4_get_state_renewal for v4.0 and to nfs41_get_state_renewal shown
below for v4.1.
+
+struct rpc_cred *
+nfs41_get_state_renewal_cred(struct nfs_client *clp)
+{
+ if (clp->cl_ex_cred)
+ get_rpccred(clp->cl_ex_cred);
+ return (clp->cl_ex_cred);
+}
+#endif /* CONFIG_NFS_V4_1 */
This change left all of the 'initial case' described above the same. In the
renewal case, the cl_ex_cred exists, and is passed into
nfs4_proc_exchange_id via the establish_clid operation.
But! this was only done for nfs4_renew_state(), not for the reclaimer. The
reclaimer is called via nfs4_schedule_state_recovery() which reclaims
delegations, locks, opens and is therefore needed by v4.1 as well.
So we need to replace the call to nfs4_get_renewal_state in the reclaimer
with a call to ops->get_renewal_state.
> Shouldn't we reuse it for sending the exchange_id?
With the above change, we will. We will also (as noted above) need to call
put_rpccred in this case.
> Also, we set cl_ex_cred unconditionally. If it wasn't
> null, we step on the previous value and YAL (yet another leak ;-)
This i agree with. we should not step on the previous value of cl_ex_cred.
>
> Last question is in case the auth_sys condition is false,
> cl_ex_creds may be left as NULL. Then what?
> get_state_renewal_cred will just return NULL and we might
> get into an endless renewal loop.
If the mount UID 0 doesn't map to any credential, the initial exchange_id
will fail. No infinite loop.
-->Andy
>
> Benny
> _______________________________________________
> pNFS mailing list
> pNFS at linux-nfs.org
> http://linux-nfs.org/cgi-bin/mailman/listinfo/pnfs
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://linux-nfs.org/pipermail/pnfs/attachments/20080604/4434485f/attachment-0001.htm
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-nfs41-fix-nfs4-state-recovery-credential.patch
Type: text/x-patch
Size: 2268 bytes
Desc: not available
Url : http://linux-nfs.org/pipermail/pnfs/attachments/20080604/4434485f/attachment-0001.bin
More information about the pNFS
mailing list