diff options
-rw-r--r-- | fs/nfs/callback.h | 8 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 32 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 22 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 44 | ||||
-rw-r--r-- | include/linux/nfs_fs_sb.h | 2 |
6 files changed, 109 insertions, 1 deletions
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index d4036be0b589..85a7cfd1b8dd 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -119,6 +119,14 @@ struct cb_recallanyargs { | |||
119 | }; | 119 | }; |
120 | 120 | ||
121 | extern unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy); | 121 | extern unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy); |
122 | |||
123 | struct cb_recallslotargs { | ||
124 | struct sockaddr *crsa_addr; | ||
125 | uint32_t crsa_target_max_slots; | ||
126 | }; | ||
127 | extern unsigned nfs4_callback_recallslot(struct cb_recallslotargs *args, | ||
128 | void *dummy); | ||
129 | |||
122 | #endif /* CONFIG_NFS_V4_1 */ | 130 | #endif /* CONFIG_NFS_V4_1 */ |
123 | 131 | ||
124 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 132 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 4062f7690a33..e5155d9df595 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -361,4 +361,36 @@ out: | |||
361 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | 361 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); |
362 | return status; | 362 | return status; |
363 | } | 363 | } |
364 | |||
365 | /* Reduce the fore channel's max_slots to the target value */ | ||
366 | unsigned nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy) | ||
367 | { | ||
368 | struct nfs_client *clp; | ||
369 | struct nfs4_slot_table *fc_tbl; | ||
370 | int status; | ||
371 | |||
372 | status = htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
373 | clp = nfs_find_client(args->crsa_addr, 4); | ||
374 | if (clp == NULL) | ||
375 | goto out; | ||
376 | |||
377 | dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", | ||
378 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR), | ||
379 | args->crsa_target_max_slots); | ||
380 | |||
381 | fc_tbl = &clp->cl_session->fc_slot_table; | ||
382 | |||
383 | status = htonl(NFS4ERR_BAD_HIGH_SLOT); | ||
384 | if (args->crsa_target_max_slots >= fc_tbl->max_slots || | ||
385 | args->crsa_target_max_slots < 1) | ||
386 | goto out; | ||
387 | |||
388 | fc_tbl->target_max_slots = args->crsa_target_max_slots; | ||
389 | nfs41_handle_recall_slot(clp); | ||
390 | status = htonl(NFS4_OK); | ||
391 | nfs_put_client(clp); /* balance nfs_find_client */ | ||
392 | out: | ||
393 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
394 | return status; | ||
395 | } | ||
364 | #endif /* CONFIG_NFS_V4_1 */ | 396 | #endif /* CONFIG_NFS_V4_1 */ |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 08b430d922c4..8e66e20b59fd 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | 24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
25 | 4 + 1 + 3) | 25 | 4 + 1 + 3) |
26 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 26 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
27 | #define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | ||
27 | #endif /* CONFIG_NFS_V4_1 */ | 28 | #endif /* CONFIG_NFS_V4_1 */ |
28 | 29 | ||
29 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 30 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
@@ -349,6 +350,20 @@ static unsigned decode_recallany_args(struct svc_rqst *rqstp, | |||
349 | return 0; | 350 | return 0; |
350 | } | 351 | } |
351 | 352 | ||
353 | static unsigned decode_recallslot_args(struct svc_rqst *rqstp, | ||
354 | struct xdr_stream *xdr, | ||
355 | struct cb_recallslotargs *args) | ||
356 | { | ||
357 | __be32 *p; | ||
358 | |||
359 | args->crsa_addr = svc_addr(rqstp); | ||
360 | p = read_buf(xdr, 4); | ||
361 | if (unlikely(p == NULL)) | ||
362 | return htonl(NFS4ERR_BADXDR); | ||
363 | args->crsa_target_max_slots = ntohl(*p++); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
352 | #endif /* CONFIG_NFS_V4_1 */ | 367 | #endif /* CONFIG_NFS_V4_1 */ |
353 | 368 | ||
354 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 369 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
@@ -557,6 +572,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
557 | case OP_CB_RECALL: | 572 | case OP_CB_RECALL: |
558 | case OP_CB_SEQUENCE: | 573 | case OP_CB_SEQUENCE: |
559 | case OP_CB_RECALL_ANY: | 574 | case OP_CB_RECALL_ANY: |
575 | case OP_CB_RECALL_SLOT: | ||
560 | *op = &callback_ops[op_nr]; | 576 | *op = &callback_ops[op_nr]; |
561 | break; | 577 | break; |
562 | 578 | ||
@@ -565,7 +581,6 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
565 | case OP_CB_NOTIFY: | 581 | case OP_CB_NOTIFY: |
566 | case OP_CB_PUSH_DELEG: | 582 | case OP_CB_PUSH_DELEG: |
567 | case OP_CB_RECALLABLE_OBJ_AVAIL: | 583 | case OP_CB_RECALLABLE_OBJ_AVAIL: |
568 | case OP_CB_RECALL_SLOT: | ||
569 | case OP_CB_WANTS_CANCELLED: | 584 | case OP_CB_WANTS_CANCELLED: |
570 | case OP_CB_NOTIFY_LOCK: | 585 | case OP_CB_NOTIFY_LOCK: |
571 | return htonl(NFS4ERR_NOTSUPP); | 586 | return htonl(NFS4ERR_NOTSUPP); |
@@ -734,6 +749,11 @@ static struct callback_op callback_ops[] = { | |||
734 | .decode_args = (callback_decode_arg_t)decode_recallany_args, | 749 | .decode_args = (callback_decode_arg_t)decode_recallany_args, |
735 | .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, | 750 | .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, |
736 | }, | 751 | }, |
752 | [OP_CB_RECALL_SLOT] = { | ||
753 | .process_op = (callback_process_op_t)nfs4_callback_recallslot, | ||
754 | .decode_args = (callback_decode_arg_t)decode_recallslot_args, | ||
755 | .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ, | ||
756 | }, | ||
737 | #endif /* CONFIG_NFS_V4_1 */ | 757 | #endif /* CONFIG_NFS_V4_1 */ |
738 | }; | 758 | }; |
739 | 759 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 0c6fda33d66e..a187200a7aac 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -46,6 +46,7 @@ enum nfs4_client_state { | |||
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_RESET, | 47 | NFS4CLNT_SESSION_RESET, |
48 | NFS4CLNT_SESSION_DRAINING, | 48 | NFS4CLNT_SESSION_DRAINING, |
49 | NFS4CLNT_RECALL_SLOT, | ||
49 | }; | 50 | }; |
50 | 51 | ||
51 | /* | 52 | /* |
@@ -280,6 +281,7 @@ extern void nfs4_schedule_state_manager(struct nfs_client *); | |||
280 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); | 281 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); |
281 | extern int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state); | 282 | extern int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state); |
282 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); | 283 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); |
284 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); | ||
283 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 285 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
284 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 286 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
285 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 287 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 8406cacd3240..9164758c1ace 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1249,6 +1249,12 @@ static int nfs4_reclaim_lease(struct nfs_client *clp) | |||
1249 | } | 1249 | } |
1250 | 1250 | ||
1251 | #ifdef CONFIG_NFS_V4_1 | 1251 | #ifdef CONFIG_NFS_V4_1 |
1252 | void nfs41_handle_recall_slot(struct nfs_client *clp) | ||
1253 | { | ||
1254 | set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); | ||
1255 | nfs4_schedule_state_recovery(clp); | ||
1256 | } | ||
1257 | |||
1252 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | 1258 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) |
1253 | { | 1259 | { |
1254 | if (!flags) | 1260 | if (!flags) |
@@ -1299,9 +1305,38 @@ out: | |||
1299 | return status; | 1305 | return status; |
1300 | } | 1306 | } |
1301 | 1307 | ||
1308 | static int nfs4_recall_slot(struct nfs_client *clp) | ||
1309 | { | ||
1310 | struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table; | ||
1311 | struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs; | ||
1312 | struct nfs4_slot *new, *old; | ||
1313 | int i; | ||
1314 | |||
1315 | nfs4_begin_drain_session(clp); | ||
1316 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), | ||
1317 | GFP_KERNEL); | ||
1318 | if (!new) | ||
1319 | return -ENOMEM; | ||
1320 | |||
1321 | spin_lock(&fc_tbl->slot_tbl_lock); | ||
1322 | for (i = 0; i < fc_tbl->target_max_slots; i++) | ||
1323 | new[i].seq_nr = fc_tbl->slots[i].seq_nr; | ||
1324 | old = fc_tbl->slots; | ||
1325 | fc_tbl->slots = new; | ||
1326 | fc_tbl->max_slots = fc_tbl->target_max_slots; | ||
1327 | fc_tbl->target_max_slots = 0; | ||
1328 | fc_attrs->max_reqs = fc_tbl->max_slots; | ||
1329 | spin_unlock(&fc_tbl->slot_tbl_lock); | ||
1330 | |||
1331 | kfree(old); | ||
1332 | nfs4_end_drain_session(clp); | ||
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1302 | #else /* CONFIG_NFS_V4_1 */ | 1336 | #else /* CONFIG_NFS_V4_1 */ |
1303 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | 1337 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } |
1304 | static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; } | 1338 | static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; } |
1339 | static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } | ||
1305 | #endif /* CONFIG_NFS_V4_1 */ | 1340 | #endif /* CONFIG_NFS_V4_1 */ |
1306 | 1341 | ||
1307 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | 1342 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors |
@@ -1398,6 +1433,15 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1398 | nfs_client_return_marked_delegations(clp); | 1433 | nfs_client_return_marked_delegations(clp); |
1399 | continue; | 1434 | continue; |
1400 | } | 1435 | } |
1436 | /* Recall session slots */ | ||
1437 | if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state) | ||
1438 | && nfs4_has_session(clp)) { | ||
1439 | status = nfs4_recall_slot(clp); | ||
1440 | if (status < 0) | ||
1441 | goto out_error; | ||
1442 | continue; | ||
1443 | } | ||
1444 | |||
1401 | 1445 | ||
1402 | nfs4_clear_state_manager_bit(clp); | 1446 | nfs4_clear_state_manager_bit(clp); |
1403 | /* Did we race with an attempt to give us more work? */ | 1447 | /* Did we race with an attempt to give us more work? */ |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 34fc6be5bfcf..ecd9e6c74d06 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -193,6 +193,8 @@ struct nfs4_slot_table { | |||
193 | int max_slots; /* # slots in table */ | 193 | int max_slots; /* # slots in table */ |
194 | int highest_used_slotid; /* sent to server on each SEQ. | 194 | int highest_used_slotid; /* sent to server on each SEQ. |
195 | * op for dynamic resizing */ | 195 | * op for dynamic resizing */ |
196 | int target_max_slots; /* Set by CB_RECALL_SLOT as | ||
197 | * the new max_slots */ | ||
196 | }; | 198 | }; |
197 | 199 | ||
198 | static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) | 200 | static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) |