diff options
| -rw-r--r-- | fs/nfs/client.c | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 3 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 32 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 9 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 8 | ||||
| -rw-r--r-- | include/linux/nfs_fs_sb.h | 3 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 1 |
7 files changed, 55 insertions, 2 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index b3dc2b88b65b..006f8ff0a3c0 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -293,6 +293,7 @@ static void nfs_free_client(struct nfs_client *clp) | |||
| 293 | nfs4_deviceid_purge_client(clp); | 293 | nfs4_deviceid_purge_client(clp); |
| 294 | 294 | ||
| 295 | kfree(clp->cl_hostname); | 295 | kfree(clp->cl_hostname); |
| 296 | kfree(clp->server_scope); | ||
| 296 | kfree(clp); | 297 | kfree(clp); |
| 297 | 298 | ||
| 298 | dprintk("<-- nfs_free_client()\n"); | 299 | dprintk("<-- nfs_free_client()\n"); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c4a69833dd0d..b47f0d4710fa 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -48,6 +48,7 @@ enum nfs4_client_state { | |||
| 48 | NFS4CLNT_SESSION_RESET, | 48 | NFS4CLNT_SESSION_RESET, |
| 49 | NFS4CLNT_RECALL_SLOT, | 49 | NFS4CLNT_RECALL_SLOT, |
| 50 | NFS4CLNT_LEASE_CONFIRM, | 50 | NFS4CLNT_LEASE_CONFIRM, |
| 51 | NFS4CLNT_SERVER_SCOPE_MISMATCH, | ||
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | enum nfs4_session_state { | 54 | enum nfs4_session_state { |
| @@ -349,6 +350,8 @@ extern void nfs4_schedule_state_manager(struct nfs_client *); | |||
| 349 | extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); | 350 | extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); |
| 350 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); | 351 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); |
| 351 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); | 352 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); |
| 353 | extern void nfs41_handle_server_scope(struct nfs_client *, | ||
| 354 | struct server_scope **); | ||
| 352 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 355 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
| 353 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 356 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
| 354 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t); | 357 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5879b23e0c99..5f4912f72282 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -4781,6 +4781,16 @@ out_inval: | |||
| 4781 | return -NFS4ERR_INVAL; | 4781 | return -NFS4ERR_INVAL; |
| 4782 | } | 4782 | } |
| 4783 | 4783 | ||
| 4784 | static bool | ||
| 4785 | nfs41_same_server_scope(struct server_scope *a, struct server_scope *b) | ||
| 4786 | { | ||
| 4787 | if (a->server_scope_sz == b->server_scope_sz && | ||
| 4788 | memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0) | ||
| 4789 | return true; | ||
| 4790 | |||
| 4791 | return false; | ||
| 4792 | } | ||
| 4793 | |||
| 4784 | /* | 4794 | /* |
| 4785 | * nfs4_proc_exchange_id() | 4795 | * nfs4_proc_exchange_id() |
| 4786 | * | 4796 | * |
| @@ -4823,9 +4833,31 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 4823 | init_utsname()->domainname, | 4833 | init_utsname()->domainname, |
| 4824 | clp->cl_rpcclient->cl_auth->au_flavor); | 4834 | clp->cl_rpcclient->cl_auth->au_flavor); |
| 4825 | 4835 | ||
| 4836 | res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL); | ||
| 4837 | if (unlikely(!res.server_scope)) | ||
| 4838 | return -ENOMEM; | ||
| 4839 | |||
| 4826 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 4840 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
| 4827 | if (!status) | 4841 | if (!status) |
| 4828 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); | 4842 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); |
| 4843 | |||
| 4844 | if (!status) { | ||
| 4845 | if (clp->server_scope && | ||
| 4846 | !nfs41_same_server_scope(clp->server_scope, | ||
| 4847 | res.server_scope)) { | ||
| 4848 | dprintk("%s: server_scope mismatch detected\n", | ||
| 4849 | __func__); | ||
| 4850 | set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state); | ||
| 4851 | kfree(clp->server_scope); | ||
| 4852 | clp->server_scope = NULL; | ||
| 4853 | } | ||
| 4854 | |||
| 4855 | if (!clp->server_scope) | ||
| 4856 | clp->server_scope = res.server_scope; | ||
| 4857 | else | ||
| 4858 | kfree(res.server_scope); | ||
| 4859 | } | ||
| 4860 | |||
| 4829 | dprintk("<-- %s status= %d\n", __func__, status); | 4861 | dprintk("<-- %s status= %d\n", __func__, status); |
| 4830 | return status; | 4862 | return status; |
| 4831 | } | 4863 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e97dd219f84f..5d744a52b4e1 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -1643,7 +1643,14 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 1643 | goto out_error; | 1643 | goto out_error; |
| 1644 | } | 1644 | } |
| 1645 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1645 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
| 1646 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); | 1646 | |
| 1647 | if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, | ||
| 1648 | &clp->cl_state)) | ||
| 1649 | nfs4_state_start_reclaim_nograce(clp); | ||
| 1650 | else | ||
| 1651 | set_bit(NFS4CLNT_RECLAIM_REBOOT, | ||
| 1652 | &clp->cl_state); | ||
| 1653 | |||
| 1647 | pnfs_destroy_all_layouts(clp); | 1654 | pnfs_destroy_all_layouts(clp); |
| 1648 | } | 1655 | } |
| 1649 | 1656 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index e6e8f3b9a1de..1555c74dd336 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -4977,11 +4977,17 @@ static int decode_exchange_id(struct xdr_stream *xdr, | |||
| 4977 | if (unlikely(status)) | 4977 | if (unlikely(status)) |
| 4978 | return status; | 4978 | return status; |
| 4979 | 4979 | ||
| 4980 | /* Throw away server_scope */ | 4980 | /* Save server_scope */ |
| 4981 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); | 4981 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
| 4982 | if (unlikely(status)) | 4982 | if (unlikely(status)) |
| 4983 | return status; | 4983 | return status; |
| 4984 | 4984 | ||
| 4985 | if (unlikely(dummy > NFS4_OPAQUE_LIMIT)) | ||
| 4986 | return -EIO; | ||
| 4987 | |||
| 4988 | memcpy(res->server_scope->server_scope, dummy_str, dummy); | ||
| 4989 | res->server_scope->server_scope_sz = dummy; | ||
| 4990 | |||
| 4985 | /* Throw away Implementation id array */ | 4991 | /* Throw away Implementation id array */ |
| 4986 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); | 4992 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
| 4987 | if (unlikely(status)) | 4993 | if (unlikely(status)) |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 87694ca86914..f23b18831559 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -16,6 +16,7 @@ struct nfs4_sequence_args; | |||
| 16 | struct nfs4_sequence_res; | 16 | struct nfs4_sequence_res; |
| 17 | struct nfs_server; | 17 | struct nfs_server; |
| 18 | struct nfs4_minor_version_ops; | 18 | struct nfs4_minor_version_ops; |
| 19 | struct server_scope; | ||
| 19 | 20 | ||
| 20 | /* | 21 | /* |
| 21 | * The nfs_client identifies our client state to the server. | 22 | * The nfs_client identifies our client state to the server. |
| @@ -83,6 +84,8 @@ struct nfs_client { | |||
| 83 | #ifdef CONFIG_NFS_FSCACHE | 84 | #ifdef CONFIG_NFS_FSCACHE |
| 84 | struct fscache_cookie *fscache; /* client index cache cookie */ | 85 | struct fscache_cookie *fscache; /* client index cache cookie */ |
| 85 | #endif | 86 | #endif |
| 87 | |||
| 88 | struct server_scope *server_scope; /* from exchange_id */ | ||
| 86 | }; | 89 | }; |
| 87 | 90 | ||
| 88 | /* | 91 | /* |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 00848d86ffb2..c4d98df884f3 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -1060,6 +1060,7 @@ struct server_scope { | |||
| 1060 | struct nfs41_exchange_id_res { | 1060 | struct nfs41_exchange_id_res { |
| 1061 | struct nfs_client *client; | 1061 | struct nfs_client *client; |
| 1062 | u32 flags; | 1062 | u32 flags; |
| 1063 | struct server_scope *server_scope; | ||
| 1063 | }; | 1064 | }; |
| 1064 | 1065 | ||
| 1065 | struct nfs41_create_session_args { | 1066 | struct nfs41_create_session_args { |
