/* * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) */ #include #include #include #include #include #include "internal.h" #include "callback.h" #define NFSDBG_FACILITY NFSDBG_CLIENT /* * Initialize the NFS4 callback service */ static int nfs4_init_callback(struct nfs_client *clp) { int error; if (clp->rpc_ops->version == 4) { struct rpc_xprt *xprt; xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); if (nfs4_has_session(clp)) { error = xprt_setup_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); if (error < 0) return error; } error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); if (error < 0) { dprintk("%s: failed to start callback. Error = %d\n", __func__, error); return error; } __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); } return 0; } /* * Initialize the minor version specific parts of an NFS4 client record */ static int nfs4_init_client_minor_version(struct nfs_client *clp) { #if defined(CONFIG_NFS_V4_1) if (clp->cl_mvops->minor_version) { struct nfs4_session *session = NULL; /* * Create the session and mark it expired. * When a SEQUENCE operation encounters the expired session * it will do session recovery to initialize it. */ session = nfs4_alloc_session(clp); if (!session) return -ENOMEM; clp->cl_session = session; /* * The create session reply races with the server back * channel probe. Mark the client NFS_CS_SESSION_INITING * so that the client back channel can find the * nfs_client struct */ nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING); } #endif /* CONFIG_NFS_V4_1 */ return nfs4_init_callback(clp); } /** * nfs4_init_client - Initialise an NFS4 client record * * @clp: nfs_client to initialise * @timeparms: timeout parameters for underlying RPC transport * @ip_addr: callback IP address in presentation format * @authflavor: authentication flavor for underlying RPC transport * * Returns pointer to an NFS client, or an ERR_PTR value. */ struct nfs_client *nfs4_init_client(struct nfs_client *clp, const struct rpc_timeout *timeparms, const char *ip_addr, rpc_authflavor_t authflavour) { char buf[INET6_ADDRSTRLEN + 1]; int error; if (clp->cl_cons_state == NFS_CS_READY) { /* the client is initialised already */ dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); return clp; } /* Check NFS protocol revision and initialize RPC op vector */ clp->rpc_ops = &nfs_v4_clientops; __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); error = nfs_create_rpc_client(clp, timeparms, authflavour); if (error < 0) goto error; /* If no clientaddr= option was specified, find a usable cb address */ if (ip_addr == NULL) { struct sockaddr_storage cb_addr; struct sockaddr *sap = (struct sockaddr *)&cb_addr; error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); if (error < 0) goto error; error = rpc_ntop(sap, buf, sizeof(buf)); if (error < 0) goto error; ip_addr = (const char *)buf; } strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); error = nfs_idmap_new(clp); if (error < 0) { dprintk("%s: failed to create idmapper. Error = %d\n", __func__, error); goto error; } __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); error = nfs4_init_client_minor_version(clp); if (error < 0) goto error; if (!nfs4_has_session(clp)) nfs_mark_client_ready(clp, NFS_CS_READY); return clp; error: nfs_mark_client_ready(clp, error); nfs_put_client(clp); dprintk("<-- nfs4_init_client() = xerror %d\n", error); return ERR_PTR(error); }