NFS: use scope from exchange_id to skip reclaim
authorWeston Andros Adamson <dros@netapp.com>
Tue, 31 May 2011 23:05:47 +0000 (19:05 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 12 Jul 2011 17:40:27 +0000 (13:40 -0400)
can be skipped if the "eir_server_scope" from the exchange_id proc differs from
previous calls.

Also, in the future server_scope will be useful for determining whether client
trunking is available

Signed-off-by: Weston Andros Adamson <dros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/client.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h

index b3dc2b88b65b139bae97fab53ad46be6b51846ab..006f8ff0a3c012ebddc86b6802be11337d6daf31 100644 (file)
@@ -293,6 +293,7 @@ static void nfs_free_client(struct nfs_client *clp)
        nfs4_deviceid_purge_client(clp);
 
        kfree(clp->cl_hostname);
+       kfree(clp->server_scope);
        kfree(clp);
 
        dprintk("<-- nfs_free_client()\n");
index c4a69833dd0d5b1abf3223e6e63f2153606ef9c5..b47f0d4710fa1f5ec38e585686b7a2d8ea37b2f2 100644 (file)
@@ -48,6 +48,7 @@ enum nfs4_client_state {
        NFS4CLNT_SESSION_RESET,
        NFS4CLNT_RECALL_SLOT,
        NFS4CLNT_LEASE_CONFIRM,
+       NFS4CLNT_SERVER_SCOPE_MISMATCH,
 };
 
 enum nfs4_session_state {
@@ -349,6 +350,8 @@ extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
 extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
 extern void nfs41_handle_recall_slot(struct nfs_client *clp);
+extern void nfs41_handle_server_scope(struct nfs_client *,
+                                     struct server_scope **);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
 extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t);
index 5879b23e0c99a1b0dfcff8c072bb0432ade497bf..5f4912f72282ec24771e6a92c5ea68423e723be2 100644 (file)
@@ -4781,6 +4781,16 @@ out_inval:
        return -NFS4ERR_INVAL;
 }
 
+static bool
+nfs41_same_server_scope(struct server_scope *a, struct server_scope *b)
+{
+       if (a->server_scope_sz == b->server_scope_sz &&
+           memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0)
+               return true;
+
+       return false;
+}
+
 /*
  * nfs4_proc_exchange_id()
  *
@@ -4823,9 +4833,31 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                                init_utsname()->domainname,
                                clp->cl_rpcclient->cl_auth->au_flavor);
 
+       res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL);
+       if (unlikely(!res.server_scope))
+               return -ENOMEM;
+
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        if (!status)
                status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
+
+       if (!status) {
+               if (clp->server_scope &&
+                   !nfs41_same_server_scope(clp->server_scope,
+                                            res.server_scope)) {
+                       dprintk("%s: server_scope mismatch detected\n",
+                               __func__);
+                       set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
+                       kfree(clp->server_scope);
+                       clp->server_scope = NULL;
+               }
+
+               if (!clp->server_scope)
+                       clp->server_scope = res.server_scope;
+               else
+                       kfree(res.server_scope);
+       }
+
        dprintk("<-- %s status= %d\n", __func__, status);
        return status;
 }
index e97dd219f84f4e205cf0a583fdb247d4ba01d807..5d744a52b4e1748dcf7d26a0d7be91143011d795 100644 (file)
@@ -1643,7 +1643,14 @@ static void nfs4_state_manager(struct nfs_client *clp)
                                goto out_error;
                        }
                        clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
-                       set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
+
+                       if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH,
+                                              &clp->cl_state))
+                               nfs4_state_start_reclaim_nograce(clp);
+                       else
+                               set_bit(NFS4CLNT_RECLAIM_REBOOT,
+                                       &clp->cl_state);
+
                        pnfs_destroy_all_layouts(clp);
                }
 
index e6e8f3b9a1dea29908a5179a38293dfbefce0ad8..1555c74dd33678e248aca23ab454ffe74832d17d 100644 (file)
@@ -4977,11 +4977,17 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        if (unlikely(status))
                return status;
 
-       /* Throw away server_scope */
+       /* Save server_scope */
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
                return status;
 
+       if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+               return -EIO;
+
+       memcpy(res->server_scope->server_scope, dummy_str, dummy);
+       res->server_scope->server_scope_sz = dummy;
+
        /* Throw away Implementation id array */
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
index 87694ca86914e379a098096fdd6989df71732a8f..f23b1883155980c22f40504927a7a881111344b6 100644 (file)
@@ -16,6 +16,7 @@ struct nfs4_sequence_args;
 struct nfs4_sequence_res;
 struct nfs_server;
 struct nfs4_minor_version_ops;
+struct server_scope;
 
 /*
  * The nfs_client identifies our client state to the server.
@@ -83,6 +84,8 @@ struct nfs_client {
 #ifdef CONFIG_NFS_FSCACHE
        struct fscache_cookie   *fscache;       /* client index cache cookie */
 #endif
+
+       struct server_scope     *server_scope;  /* from exchange_id */
 };
 
 /*
index 00848d86ffb250fe50b7e5090986646aac43aa47..c4d98df884f365d30f2d30a560d6f78b012ddb6d 100644 (file)
@@ -1060,6 +1060,7 @@ struct server_scope {
 struct nfs41_exchange_id_res {
        struct nfs_client               *client;
        u32                             flags;
+       struct server_scope             *server_scope;
 };
 
 struct nfs41_create_session_args {