Branch data Line data Source code
1 : : /*
2 : : * linux/fs/nfs/callback_proc.c
3 : : *
4 : : * Copyright (C) 2004 Trond Myklebust
5 : : *
6 : : * NFSv4 callback procedures
7 : : */
8 : : #include <linux/nfs4.h>
9 : : #include <linux/nfs_fs.h>
10 : : #include <linux/slab.h>
11 : : #include <linux/rcupdate.h>
12 : : #include "nfs4_fs.h"
13 : : #include "callback.h"
14 : : #include "delegation.h"
15 : : #include "internal.h"
16 : : #include "pnfs.h"
17 : : #include "nfs4session.h"
18 : : #include "nfs4trace.h"
19 : :
20 : : #ifdef NFS_DEBUG
21 : : #define NFSDBG_FACILITY NFSDBG_CALLBACK
22 : : #endif
23 : :
24 : 0 : __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
25 : : struct cb_getattrres *res,
26 : : struct cb_process_state *cps)
27 : : {
28 : : struct nfs_delegation *delegation;
29 : : struct nfs_inode *nfsi;
30 : : struct inode *inode;
31 : :
32 : 0 : res->status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
33 [ # # ]: 0 : if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
34 : : goto out;
35 : :
36 : 0 : res->bitmap[0] = res->bitmap[1] = 0;
37 : 0 : res->status = htonl(NFS4ERR_BADHANDLE);
38 : :
39 : : dprintk_rcu("NFS: GETATTR callback request from %s\n",
40 : : rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
41 : :
42 : 0 : inode = nfs_delegation_find_inode(cps->clp, &args->fh);
43 [ # # ]: 0 : if (inode == NULL)
44 : : goto out;
45 : : nfsi = NFS_I(inode);
46 : : rcu_read_lock();
47 : 0 : delegation = rcu_dereference(nfsi->delegation);
48 [ # # ][ # # ]: 0 : if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
49 : : goto out_iput;
50 : 0 : res->size = i_size_read(inode);
51 : 0 : res->change_attr = delegation->change_attr;
52 [ # # ]: 0 : if (nfsi->npages != 0)
53 : 0 : res->change_attr++;
54 : 0 : res->ctime = inode->i_ctime;
55 : 0 : res->mtime = inode->i_mtime;
56 : 0 : res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
57 : 0 : args->bitmap[0];
58 : 0 : res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
59 : 0 : args->bitmap[1];
60 : 0 : res->status = 0;
61 : : out_iput:
62 : : rcu_read_unlock();
63 : 0 : iput(inode);
64 : : out:
65 : : dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
66 : 0 : return res->status;
67 : : }
68 : :
69 : 0 : __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
70 : : struct cb_process_state *cps)
71 : : {
72 : : struct inode *inode;
73 : : __be32 res;
74 : :
75 : : res = htonl(NFS4ERR_OP_NOT_IN_SESSION);
76 [ # # ]: 0 : if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
77 : : goto out;
78 : :
79 : : dprintk_rcu("NFS: RECALL callback request from %s\n",
80 : : rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
81 : :
82 : : res = htonl(NFS4ERR_BADHANDLE);
83 : 0 : inode = nfs_delegation_find_inode(cps->clp, &args->fh);
84 [ # # ]: 0 : if (inode == NULL)
85 : : goto out;
86 : : /* Set up a helper thread to actually return the delegation */
87 [ # # # ]: 0 : switch (nfs_async_inode_return_delegation(inode, &args->stateid)) {
88 : : case 0:
89 : : res = 0;
90 : : break;
91 : : case -ENOENT:
92 : : res = htonl(NFS4ERR_BAD_STATEID);
93 : 0 : break;
94 : : default:
95 : : res = htonl(NFS4ERR_RESOURCE);
96 : : }
97 [ # # ]: 0 : trace_nfs4_recall_delegation(inode, -ntohl(res));
98 : 0 : iput(inode);
99 : : out:
100 : : dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
101 : 0 : return res;
102 : : }
103 : :
104 : : #if defined(CONFIG_NFS_V4_1)
105 : :
106 : : /*
107 : : * Lookup a layout by filehandle.
108 : : *
109 : : * Note: gets a refcount on the layout hdr and on its respective inode.
110 : : * Caller must put the layout hdr and the inode.
111 : : *
112 : : * TODO: keep track of all layouts (and delegations) in a hash table
113 : : * hashed by filehandle.
114 : : */
115 : : static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh)
116 : : {
117 : : struct nfs_server *server;
118 : : struct inode *ino;
119 : : struct pnfs_layout_hdr *lo;
120 : :
121 : : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
122 : : list_for_each_entry(lo, &server->layouts, plh_layouts) {
123 : : if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
124 : : continue;
125 : : ino = igrab(lo->plh_inode);
126 : : if (!ino)
127 : : continue;
128 : : spin_lock(&ino->i_lock);
129 : : /* Is this layout in the process of being freed? */
130 : : if (NFS_I(ino)->layout != lo) {
131 : : spin_unlock(&ino->i_lock);
132 : : iput(ino);
133 : : continue;
134 : : }
135 : : pnfs_get_layout_hdr(lo);
136 : : spin_unlock(&ino->i_lock);
137 : : return lo;
138 : : }
139 : : }
140 : :
141 : : return NULL;
142 : : }
143 : :
144 : : static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh)
145 : : {
146 : : struct pnfs_layout_hdr *lo;
147 : :
148 : : spin_lock(&clp->cl_lock);
149 : : rcu_read_lock();
150 : : lo = get_layout_by_fh_locked(clp, fh);
151 : : rcu_read_unlock();
152 : : spin_unlock(&clp->cl_lock);
153 : :
154 : : return lo;
155 : : }
156 : :
157 : : static u32 initiate_file_draining(struct nfs_client *clp,
158 : : struct cb_layoutrecallargs *args)
159 : : {
160 : : struct inode *ino;
161 : : struct pnfs_layout_hdr *lo;
162 : : u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
163 : : LIST_HEAD(free_me_list);
164 : :
165 : : lo = get_layout_by_fh(clp, &args->cbl_fh);
166 : : if (!lo)
167 : : return NFS4ERR_NOMATCHING_LAYOUT;
168 : :
169 : : ino = lo->plh_inode;
170 : : spin_lock(&ino->i_lock);
171 : : if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
172 : : pnfs_mark_matching_lsegs_invalid(lo, &free_me_list,
173 : : &args->cbl_range))
174 : : rv = NFS4ERR_DELAY;
175 : : else
176 : : rv = NFS4ERR_NOMATCHING_LAYOUT;
177 : : pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
178 : : spin_unlock(&ino->i_lock);
179 : : pnfs_free_lseg_list(&free_me_list);
180 : : pnfs_put_layout_hdr(lo);
181 : : iput(ino);
182 : : return rv;
183 : : }
184 : :
185 : : static u32 initiate_bulk_draining(struct nfs_client *clp,
186 : : struct cb_layoutrecallargs *args)
187 : : {
188 : : int stat;
189 : :
190 : : if (args->cbl_recall_type == RETURN_FSID)
191 : : stat = pnfs_destroy_layouts_byfsid(clp, &args->cbl_fsid, true);
192 : : else
193 : : stat = pnfs_destroy_layouts_byclid(clp, true);
194 : : if (stat != 0)
195 : : return NFS4ERR_DELAY;
196 : : return NFS4ERR_NOMATCHING_LAYOUT;
197 : : }
198 : :
199 : : static u32 do_callback_layoutrecall(struct nfs_client *clp,
200 : : struct cb_layoutrecallargs *args)
201 : : {
202 : : u32 res;
203 : :
204 : : dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type);
205 : : if (args->cbl_recall_type == RETURN_FILE)
206 : : res = initiate_file_draining(clp, args);
207 : : else
208 : : res = initiate_bulk_draining(clp, args);
209 : : dprintk("%s returning %i\n", __func__, res);
210 : : return res;
211 : :
212 : : }
213 : :
214 : : __be32 nfs4_callback_layoutrecall(struct cb_layoutrecallargs *args,
215 : : void *dummy, struct cb_process_state *cps)
216 : : {
217 : : u32 res;
218 : :
219 : : dprintk("%s: -->\n", __func__);
220 : :
221 : : if (cps->clp)
222 : : res = do_callback_layoutrecall(cps->clp, args);
223 : : else
224 : : res = NFS4ERR_OP_NOT_IN_SESSION;
225 : :
226 : : dprintk("%s: exit with status = %d\n", __func__, res);
227 : : return cpu_to_be32(res);
228 : : }
229 : :
230 : : static void pnfs_recall_all_layouts(struct nfs_client *clp)
231 : : {
232 : : struct cb_layoutrecallargs args;
233 : :
234 : : /* Pretend we got a CB_LAYOUTRECALL(ALL) */
235 : : memset(&args, 0, sizeof(args));
236 : : args.cbl_recall_type = RETURN_ALL;
237 : : /* FIXME we ignore errors, what should we do? */
238 : : do_callback_layoutrecall(clp, &args);
239 : : }
240 : :
241 : : __be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
242 : : void *dummy, struct cb_process_state *cps)
243 : : {
244 : : int i;
245 : : __be32 res = 0;
246 : : struct nfs_client *clp = cps->clp;
247 : : struct nfs_server *server = NULL;
248 : :
249 : : dprintk("%s: -->\n", __func__);
250 : :
251 : : if (!clp) {
252 : : res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
253 : : goto out;
254 : : }
255 : :
256 : : for (i = 0; i < args->ndevs; i++) {
257 : : struct cb_devicenotifyitem *dev = &args->devs[i];
258 : :
259 : : if (!server ||
260 : : server->pnfs_curr_ld->id != dev->cbd_layout_type) {
261 : : rcu_read_lock();
262 : : list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
263 : : if (server->pnfs_curr_ld &&
264 : : server->pnfs_curr_ld->id == dev->cbd_layout_type) {
265 : : rcu_read_unlock();
266 : : goto found;
267 : : }
268 : : rcu_read_unlock();
269 : : dprintk("%s: layout type %u not found\n",
270 : : __func__, dev->cbd_layout_type);
271 : : continue;
272 : : }
273 : :
274 : : found:
275 : : if (dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE)
276 : : dprintk("%s: NOTIFY_DEVICEID4_CHANGE not supported, "
277 : : "deleting instead\n", __func__);
278 : : nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
279 : : }
280 : :
281 : : out:
282 : : kfree(args->devs);
283 : : dprintk("%s: exit with status = %u\n",
284 : : __func__, be32_to_cpu(res));
285 : : return res;
286 : : }
287 : :
288 : : /*
289 : : * Validate the sequenceID sent by the server.
290 : : * Return success if the sequenceID is one more than what we last saw on
291 : : * this slot, accounting for wraparound. Increments the slot's sequence.
292 : : *
293 : : * We don't yet implement a duplicate request cache, instead we set the
294 : : * back channel ca_maxresponsesize_cached to zero. This is OK for now
295 : : * since we only currently implement idempotent callbacks anyway.
296 : : *
297 : : * We have a single slot backchannel at this time, so we don't bother
298 : : * checking the used_slots bit array on the table. The lower layer guarantees
299 : : * a single outstanding callback request at a time.
300 : : */
301 : : static __be32
302 : : validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
303 : : {
304 : : struct nfs4_slot *slot;
305 : :
306 : : dprintk("%s enter. slotid %u seqid %u\n",
307 : : __func__, args->csa_slotid, args->csa_sequenceid);
308 : :
309 : : if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS)
310 : : return htonl(NFS4ERR_BADSLOT);
311 : :
312 : : slot = tbl->slots + args->csa_slotid;
313 : : dprintk("%s slot table seqid: %u\n", __func__, slot->seq_nr);
314 : :
315 : : /* Normal */
316 : : if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
317 : : slot->seq_nr++;
318 : : goto out_ok;
319 : : }
320 : :
321 : : /* Replay */
322 : : if (args->csa_sequenceid == slot->seq_nr) {
323 : : dprintk("%s seqid %u is a replay\n",
324 : : __func__, args->csa_sequenceid);
325 : : /* Signal process_op to set this error on next op */
326 : : if (args->csa_cachethis == 0)
327 : : return htonl(NFS4ERR_RETRY_UNCACHED_REP);
328 : :
329 : : /* The ca_maxresponsesize_cached is 0 with no DRC */
330 : : else if (args->csa_cachethis == 1)
331 : : return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
332 : : }
333 : :
334 : : /* Wraparound */
335 : : if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
336 : : slot->seq_nr = 1;
337 : : goto out_ok;
338 : : }
339 : :
340 : : /* Misordered request */
341 : : return htonl(NFS4ERR_SEQ_MISORDERED);
342 : : out_ok:
343 : : tbl->highest_used_slotid = args->csa_slotid;
344 : : return htonl(NFS4_OK);
345 : : }
346 : :
347 : : /*
348 : : * For each referring call triple, check the session's slot table for
349 : : * a match. If the slot is in use and the sequence numbers match, the
350 : : * client is still waiting for a response to the original request.
351 : : */
352 : : static bool referring_call_exists(struct nfs_client *clp,
353 : : uint32_t nrclists,
354 : : struct referring_call_list *rclists)
355 : : {
356 : : bool status = 0;
357 : : int i, j;
358 : : struct nfs4_session *session;
359 : : struct nfs4_slot_table *tbl;
360 : : struct referring_call_list *rclist;
361 : : struct referring_call *ref;
362 : :
363 : : /*
364 : : * XXX When client trunking is implemented, this becomes
365 : : * a session lookup from within the loop
366 : : */
367 : : session = clp->cl_session;
368 : : tbl = &session->fc_slot_table;
369 : :
370 : : for (i = 0; i < nrclists; i++) {
371 : : rclist = &rclists[i];
372 : : if (memcmp(session->sess_id.data,
373 : : rclist->rcl_sessionid.data,
374 : : NFS4_MAX_SESSIONID_LEN) != 0)
375 : : continue;
376 : :
377 : : for (j = 0; j < rclist->rcl_nrefcalls; j++) {
378 : : ref = &rclist->rcl_refcalls[j];
379 : :
380 : : dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u "
381 : : "slotid %u\n", __func__,
382 : : ((u32 *)&rclist->rcl_sessionid.data)[0],
383 : : ((u32 *)&rclist->rcl_sessionid.data)[1],
384 : : ((u32 *)&rclist->rcl_sessionid.data)[2],
385 : : ((u32 *)&rclist->rcl_sessionid.data)[3],
386 : : ref->rc_sequenceid, ref->rc_slotid);
387 : :
388 : : spin_lock(&tbl->slot_tbl_lock);
389 : : status = (test_bit(ref->rc_slotid, tbl->used_slots) &&
390 : : tbl->slots[ref->rc_slotid].seq_nr ==
391 : : ref->rc_sequenceid);
392 : : spin_unlock(&tbl->slot_tbl_lock);
393 : : if (status)
394 : : goto out;
395 : : }
396 : : }
397 : :
398 : : out:
399 : : return status;
400 : : }
401 : :
402 : : __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
403 : : struct cb_sequenceres *res,
404 : : struct cb_process_state *cps)
405 : : {
406 : : struct nfs4_slot_table *tbl;
407 : : struct nfs_client *clp;
408 : : int i;
409 : : __be32 status = htonl(NFS4ERR_BADSESSION);
410 : :
411 : : clp = nfs4_find_client_sessionid(cps->net, args->csa_addr,
412 : : &args->csa_sessionid, cps->minorversion);
413 : : if (clp == NULL)
414 : : goto out;
415 : :
416 : : tbl = &clp->cl_session->bc_slot_table;
417 : :
418 : : spin_lock(&tbl->slot_tbl_lock);
419 : : /* state manager is resetting the session */
420 : : if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
421 : : spin_unlock(&tbl->slot_tbl_lock);
422 : : status = htonl(NFS4ERR_DELAY);
423 : : /* Return NFS4ERR_BADSESSION if we're draining the session
424 : : * in order to reset it.
425 : : */
426 : : if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
427 : : status = htonl(NFS4ERR_BADSESSION);
428 : : goto out;
429 : : }
430 : :
431 : : status = validate_seqid(&clp->cl_session->bc_slot_table, args);
432 : : spin_unlock(&tbl->slot_tbl_lock);
433 : : if (status)
434 : : goto out;
435 : :
436 : : cps->slotid = args->csa_slotid;
437 : :
438 : : /*
439 : : * Check for pending referring calls. If a match is found, a
440 : : * related callback was received before the response to the original
441 : : * call.
442 : : */
443 : : if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
444 : : status = htonl(NFS4ERR_DELAY);
445 : : goto out;
446 : : }
447 : :
448 : : memcpy(&res->csr_sessionid, &args->csa_sessionid,
449 : : sizeof(res->csr_sessionid));
450 : : res->csr_sequenceid = args->csa_sequenceid;
451 : : res->csr_slotid = args->csa_slotid;
452 : : res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
453 : : res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
454 : :
455 : : out:
456 : : cps->clp = clp; /* put in nfs4_callback_compound */
457 : : for (i = 0; i < args->csa_nrclists; i++)
458 : : kfree(args->csa_rclists[i].rcl_refcalls);
459 : : kfree(args->csa_rclists);
460 : :
461 : : if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) {
462 : : cps->drc_status = status;
463 : : status = 0;
464 : : } else
465 : : res->csr_status = status;
466 : :
467 : : trace_nfs4_cb_sequence(args, res, status);
468 : : dprintk("%s: exit with status = %d res->csr_status %d\n", __func__,
469 : : ntohl(status), ntohl(res->csr_status));
470 : : return status;
471 : : }
472 : :
473 : : static bool
474 : : validate_bitmap_values(unsigned long mask)
475 : : {
476 : : return (mask & ~RCA4_TYPE_MASK_ALL) == 0;
477 : : }
478 : :
479 : : __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
480 : : struct cb_process_state *cps)
481 : : {
482 : : __be32 status;
483 : : fmode_t flags = 0;
484 : :
485 : : status = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
486 : : if (!cps->clp) /* set in cb_sequence */
487 : : goto out;
488 : :
489 : : dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
490 : : rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
491 : :
492 : : status = cpu_to_be32(NFS4ERR_INVAL);
493 : : if (!validate_bitmap_values(args->craa_type_mask))
494 : : goto out;
495 : :
496 : : status = cpu_to_be32(NFS4_OK);
497 : : if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *)
498 : : &args->craa_type_mask))
499 : : flags = FMODE_READ;
500 : : if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *)
501 : : &args->craa_type_mask))
502 : : flags |= FMODE_WRITE;
503 : : if (test_bit(RCA4_TYPE_MASK_FILE_LAYOUT, (const unsigned long *)
504 : : &args->craa_type_mask))
505 : : pnfs_recall_all_layouts(cps->clp);
506 : : if (flags)
507 : : nfs_expire_unused_delegation_types(cps->clp, flags);
508 : : out:
509 : : dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
510 : : return status;
511 : : }
512 : :
513 : : /* Reduce the fore channel's max_slots to the target value */
514 : : __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
515 : : struct cb_process_state *cps)
516 : : {
517 : : struct nfs4_slot_table *fc_tbl;
518 : : __be32 status;
519 : :
520 : : status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
521 : : if (!cps->clp) /* set in cb_sequence */
522 : : goto out;
523 : :
524 : : dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %u\n",
525 : : rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
526 : : args->crsa_target_highest_slotid);
527 : :
528 : : fc_tbl = &cps->clp->cl_session->fc_slot_table;
529 : :
530 : : status = htonl(NFS4_OK);
531 : :
532 : : nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid);
533 : : nfs41_server_notify_target_slotid_update(cps->clp);
534 : : out:
535 : : dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
536 : : return status;
537 : : }
538 : : #endif /* CONFIG_NFS_V4_1 */
|