return ret;
 }
 
+/**
+ * nfs_find_best_sec - Find a security mechanism supported locally
+ * @flavors: List of security tuples returned by SECINFO procedure
+ *
+ * Return the pseudoflavor of the first security mechanism in
+ * "flavors" that is locally supported.  Return RPC_AUTH_UNIX if
+ * no matching flavor is found in the array.  The "flavors" array
+ * is searched in the order returned from the server, per RFC 3530
+ * recommendation.
+ */
 rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
 {
-       struct gss_api_mech *mech;
-       struct xdr_netobj oid;
+       rpc_authflavor_t pseudoflavor;
+       struct nfs4_secinfo4 *secinfo;
        unsigned int i;
-       rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
 
        for (i = 0; i < flavors->num_flavors; i++) {
-               struct nfs4_secinfo4 *flavor = &flavors->flavors[i];
-
-               if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
-                       pseudoflavor = flavor->flavor;
-                       break;
-               } else if (flavor->flavor == RPC_AUTH_GSS) {
-                       oid.len  = flavor->flavor_info.oid.len;
-                       oid.data = flavor->flavor_info.oid.data;
-                       mech = gss_mech_get_by_OID(&oid);
-                       if (!mech)
-                               continue;
-                       pseudoflavor = gss_svc_to_pseudoflavor(mech,
-                                               flavor->flavor_info.service);
-                       gss_mech_put(mech);
+               secinfo = &flavors->flavors[i];
+
+               switch (secinfo->flavor) {
+               case RPC_AUTH_NULL:
+               case RPC_AUTH_UNIX:
+               case RPC_AUTH_GSS:
+                       pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
+                                                       &secinfo->flavor_info);
+                       if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
+                               return pseudoflavor;
                        break;
                }
        }
 
-       return pseudoflavor;
+       return RPC_AUTH_UNIX;
 }
 
 static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
 
 /* size of the nodename buffer */
 #define UNX_MAXNODENAME        32
 
+struct rpcsec_gss_info;
+
 /* Work around the lack of a VFS credential */
 struct auth_cred {
        kuid_t  uid;
        int                     (*pipes_create)(struct rpc_auth *);
        void                    (*pipes_destroy)(struct rpc_auth *);
        int                     (*list_pseudoflavors)(rpc_authflavor_t *, int);
+       rpc_authflavor_t        (*info2flavor)(struct rpcsec_gss_info *);
 };
 
 struct rpc_credops {
 int                    rpcauth_unregister(const struct rpc_authops *);
 struct rpc_auth *      rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
 void                   rpcauth_release(struct rpc_auth *);
+rpc_authflavor_t       rpcauth_get_pseudoflavor(rpc_authflavor_t,
+                               struct rpcsec_gss_info *);
 int                    rpcauth_list_flavors(rpc_authflavor_t *, int);
 struct rpc_cred *      rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
 void                   rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
 
 int gss_mech_register(struct gss_api_mech *);
 void gss_mech_unregister(struct gss_api_mech *);
 
-/* returns a mechanism descriptor given an OID, and increments the mechanism's
- * reference count. */
-struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
+/* Given a GSS security tuple, look up a pseudoflavor */
+rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
 
 /* Returns a reference to a mechanism, given a name like "krb5" etc. */
 struct gss_api_mech *gss_mech_get_by_name(const char *);
 
 }
 EXPORT_SYMBOL_GPL(rpcauth_unregister);
 
+/**
+ * rpcauth_get_pseudoflavor - check if security flavor is supported
+ * @flavor: a security flavor
+ * @info: a GSS mech OID, quality of protection, and service value
+ *
+ * Verifies that an appropriate kernel module is available or already loaded.
+ * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is
+ * not supported locally.
+ */
+rpc_authflavor_t
+rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
+{
+       const struct rpc_authops *ops;
+       rpc_authflavor_t pseudoflavor;
+
+       ops = auth_flavors[flavor];
+       if (ops == NULL)
+               request_module("rpc-auth-%u", flavor);
+       spin_lock(&rpc_authflavor_lock);
+       ops = auth_flavors[flavor];
+       if (ops == NULL || !try_module_get(ops->owner)) {
+               spin_unlock(&rpc_authflavor_lock);
+               return RPC_AUTH_MAXFLAVOR;
+       }
+       spin_unlock(&rpc_authflavor_lock);
+
+       pseudoflavor = flavor;
+       if (ops->info2flavor != NULL)
+               pseudoflavor = ops->info2flavor(info);
+
+       module_put(ops->owner);
+       return pseudoflavor;
+}
+EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
+
 /**
  * rpcauth_list_flavors - discover registered flavors and pseudoflavors
  * @array: array to fill in
 
        .pipes_create   = gss_pipes_dentries_create,
        .pipes_destroy  = gss_pipes_dentries_destroy,
        .list_pseudoflavors = gss_mech_list_pseudoflavors,
+       .info2flavor    = gss_mech_info2flavor,
 };
 
 static const struct rpc_credops gss_credops = {
 
 }
 EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
 
-struct gss_api_mech *
-gss_mech_get_by_OID(struct xdr_netobj *obj)
+static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
 {
        struct gss_api_mech     *pos, *gm = NULL;
 
        }
        spin_unlock(®istered_mechs_lock);
        return gm;
-
 }
 
-EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
-
 static inline int
 mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
 {
 }
 EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
 
+/**
+ * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
+ * @info: a GSS mech OID, quality of protection, and service value
+ *
+ * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
+ * not supported.
+ */
+rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
+{
+       rpc_authflavor_t pseudoflavor;
+       struct gss_api_mech *gm;
+
+       gm = gss_mech_get_by_OID(&info->oid);
+       if (gm == NULL)
+               return RPC_AUTH_MAXFLAVOR;
+
+       pseudoflavor = gss_svc_to_pseudoflavor(gm, info->service);
+
+       gss_mech_put(gm);
+       return pseudoflavor;
+}
+
 u32
 gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
 {