diff options
-rw-r--r-- | fs/nfs/client.c | 10 | ||||
-rw-r--r-- | fs/nfs/internal.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 10 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 35 | ||||
-rw-r--r-- | include/linux/nfs_fs_sb.h | 1 |
6 files changed, 54 insertions, 5 deletions
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) | |||
366 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 366 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
367 | 367 | ||
368 | /* Don't match clients that failed to initialise properly */ | 368 | /* Don't match clients that failed to initialise properly */ |
369 | if (clp->cl_cons_state != NFS_CS_READY) | 369 | if (!(clp->cl_cons_state == NFS_CS_READY || |
370 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
370 | continue; | 371 | continue; |
371 | 372 | ||
372 | /* Different NFS versions cannot share the same nfs_client */ | 373 | /* Different NFS versions cannot share the same nfs_client */ |
@@ -499,7 +500,7 @@ found_client: | |||
499 | nfs_free_client(new); | 500 | nfs_free_client(new); |
500 | 501 | ||
501 | error = wait_event_killable(nfs_client_active_wq, | 502 | error = wait_event_killable(nfs_client_active_wq, |
502 | clp->cl_cons_state != NFS_CS_INITING); | 503 | clp->cl_cons_state < NFS_CS_INITING); |
503 | if (error < 0) { | 504 | if (error < 0) { |
504 | nfs_put_client(clp); | 505 | nfs_put_client(clp); |
505 | return ERR_PTR(-ERESTARTSYS); | 506 | return ERR_PTR(-ERESTARTSYS); |
@@ -520,7 +521,7 @@ found_client: | |||
520 | /* | 521 | /* |
521 | * Mark a server as ready or failed | 522 | * Mark a server as ready or failed |
522 | */ | 523 | */ |
523 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | 524 | void nfs_mark_client_ready(struct nfs_client *clp, int state) |
524 | { | 525 | { |
525 | clp->cl_cons_state = state; | 526 | clp->cl_cons_state = state; |
526 | wake_up_all(&nfs_client_active_wq); | 527 | wake_up_all(&nfs_client_active_wq); |
@@ -1135,7 +1136,8 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
1135 | if (error < 0) | 1136 | if (error < 0) |
1136 | goto error; | 1137 | goto error; |
1137 | 1138 | ||
1138 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1139 | if (!nfs4_has_session(clp)) |
1140 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1139 | return 0; | 1141 | return 0; |
1140 | 1142 | ||
1141 | error: | 1143 | error: |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index f62bc5226155..f3b310e8ea03 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -100,6 +100,7 @@ extern void nfs_free_server(struct nfs_server *server); | |||
100 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 100 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
101 | struct nfs_fh *, | 101 | struct nfs_fh *, |
102 | struct nfs_fattr *); | 102 | struct nfs_fattr *); |
103 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); | ||
103 | #ifdef CONFIG_PROC_FS | 104 | #ifdef CONFIG_PROC_FS |
104 | extern int __init nfs_fs_proc_init(void); | 105 | extern int __init nfs_fs_proc_init(void); |
105 | extern void nfs_fs_proc_exit(void); | 106 | extern void nfs_fs_proc_exit(void); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index eccf4e93e7d7..288717abaddc 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -44,6 +44,7 @@ enum nfs4_client_state { | |||
44 | NFS4CLNT_RECLAIM_REBOOT, | 44 | NFS4CLNT_RECLAIM_REBOOT, |
45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_SETUP, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -208,6 +209,7 @@ extern int nfs4_setup_sequence(struct nfs_client *clp, | |||
208 | int cache_reply, struct rpc_task *task); | 209 | int cache_reply, struct rpc_task *task); |
209 | extern void nfs4_destroy_session(struct nfs4_session *session); | 210 | extern void nfs4_destroy_session(struct nfs4_session *session); |
210 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | 211 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); |
212 | extern int nfs4_proc_create_session(struct nfs_client *, int reset); | ||
211 | #else /* CONFIG_NFS_v4_1 */ | 213 | #else /* CONFIG_NFS_v4_1 */ |
212 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | 214 | static inline int nfs4_setup_sequence(struct nfs_client *clp, |
213 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 215 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0b1214740248..7fc0c9c8f5e3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -4382,6 +4382,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4382 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | 4382 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); |
4383 | if (!session) | 4383 | if (!session) |
4384 | return NULL; | 4384 | return NULL; |
4385 | |||
4386 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4387 | /* | ||
4388 | * The create session reply races with the server back | ||
4389 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
4390 | * so that the client back channel can find the | ||
4391 | * nfs_client struct | ||
4392 | */ | ||
4393 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
4394 | |||
4385 | tbl = &session->fc_slot_table; | 4395 | tbl = &session->fc_slot_table; |
4386 | spin_lock_init(&tbl->slot_tbl_lock); | 4396 | spin_lock_init(&tbl->slot_tbl_lock); |
4387 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "Slot table"); | 4397 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "Slot table"); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index bc683ed477e1..df5b4807daa7 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1113,6 +1113,27 @@ static int nfs4_reclaim_lease(struct nfs_client *clp) | |||
1113 | return status; | 1113 | return status; |
1114 | } | 1114 | } |
1115 | 1115 | ||
1116 | #ifdef CONFIG_NFS_V4_1 | ||
1117 | |||
1118 | static int nfs4_initialize_session(struct nfs_client *clp) | ||
1119 | { | ||
1120 | int status; | ||
1121 | |||
1122 | status = nfs4_proc_create_session(clp, 0); | ||
1123 | if (!status) { | ||
1124 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1125 | } else if (status == -NFS4ERR_STALE_CLIENTID) { | ||
1126 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1127 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1128 | } else { | ||
1129 | nfs_mark_client_ready(clp, status); | ||
1130 | } | ||
1131 | return status; | ||
1132 | } | ||
1133 | #else /* CONFIG_NFS_V4_1 */ | ||
1134 | static int nfs4_initialize_session(struct nfs_client *clp) { return 0; } | ||
1135 | #endif /* CONFIG_NFS_V4_1 */ | ||
1136 | |||
1116 | static void nfs4_state_manager(struct nfs_client *clp) | 1137 | static void nfs4_state_manager(struct nfs_client *clp) |
1117 | { | 1138 | { |
1118 | int status = 0; | 1139 | int status = 0; |
@@ -1126,6 +1147,9 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1126 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1147 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1127 | if (status == -EAGAIN) | 1148 | if (status == -EAGAIN) |
1128 | continue; | 1149 | continue; |
1150 | if (clp->cl_cons_state == | ||
1151 | NFS_CS_SESSION_INITING) | ||
1152 | nfs_mark_client_ready(clp, status); | ||
1129 | goto out_error; | 1153 | goto out_error; |
1130 | } | 1154 | } |
1131 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1155 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
@@ -1136,7 +1160,16 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1136 | if (status != 0) | 1160 | if (status != 0) |
1137 | continue; | 1161 | continue; |
1138 | } | 1162 | } |
1139 | 1163 | /* Setup the session */ | |
1164 | if (nfs4_has_session(clp) && | ||
1165 | test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
1166 | status = nfs4_initialize_session(clp); | ||
1167 | if (status) { | ||
1168 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
1169 | continue; | ||
1170 | goto out_error; | ||
1171 | } | ||
1172 | } | ||
1140 | /* First recover reboot state... */ | 1173 | /* First recover reboot state... */ |
1141 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1174 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1142 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); | 1175 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 435ed556efb5..d0902ccec9ce 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -24,6 +24,7 @@ struct nfs_client { | |||
24 | int cl_cons_state; /* current construction state (-ve: init error) */ | 24 | int cl_cons_state; /* current construction state (-ve: init error) */ |
25 | #define NFS_CS_READY 0 /* ready to be used */ | 25 | #define NFS_CS_READY 0 /* ready to be used */ |
26 | #define NFS_CS_INITING 1 /* busy initialising */ | 26 | #define NFS_CS_INITING 1 /* busy initialising */ |
27 | #define NFS_CS_SESSION_INITING 2 /* busy initialising session */ | ||
27 | unsigned long cl_res_state; /* NFS resources state */ | 28 | unsigned long cl_res_state; /* NFS resources state */ |
28 | #define NFS_CS_CALLBACK 1 /* - callback started */ | 29 | #define NFS_CS_CALLBACK 1 /* - callback started */ |
29 | #define NFS_CS_IDMAP 2 /* - idmap started */ | 30 | #define NFS_CS_IDMAP 2 /* - idmap started */ |