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