Commit b9efa1b27e25b1286504973c0a6bf0f24106faa8

Authored by Andy Adamson
Committed by Trond Myklebust
1 parent 4911096f1a

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

... ... @@ -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 };
... ... @@ -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);
... ... @@ -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)