| /* |
| * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. |
| * Written by David Howells (dhowells@redhat.com) |
| */ |
| #include <linux/nfs_fs.h> |
| #include <linux/nfs_idmap.h> |
| #include <linux/sunrpc/auth.h> |
| #include <linux/sunrpc/xprt.h> |
| #include <linux/sunrpc/bc_xprt.h> |
| #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); |
| } |