SUNRPC: Move upcall out of auth->au_ops->crcreate()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 1 Feb 2006 17:19:27 +0000 (12:19 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 1 Feb 2006 17:52:25 +0000 (12:52 -0500)
 This fixes a bug whereby if two processes try to look up the same auth_gss
 credential, they may end up creating two creds, and triggering two upcalls
 because the upcall is performed before the credential is added to the
 credcache.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
include/linux/sunrpc/auth.h
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c

index bfc5fb27953949edc244f0b8228701b8f047917c..2647798b72c7621123bcaa7ce394408624b1e6e0 100644 (file)
@@ -110,6 +110,7 @@ struct rpc_authops {
 
 struct rpc_credops {
        const char *            cr_name;        /* Name of the auth flavour */
+       int                     (*cr_init)(struct rpc_auth *, struct rpc_cred *);
        void                    (*crdestroy)(struct rpc_cred *);
 
        int                     (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
index 1ca89c36da7abaa629e5485b0b04ca25afe42a69..8d6f1a176b159f9ee1a989dd0803fc0d5eb5d2d0 100644 (file)
@@ -232,6 +232,14 @@ retry:
                        goto retry;
                } else
                        cred = new;
+       } else if ((cred->cr_flags & RPCAUTH_CRED_NEW)
+                       && cred->cr_ops->cr_init != NULL
+                       && !(flags & RPCAUTH_LOOKUP_NEW)) {
+               int res = cred->cr_ops->cr_init(auth, cred);
+               if (res < 0) {
+                       put_rpccred(cred);
+                       cred = ERR_PTR(res);
+               }
        }
 
        return (struct rpc_cred *) cred;
index 03affcbf6292b69dfe821cbea0998de2841a9a12..bb46efd92e5723475b3dd1c1cbf38f78c2af7c82 100644 (file)
@@ -788,15 +788,6 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
        cred->gc_base.cr_ops = &gss_credops;
        cred->gc_base.cr_flags = RPCAUTH_CRED_NEW;
        cred->gc_service = gss_auth->service;
-       /* Is the caller prepared to initialise the credential? */
-       if (flags & RPCAUTH_LOOKUP_NEW)
-               goto out;
-       do {
-               err = gss_create_upcall(gss_auth, cred);
-       } while (err == -EAGAIN);
-       if (err < 0)
-               goto out_err;
-out:
        return &cred->gc_base;
 
 out_err:
@@ -805,6 +796,19 @@ out_err:
        return ERR_PTR(err);
 }
 
+static int
+gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+       struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+       struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base);
+       int err;
+
+       do {
+               err = gss_create_upcall(gss_auth, gss_cred);
+       } while (err == -EAGAIN);
+       return err;
+}
+
 static int
 gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
 {
@@ -1254,6 +1258,7 @@ static struct rpc_authops authgss_ops = {
 static struct rpc_credops gss_credops = {
        .cr_name        = "AUTH_GSS",
        .crdestroy      = gss_destroy_cred,
+       .cr_init        = gss_cred_init,
        .crmatch        = gss_match,
        .crmarshal      = gss_marshal,
        .crrefresh      = gss_refresh,