From 94a417f3d7a02478a2d7842e693a61339fb54ea4 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Wed, 1 Apr 2009 09:21:49 -0400 Subject: nfs41: nfs_client.cl_minorversion This field is set to the nfsv4 minor version for this mount. Signed-off-by: Benny Halevy Note: This patch sets the referral to the same minorversion as the current mount. Revisit in future patch. Signed-off-by: Andy Adamson [removed cl_minorversion assignment in nfs_set_client] Signed-off-by: Benny Halevy [always define nfs_client.cl_minorversion] Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 75c9cd2aa119..0efcb55c2caa 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1101,7 +1101,8 @@ static int nfs4_set_client(struct nfs_server *server, const size_t addrlen, const char *ip_addr, rpc_authflavor_t authflavour, - int proto, const struct rpc_timeout *timeparms) + int proto, const struct rpc_timeout *timeparms, + u32 minorversion) { struct nfs_client_initdata cl_init = { .hostname = hostname, @@ -1164,7 +1165,8 @@ static int nfs4_init_server(struct nfs_server *server, data->client_address, data->auth_flavors[0], data->nfs_server.protocol, - &timeparms); + &timeparms, + data->minorversion); if (error < 0) goto error; @@ -1282,7 +1284,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, parent_client->cl_ipaddr, data->authflavor, parent_server->client->cl_xprt->prot, - parent_server->client->cl_timeout); + parent_server->client->cl_timeout, + parent_client->cl_minorversion); if (error < 0) goto error; -- cgit v1.2.3 From 5aae4a9ae0dd55409a42ca61b82ef1f5a840091e Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Wed, 1 Apr 2009 09:21:50 -0400 Subject: nfs41: Use mount minorversion option Use the mount minorversion option to initialize the nfs_client cl_minorversion and match it in nfs_match_client() when looking up a nfs_client. [nfs41: remove ifdefs around nfs_client_initdata.minorversion] Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 0efcb55c2caa..a736160046c3 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -102,6 +102,7 @@ struct nfs_client_initdata { size_t addrlen; const struct nfs_rpc_ops *rpc_ops; int proto; + u32 minorversion; }; /* @@ -150,6 +151,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); clp->cl_boot_time = CURRENT_TIME; clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; + clp->cl_minorversion = cl_init->minorversion; #endif cred = rpc_lookup_machine_cred(); if (!IS_ERR(cred)) @@ -420,7 +422,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat if (clp->cl_proto != data->proto) continue; - + /* Match nfsv4 minorversion */ + if (clp->cl_minorversion != data->minorversion) + continue; /* Match the full socket address */ if (!nfs_sockaddr_cmp(sap, clap)) continue; @@ -1110,6 +1114,7 @@ static int nfs4_set_client(struct nfs_server *server, .addrlen = addrlen, .rpc_ops = &nfs_v4_clientops, .proto = proto, + .minorversion = minorversion, }; struct nfs_client *clp; int error; -- cgit v1.2.3 From 557134a39c8d2ab79d8b8d53438e03e29feb5ec4 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 1 Apr 2009 09:21:53 -0400 Subject: nfs41: sessions client infrastructure NFSv4.1 Sessions basic data types, initialization, and destruction. The session is always associated with a struct nfs_client that holds the exchange_id results. Signed-off-by: Rahul Iyer Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [remove extraneous rpc_clnt pointer, use the struct nfs_client cl_rpcclient. remove the rpc_clnt parameter from nfs4 nfs4_init_session] Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [Use the presence of a session to determine behaviour instead of the minorversion number.] Signed-off-by: Andy Adamson [constified nfs4_has_session's struct nfs_client parameter] Signed-off-by: Benny Halevy [Rename nfs4_put_session() to nfs4_destroy_session() and call it from nfs4_free_client() not nfs4_free_server(). Also get rid of nfs4_get_session() and the ref_count in nfs4_session struct as keeping track of nfs_client should be sufficient] Signed-off-by: Alexandros Batsakis [nfs41: pass rsize and wsize into nfs4_init_session] Signed-off-by: Andy Adamson [separated out removal of rpc_clnt parameter from nfs4_init_session ot a patch of its own] Signed-off-by: Benny Halevy [Pass the nfs_client pointer into nfs4_alloc_session] Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [nfs41: don't assign to session->clp->cl_session in nfs4_destroy_session] [nfs41: fixup nfs4_clear_client_minor_version] [introduce nfs4_clear_client_minor_version() in this patch] Signed-off-by: Benny Halevy [Refactor nfs4_init_session] Moved session allocation into nfs4_init_client_minor_version, called from nfs4_init_client. Leave rwise and wsize initialization in nfs4_init_session, called from nfs4_init_server. Reverted moving of nfs_fsid definition to nfs_fs_sb.h Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [nfs41: Move NFS4_MAX_SLOT_TABLE define from under CONFIG_NFS_V4_1] [Fix comile error when CONFIG_NFS_V4_1 is not set.] Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [moved nfs4_init_slot_table definition to "create_session operation"] Signed-off-by: Benny Halevy [nfs41: alloc session with GFP_KERNEL] Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a736160046c3..f1506f148521 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -183,6 +183,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp) #endif } +/* + * Clears/puts all minor version specific parts from an nfs_client struct + * reverting it to minorversion 0. + */ +static void nfs4_clear_client_minor_version(struct nfs_client *clp) +{ +#ifdef CONFIG_NFS_V4_1 + if (nfs4_has_session(clp)) { + nfs4_destroy_session(clp->cl_session); + clp->cl_session = NULL; + } +#endif /* CONFIG_NFS_V4_1 */ +} + /* * Destroy a shared client record */ @@ -190,6 +204,7 @@ static void nfs_free_client(struct nfs_client *clp) { dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); + nfs4_clear_client_minor_version(clp); nfs4_shutdown_client(clp); nfs_fscache_release_client_cookie(clp); @@ -1053,6 +1068,30 @@ error: } #ifdef CONFIG_NFS_V4 +/* + * 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_minorversion) { + 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; + } +#endif /* CONFIG_NFS_V4_1 */ + + return 0; +} + /* * Initialise an NFS4 client record */ @@ -1087,6 +1126,10 @@ static int nfs4_init_client(struct nfs_client *clp, } __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); + error = nfs4_init_client_minor_version(clp); + if (error < 0) + goto error; + nfs_mark_client_ready(clp, NFS_CS_READY); return 0; @@ -1143,6 +1186,21 @@ error: return error; } +/* + * Initialize a session. + * Note: save the mount rsize and wsize for create_server negotiation. + */ +static void nfs4_init_session(struct nfs_client *clp, + unsigned int wsize, unsigned int rsize) +{ +#if defined(CONFIG_NFS_V4_1) + if (nfs4_has_session(clp)) { + clp->cl_session->fc_attrs.max_rqst_sz = wsize; + clp->cl_session->fc_attrs.max_resp_sz = rsize; + } +#endif /* CONFIG_NFS_V4_1 */ +} + /* * Create a version 4 volume record */ @@ -1221,6 +1279,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, BUG_ON(!server->nfs_client->rpc_ops); BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); + nfs4_init_session(server->nfs_client, server->wsize, server->rsize); + /* Probe the root fh to retrieve its FSID */ error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); if (error < 0) -- cgit v1.2.3 From cccef3b96a4759ae0790452280c00ea505412157 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 1 Apr 2009 09:22:03 -0400 Subject: nfs41: introduce nfs4_call_sync Use nfs4_call_sync rather than rpc_call_sync to provide for a nfs41 sessions-enabled interface for sessions manipulation. The nfs41 rpc logic uses the rpc_call_prepare method to recover and create the session, as well as selecting a free slot id and the rpc_call_done to free the slot and update slot table related metadata. In the coming patches we'll add rpc prepare and done routines for setting up the sequence op and processing the sequence result. Signed-off-by: Benny Halevy [nfs41: nfs4_call_sync] As per 11-14-08 review. Squash into "nfs41: introduce nfs4_call_sync" and "nfs41: nfs4_setup_sequence" Define two functions one for v4 and one for v41 add a pointer to struct nfs4_client to the correct one. Signed-off-by: Andy Adamson [added BUG() in _nfs4_call_sync_session if !CONFIG_NFS_V4_1] Signed-off-by: Benny Halevy [nfs41: check for session not minorversion] Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [group minorversion specific stuff together] Signed-off-by: Alexandros Batsakis Signed-off-by: Benny Halevy Signed-off-by: Andy Adamson [nfs41: fixup nfs4_clear_client_minor_version] [introduce nfs4_init_client_minor_version() in this patch] Signed-off-by: Benny Halevy [cleaned-up patch: got rid of nfs_call_sync_t, dprintks, cosmetics, extra server defs] Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index f1506f148521..a9828baaa445 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -194,6 +194,8 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) nfs4_destroy_session(clp->cl_session); clp->cl_session = NULL; } + + clp->cl_call_sync = _nfs4_call_sync; #endif /* CONFIG_NFS_V4_1 */ } @@ -1073,6 +1075,8 @@ error: */ static int nfs4_init_client_minor_version(struct nfs_client *clp) { + clp->cl_call_sync = _nfs4_call_sync; + #if defined(CONFIG_NFS_V4_1) if (clp->cl_minorversion) { struct nfs4_session *session = NULL; @@ -1086,6 +1090,7 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) return -ENOMEM; clp->cl_session = session; + clp->cl_call_sync = _nfs4_call_sync_session; } #endif /* CONFIG_NFS_V4_1 */ -- cgit v1.2.3 From 96b09e024fedf0a6604c8c688a3994d5ed991434 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 1 Apr 2009 09:22:33 -0400 Subject: nfs41: use session attributes for rsize and wsize Set the mount points rsize and wsize to the negotiated session fore channel maximum response and requeset size. These values will be bound checked in nfs_server_set_fsinfo. Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [move nfs4_session_set_rwsize into CONFIG_NFS_V4] Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index a9828baaa445..bb7432d83b5a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1206,6 +1206,21 @@ static void nfs4_init_session(struct nfs_client *clp, #endif /* CONFIG_NFS_V4_1 */ } +/* + * Session has been established, and the client marked ready. + * Set the mount rsize and wsize with negotiated fore channel + * attributes which will be bound checked in nfs_server_set_fsinfo. + */ +static void nfs4_session_set_rwsize(struct nfs_server *server) +{ +#ifdef CONFIG_NFS_V4_1 + if (!nfs4_has_session(server->nfs_client)) + return; + server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz; + server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz; +#endif /* CONFIG_NFS_V4_1 */ +} + /* * Create a version 4 volume record */ @@ -1296,6 +1311,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, (unsigned long long) server->fsid.minor); dprintk("Mount FH: %d\n", mntfh->size); + nfs4_session_set_rwsize(server); + error = nfs_probe_fsinfo(server, mntfh, &fattr); if (error < 0) goto error; -- cgit v1.2.3 From 76db6d9500caeaa774a3e32a997eba30bbdc176b Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 1 Apr 2009 09:22:38 -0400 Subject: nfs41: add session setup to the state manager At mount, nfs_alloc_client sets the cl_state NFS4CLNT_LEASE_EXPIRED bit and nfs4_alloc_session sets the NFS4CLNT_SESSION_SETUP bit, so both bits are set when nfs4_lookup_root calls nfs4_recover_expired_lease which schedules the nfs4_state_manager and waits for it to complete. Place the session setup after the clientid establishment in nfs4_state_manager so that the session is setup right after the clientid has been established without rescheduling the state manager. Unlike nfsv4.0, the nfs_client struct is not ready to use until the session has been established. Postpone marking the nfs_client struct to NFS_CS_READY until after a successful CREATE_SESSION call so that other threads cannot use the client until the session is established. If the EXCHANGE_ID call fails and the session has not been setup (the NFS4CLNT_SESSION_SETUP bit is set), mark the client with the error and return. If the session setup CREATE_SESSION call fails with NFS4ERR_STALE_CLIENTID which could occur due to server reboot or network partition inbetween the EXCHANGE_ID and CREATE_SESSION call, reset the NFS4CLNT_LEASE_EXPIRED and NFS4CLNT_SESSION_SETUP bits and try again. If the CREATE_SESSION call fails with other errors, mark the client with the error and return. Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [nfs41: NFS_CS_SESSION_SETUP cl_cons_state for back channel setup] On session setup, the CREATE_SESSION reply races with the server back channel probe which needs to succeed to setup the back channel. Set a new cl_cons_state NFS_CS_SESSION_SETUP just prior to the CREATE_SESSION call and add it as a valid state to nfs_find_client so that the client back channel can find the nfs_client struct and won't drop the server backchannel probe. Use a new cl_cons_state so that NFSv4.0 back channel behaviour which only sets NFS_CS_READY is unchanged. Adjust waiting on the nfs_client_active_wq accordingly. Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [nfs41: rename NFS_CS_SESSION_SETUP to NFS_CS_SESSION_INITING] Signed-off-by: Andy Adamson [nfs41: set NFS_CL_SESSION_INITING in alloc_session] Signed-off-by: Andy Adamson [nfs41: move session setup into a function] Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [moved nfs4_proc_create_session declaration here] Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index bb7432d83b5a..d28a987f569e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -366,7 +366,8 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; /* Don't match clients that failed to initialise properly */ - if (clp->cl_cons_state != NFS_CS_READY) + if (!(clp->cl_cons_state == NFS_CS_READY || + clp->cl_cons_state == NFS_CS_SESSION_INITING)) continue; /* Different NFS versions cannot share the same nfs_client */ @@ -499,7 +500,7 @@ found_client: nfs_free_client(new); error = wait_event_killable(nfs_client_active_wq, - clp->cl_cons_state != NFS_CS_INITING); + clp->cl_cons_state < NFS_CS_INITING); if (error < 0) { nfs_put_client(clp); return ERR_PTR(-ERESTARTSYS); @@ -520,7 +521,7 @@ found_client: /* * Mark a server as ready or failed */ -static void nfs_mark_client_ready(struct nfs_client *clp, int state) +void nfs_mark_client_ready(struct nfs_client *clp, int state) { clp->cl_cons_state = state; wake_up_all(&nfs_client_active_wq); @@ -1135,7 +1136,8 @@ static int nfs4_init_client(struct nfs_client *clp, if (error < 0) goto error; - nfs_mark_client_ready(clp, NFS_CS_READY); + if (!nfs4_has_session(clp)) + nfs_mark_client_ready(clp, NFS_CS_READY); return 0; error: -- cgit v1.2.3 From 008f55d0e019943323c20a03493a2ba5672a4cc8 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Wed, 1 Apr 2009 09:22:50 -0400 Subject: nfs41: recover lease in _nfs4_lookup_root This creates the nfsv4.1 session on mount. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d28a987f569e..3e232bf56dfb 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -527,6 +527,22 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state) wake_up_all(&nfs_client_active_wq); } +/* + * With sessions, the client is not marked ready until after a + * successful EXCHANGE_ID and CREATE_SESSION. + * + * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate + * other versions of NFS can be tried. + */ +int nfs4_check_client_ready(struct nfs_client *clp) +{ + if (!nfs4_has_session(clp)) + return 0; + if (clp->cl_cons_state < NFS_CS_READY) + return -EPROTONOSUPPORT; + return 0; +} + /* * Initialise the timeout values for a connection */ -- cgit v1.2.3 From 9bdaa86d2a4cbf9a71de3048c0c0a874e7ebc8ad Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Wed, 1 Apr 2009 09:22:55 -0400 Subject: nfs41: Refactor nfs4_{init,destroy}_callback for nfs4.0 Refactor-out code to bring the callback service up and down. Signed-off-by: Benny Halevy --- fs/nfs/client.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 3e232bf56dfb..d9657d455730 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -47,6 +47,9 @@ #include "internal.h" #include "fscache.h" +static int nfs4_init_callback(struct nfs_client *); +static void nfs4_destroy_callback(struct nfs_client *); + #define NFSDBG_FACILITY NFSDBG_CLIENT static DEFINE_SPINLOCK(nfs_client_lock); @@ -121,11 +124,8 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ clp->rpc_ops = cl_init->rpc_ops; - if (cl_init->rpc_ops->version == 4) { - if (nfs_callback_up() < 0) - goto error_2; - __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); - } + if (nfs4_init_callback(clp) < 0) + goto error_2; atomic_set(&clp->cl_count, 1); clp->cl_cons_state = NFS_CS_INITING; @@ -162,8 +162,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ return clp; error_3: - if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) - nfs_callback_down(); + nfs4_destroy_callback(clp); error_2: kfree(clp); error_0: @@ -183,6 +182,17 @@ static void nfs4_shutdown_client(struct nfs_client *clp) #endif } +/* + * Destroy the NFS4 callback service + */ +static void nfs4_destroy_callback(struct nfs_client *clp) +{ +#ifdef CONFIG_NFS_V4 + if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) + nfs_callback_down(); +#endif /* CONFIG_NFS_V4 */ +} + /* * Clears/puts all minor version specific parts from an nfs_client struct * reverting it to minorversion 0. @@ -215,8 +225,7 @@ static void nfs_free_client(struct nfs_client *clp) if (!IS_ERR(clp->cl_rpcclient)) rpc_shutdown_client(clp->cl_rpcclient); - if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) - nfs_callback_down(); + nfs4_destroy_callback(clp); if (clp->cl_machine_cred != NULL) put_rpccred(clp->cl_machine_cred); @@ -1087,6 +1096,25 @@ error: } #ifdef CONFIG_NFS_V4 +/* + * Initialize the NFS4 callback service + */ +static int nfs4_init_callback(struct nfs_client *clp) +{ + int error; + + if (clp->rpc_ops->version == 4) { + error = nfs_callback_up(); + 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 */ -- cgit v1.2.3 From 7146851376861fe55c7a48ac8fc1354a5fff6cd0 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Wed, 1 Apr 2009 09:22:56 -0400 Subject: nfs41: minorversion support for nfs4_{init,destroy}_callback move nfs4_init_callback into nfs4_init_client_minor_version and nfs4_destroy_callback into nfs4_clear_client_minor_version as these need to happen also when auto-negotiating the minorversion once the callback service for nfs41 becomes different than for nfs4.0 Signed-off-by: Benny Halevy [nfs41: Fix checkpatch warning] Signed-off-by: Ricardo Labiaga Signed-off-by: Benny Halevy [Type check arguments of nfs_callback_up] Signed-off-by: Ricardo Labiaga Signed-off-by: Benny Halevy [nfs41: Backchannel: Remove FIXME comment] Signed-off-by: Ricardo Labiaga Signed-off-by: Benny Halevy --- fs/nfs/client.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d9657d455730..df2b40d1883d 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -47,9 +47,6 @@ #include "internal.h" #include "fscache.h" -static int nfs4_init_callback(struct nfs_client *); -static void nfs4_destroy_callback(struct nfs_client *); - #define NFSDBG_FACILITY NFSDBG_CLIENT static DEFINE_SPINLOCK(nfs_client_lock); @@ -124,9 +121,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ clp->rpc_ops = cl_init->rpc_ops; - if (nfs4_init_callback(clp) < 0) - goto error_2; - atomic_set(&clp->cl_count, 1); clp->cl_cons_state = NFS_CS_INITING; @@ -136,7 +130,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ if (cl_init->hostname) { clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); if (!clp->cl_hostname) - goto error_3; + goto error_cleanup; } INIT_LIST_HEAD(&clp->cl_superblocks); @@ -161,9 +155,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ return clp; -error_3: - nfs4_destroy_callback(clp); -error_2: +error_cleanup: kfree(clp); error_0: return NULL; @@ -207,6 +199,8 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) clp->cl_call_sync = _nfs4_call_sync; #endif /* CONFIG_NFS_V4_1 */ + + nfs4_destroy_callback(clp); } /* @@ -225,8 +219,6 @@ static void nfs_free_client(struct nfs_client *clp) if (!IS_ERR(clp->cl_rpcclient)) rpc_shutdown_client(clp->cl_rpcclient); - nfs4_destroy_callback(clp); - if (clp->cl_machine_cred != NULL) put_rpccred(clp->cl_machine_cred); @@ -1104,7 +1096,8 @@ static int nfs4_init_callback(struct nfs_client *clp) int error; if (clp->rpc_ops->version == 4) { - error = nfs_callback_up(); + error = nfs_callback_up(clp->cl_minorversion, + clp->cl_rpcclient->cl_xprt); if (error < 0) { dprintk("%s: failed to start callback. Error = %d\n", __func__, error); @@ -1139,7 +1132,7 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) } #endif /* CONFIG_NFS_V4_1 */ - return 0; + return nfs4_init_callback(clp); } /* -- cgit v1.2.3 From e82dc22dac6525a2f365a1d53c0483252d4aa38e Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 1 Apr 2009 09:23:14 -0400 Subject: nfs41: Allow NFSv4 and NFSv4.1 callback services to coexist Tracks the nfs_callback_info for both versions, enabling the callback service for v4 and v4.1 to run concurrently and be stopped independently of each other. Signed-off-by: Ricardo Labiaga Signed-off-by: Benny Halevy --- fs/nfs/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index df2b40d1883d..ac6575c4da31 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -181,7 +181,7 @@ static void nfs4_destroy_callback(struct nfs_client *clp) { #ifdef CONFIG_NFS_V4 if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) - nfs_callback_down(); + nfs_callback_down(clp->cl_minorversion); #endif /* CONFIG_NFS_V4 */ } -- cgit v1.2.3 From 0b5b7ae0a853c91015bb3b1729166ca65f693322 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 1 Apr 2009 09:23:15 -0400 Subject: nfs41: Setup the backchannel The NFS v4.1 callback service has already been setup, and rpc_xprt->serv points to the svc_serv structure describing it. Invoke the xprt_setup_backchannel() initialization to pre- allocate the necessary backchannel structures. Signed-off-by: Ricardo Labiaga Signed-off-by: Benny Halevy [nfs41: change nfs4_put_session(nfs4_session**) to nfs4_destroy_session(nfs_session*)] Signed-off-by: Alexandros Batsakis Signed-off-by: Benny Halevy [moved xprt_setup_backchannel from nfs4_init_session to nfs4_init_backchannel] Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy --- fs/nfs/client.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ac6575c4da31..4f75ec593be8 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -1096,6 +1097,14 @@ static int nfs4_init_callback(struct nfs_client *clp) int error; if (clp->rpc_ops->version == 4) { + if (nfs4_has_session(clp)) { + error = xprt_setup_backchannel( + clp->cl_rpcclient->cl_xprt, + NFS41_BC_MIN_CALLBACKS); + if (error < 0) + return error; + } + error = nfs_callback_up(clp->cl_minorversion, clp->cl_rpcclient->cl_xprt); if (error < 0) { -- cgit v1.2.3 From a21bdd9b960ccce421b63aa0e3efda4fcdc26f10 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 17 Jun 2009 18:02:10 -0700 Subject: NFS: Return error code from nfs_callback_up() to user space If the kernel cannot start the NFSv4 callback service during a mount request, it returns -ENOMEM to user space, resulting in this message: mount.nfs4: Cannot allocate memory Adjust nfs_alloc_client() and nfs_get_client() to pass NFSv4 callback start-up errors back to user space so a less mysterious error message can be displayed by the mount command. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'fs/nfs/client.c') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 75c9cd2aa119..0e9a1f9743b0 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -114,6 +114,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ { struct nfs_client *clp; struct rpc_cred *cred; + int err = -ENOMEM; if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) goto error_0; @@ -121,7 +122,8 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ clp->rpc_ops = cl_init->rpc_ops; if (cl_init->rpc_ops->version == 4) { - if (nfs_callback_up() < 0) + err = nfs_callback_up(); + if (err < 0) goto error_2; __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); } @@ -133,6 +135,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ clp->cl_addrlen = cl_init->addrlen; if (cl_init->hostname) { + err = -ENOMEM; clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); if (!clp->cl_hostname) goto error_3; @@ -165,7 +168,7 @@ error_3: error_2: kfree(clp); error_0: - return NULL; + return ERR_PTR(err); } static void nfs4_shutdown_client(struct nfs_client *clp) @@ -456,9 +459,10 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in spin_unlock(&nfs_client_lock); new = nfs_alloc_client(cl_init); - } while (new); + } while (!IS_ERR(new)); - return ERR_PTR(-ENOMEM); + dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new)); + return new; /* install a new client and return with it unready */ install_client: -- cgit v1.2.3