Commit b9efa1b27e25b1286504973c0a6bf0f24106faa8
Committed by
Trond Myklebust
1 parent
4911096f1a
Exists in
master
and in
7 other branches
nfs41: implement cb_recall_slot
Drain the fore channel and reset the max_slots to the new value. Signed-off-by: Andy Adamson <andros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 6 changed files with 109 additions and 1 deletions Side-by-side Diff
fs/nfs/callback.h
... | ... | @@ -119,6 +119,14 @@ |
119 | 119 | }; |
120 | 120 | |
121 | 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 | 130 | #endif /* CONFIG_NFS_V4_1 */ |
123 | 131 | |
124 | 132 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
fs/nfs/callback_proc.c
... | ... | @@ -361,5 +361,37 @@ |
361 | 361 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); |
362 | 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 | 396 | #endif /* CONFIG_NFS_V4_1 */ |
fs/nfs/callback_xdr.c
... | ... | @@ -24,6 +24,7 @@ |
24 | 24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
25 | 25 | 4 + 1 + 3) |
26 | 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 | 28 | #endif /* CONFIG_NFS_V4_1 */ |
28 | 29 | |
29 | 30 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
... | ... | @@ -349,6 +350,20 @@ |
349 | 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 | 367 | #endif /* CONFIG_NFS_V4_1 */ |
353 | 368 | |
354 | 369 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
... | ... | @@ -557,6 +572,7 @@ |
557 | 572 | case OP_CB_RECALL: |
558 | 573 | case OP_CB_SEQUENCE: |
559 | 574 | case OP_CB_RECALL_ANY: |
575 | + case OP_CB_RECALL_SLOT: | |
560 | 576 | *op = &callback_ops[op_nr]; |
561 | 577 | break; |
562 | 578 | |
... | ... | @@ -565,7 +581,6 @@ |
565 | 581 | case OP_CB_NOTIFY: |
566 | 582 | case OP_CB_PUSH_DELEG: |
567 | 583 | case OP_CB_RECALLABLE_OBJ_AVAIL: |
568 | - case OP_CB_RECALL_SLOT: | |
569 | 584 | case OP_CB_WANTS_CANCELLED: |
570 | 585 | case OP_CB_NOTIFY_LOCK: |
571 | 586 | return htonl(NFS4ERR_NOTSUPP); |
... | ... | @@ -733,6 +748,11 @@ |
733 | 748 | .process_op = (callback_process_op_t)nfs4_callback_recallany, |
734 | 749 | .decode_args = (callback_decode_arg_t)decode_recallany_args, |
735 | 750 | .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, |
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, | |
736 | 756 | }, |
737 | 757 | #endif /* CONFIG_NFS_V4_1 */ |
738 | 758 | }; |
fs/nfs/nfs4_fs.h
... | ... | @@ -46,6 +46,7 @@ |
46 | 46 | NFS4CLNT_DELEGRETURN, |
47 | 47 | NFS4CLNT_SESSION_RESET, |
48 | 48 | NFS4CLNT_SESSION_DRAINING, |
49 | + NFS4CLNT_RECALL_SLOT, | |
49 | 50 | }; |
50 | 51 | |
51 | 52 | /* |
... | ... | @@ -280,6 +281,7 @@ |
280 | 281 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); |
281 | 282 | extern int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state); |
282 | 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 | 285 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
284 | 286 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
285 | 287 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
fs/nfs/nfs4state.c
... | ... | @@ -1249,6 +1249,12 @@ |
1249 | 1249 | } |
1250 | 1250 | |
1251 | 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 | 1258 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) |
1253 | 1259 | { |
1254 | 1260 | if (!flags) |
1255 | 1261 | |
... | ... | @@ -1299,9 +1305,38 @@ |
1299 | 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 | 1336 | #else /* CONFIG_NFS_V4_1 */ |
1303 | 1337 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } |
1304 | 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 | 1340 | #endif /* CONFIG_NFS_V4_1 */ |
1306 | 1341 | |
1307 | 1342 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors |
... | ... | @@ -1398,6 +1433,15 @@ |
1398 | 1433 | nfs_client_return_marked_delegations(clp); |
1399 | 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 | 1446 | nfs4_clear_state_manager_bit(clp); |
1403 | 1447 | /* Did we race with an attempt to give us more work? */ |
include/linux/nfs_fs_sb.h
... | ... | @@ -193,6 +193,8 @@ |
193 | 193 | int max_slots; /* # slots in table */ |
194 | 194 | int highest_used_slotid; /* sent to server on each SEQ. |
195 | 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 | 200 | static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) |