Merge tag 'arc-4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
[cascardo/linux.git] / fs / nfs / nfs42xdr.c
1 /*
2  * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com>
3  */
4 #ifndef __LINUX_FS_NFS_NFS4_2XDR_H
5 #define __LINUX_FS_NFS_NFS4_2XDR_H
6
7 #include "nfs42.h"
8
9 #define encode_fallocate_maxsz          (encode_stateid_maxsz + \
10                                          2 /* offset */ + \
11                                          2 /* length */)
12 #define NFS42_WRITE_RES_SIZE            (1 /* wr_callback_id size */ +\
13                                          XDR_QUADLEN(NFS4_STATEID_SIZE) + \
14                                          2 /* wr_count */ + \
15                                          1 /* wr_committed */ + \
16                                          XDR_QUADLEN(NFS4_VERIFIER_SIZE))
17 #define encode_allocate_maxsz           (op_encode_hdr_maxsz + \
18                                          encode_fallocate_maxsz)
19 #define decode_allocate_maxsz           (op_decode_hdr_maxsz)
20 #define encode_copy_maxsz               (op_encode_hdr_maxsz +          \
21                                          XDR_QUADLEN(NFS4_STATEID_SIZE) + \
22                                          XDR_QUADLEN(NFS4_STATEID_SIZE) + \
23                                          2 + 2 + 2 + 1 + 1 + 1)
24 #define decode_copy_maxsz               (op_decode_hdr_maxsz + \
25                                          NFS42_WRITE_RES_SIZE + \
26                                          1 /* cr_consecutive */ + \
27                                          1 /* cr_synchronous */)
28 #define encode_deallocate_maxsz         (op_encode_hdr_maxsz + \
29                                          encode_fallocate_maxsz)
30 #define decode_deallocate_maxsz         (op_decode_hdr_maxsz)
31 #define encode_seek_maxsz               (op_encode_hdr_maxsz + \
32                                          encode_stateid_maxsz + \
33                                          2 /* offset */ + \
34                                          1 /* whence */)
35 #define decode_seek_maxsz               (op_decode_hdr_maxsz + \
36                                          1 /* eof */ + \
37                                          1 /* whence */ + \
38                                          2 /* offset */ + \
39                                          2 /* length */)
40 #define encode_io_info_maxsz            4
41 #define encode_layoutstats_maxsz        (op_decode_hdr_maxsz + \
42                                         2 /* offset */ + \
43                                         2 /* length */ + \
44                                         encode_stateid_maxsz + \
45                                         encode_io_info_maxsz + \
46                                         encode_io_info_maxsz + \
47                                         1 /* opaque devaddr4 length */ + \
48                                         XDR_QUADLEN(PNFS_LAYOUTSTATS_MAXSIZE))
49 #define decode_layoutstats_maxsz        (op_decode_hdr_maxsz)
50 #define encode_clone_maxsz              (encode_stateid_maxsz + \
51                                         encode_stateid_maxsz + \
52                                         2 /* src offset */ + \
53                                         2 /* dst offset */ + \
54                                         2 /* count */)
55 #define decode_clone_maxsz              (op_decode_hdr_maxsz)
56
57 #define NFS4_enc_allocate_sz            (compound_encode_hdr_maxsz + \
58                                          encode_putfh_maxsz + \
59                                          encode_allocate_maxsz + \
60                                          encode_getattr_maxsz)
61 #define NFS4_dec_allocate_sz            (compound_decode_hdr_maxsz + \
62                                          decode_putfh_maxsz + \
63                                          decode_allocate_maxsz + \
64                                          decode_getattr_maxsz)
65 #define NFS4_enc_copy_sz                (compound_encode_hdr_maxsz + \
66                                          encode_putfh_maxsz + \
67                                          encode_savefh_maxsz + \
68                                          encode_putfh_maxsz + \
69                                          encode_copy_maxsz)
70 #define NFS4_dec_copy_sz                (compound_decode_hdr_maxsz + \
71                                          decode_putfh_maxsz + \
72                                          decode_savefh_maxsz + \
73                                          decode_putfh_maxsz + \
74                                          decode_copy_maxsz)
75 #define NFS4_enc_deallocate_sz          (compound_encode_hdr_maxsz + \
76                                          encode_putfh_maxsz + \
77                                          encode_deallocate_maxsz + \
78                                          encode_getattr_maxsz)
79 #define NFS4_dec_deallocate_sz          (compound_decode_hdr_maxsz + \
80                                          decode_putfh_maxsz + \
81                                          decode_deallocate_maxsz + \
82                                          decode_getattr_maxsz)
83 #define NFS4_enc_seek_sz                (compound_encode_hdr_maxsz + \
84                                          encode_putfh_maxsz + \
85                                          encode_seek_maxsz)
86 #define NFS4_dec_seek_sz                (compound_decode_hdr_maxsz + \
87                                          decode_putfh_maxsz + \
88                                          decode_seek_maxsz)
89 #define NFS4_enc_layoutstats_sz         (compound_encode_hdr_maxsz + \
90                                          encode_sequence_maxsz + \
91                                          encode_putfh_maxsz + \
92                                          PNFS_LAYOUTSTATS_MAXDEV * encode_layoutstats_maxsz)
93 #define NFS4_dec_layoutstats_sz         (compound_decode_hdr_maxsz + \
94                                          decode_sequence_maxsz + \
95                                          decode_putfh_maxsz + \
96                                          PNFS_LAYOUTSTATS_MAXDEV * decode_layoutstats_maxsz)
97 #define NFS4_enc_clone_sz               (compound_encode_hdr_maxsz + \
98                                          encode_sequence_maxsz + \
99                                          encode_putfh_maxsz + \
100                                          encode_savefh_maxsz + \
101                                          encode_putfh_maxsz + \
102                                          encode_clone_maxsz + \
103                                          encode_getattr_maxsz)
104 #define NFS4_dec_clone_sz               (compound_decode_hdr_maxsz + \
105                                          decode_sequence_maxsz + \
106                                          decode_putfh_maxsz + \
107                                          decode_savefh_maxsz + \
108                                          decode_putfh_maxsz + \
109                                          decode_clone_maxsz + \
110                                          decode_getattr_maxsz)
111
112 static void encode_fallocate(struct xdr_stream *xdr,
113                              struct nfs42_falloc_args *args)
114 {
115         encode_nfs4_stateid(xdr, &args->falloc_stateid);
116         encode_uint64(xdr, args->falloc_offset);
117         encode_uint64(xdr, args->falloc_length);
118 }
119
120 static void encode_allocate(struct xdr_stream *xdr,
121                             struct nfs42_falloc_args *args,
122                             struct compound_hdr *hdr)
123 {
124         encode_op_hdr(xdr, OP_ALLOCATE, decode_allocate_maxsz, hdr);
125         encode_fallocate(xdr, args);
126 }
127
128 static void encode_copy(struct xdr_stream *xdr,
129                         struct nfs42_copy_args *args,
130                         struct compound_hdr *hdr)
131 {
132         encode_op_hdr(xdr, OP_COPY, decode_copy_maxsz, hdr);
133         encode_nfs4_stateid(xdr, &args->src_stateid);
134         encode_nfs4_stateid(xdr, &args->dst_stateid);
135
136         encode_uint64(xdr, args->src_pos);
137         encode_uint64(xdr, args->dst_pos);
138         encode_uint64(xdr, args->count);
139
140         encode_uint32(xdr, 1); /* consecutive = true */
141         encode_uint32(xdr, 1); /* synchronous = true */
142         encode_uint32(xdr, 0); /* src server list */
143 }
144
145 static void encode_deallocate(struct xdr_stream *xdr,
146                               struct nfs42_falloc_args *args,
147                               struct compound_hdr *hdr)
148 {
149         encode_op_hdr(xdr, OP_DEALLOCATE, decode_deallocate_maxsz, hdr);
150         encode_fallocate(xdr, args);
151 }
152
153 static void encode_seek(struct xdr_stream *xdr,
154                         struct nfs42_seek_args *args,
155                         struct compound_hdr *hdr)
156 {
157         encode_op_hdr(xdr, OP_SEEK, decode_seek_maxsz, hdr);
158         encode_nfs4_stateid(xdr, &args->sa_stateid);
159         encode_uint64(xdr, args->sa_offset);
160         encode_uint32(xdr, args->sa_what);
161 }
162
163 static void encode_layoutstats(struct xdr_stream *xdr,
164                                struct nfs42_layoutstat_args *args,
165                                struct nfs42_layoutstat_devinfo *devinfo,
166                                struct compound_hdr *hdr)
167 {
168         __be32 *p;
169
170         encode_op_hdr(xdr, OP_LAYOUTSTATS, decode_layoutstats_maxsz, hdr);
171         p = reserve_space(xdr, 8 + 8);
172         p = xdr_encode_hyper(p, devinfo->offset);
173         p = xdr_encode_hyper(p, devinfo->length);
174         encode_nfs4_stateid(xdr, &args->stateid);
175         p = reserve_space(xdr, 4*8 + NFS4_DEVICEID4_SIZE + 4);
176         p = xdr_encode_hyper(p, devinfo->read_count);
177         p = xdr_encode_hyper(p, devinfo->read_bytes);
178         p = xdr_encode_hyper(p, devinfo->write_count);
179         p = xdr_encode_hyper(p, devinfo->write_bytes);
180         p = xdr_encode_opaque_fixed(p, devinfo->dev_id.data,
181                         NFS4_DEVICEID4_SIZE);
182         /* Encode layoutupdate4 */
183         *p++ = cpu_to_be32(devinfo->layout_type);
184         if (devinfo->layoutstats_encode != NULL)
185                 devinfo->layoutstats_encode(xdr, args, devinfo);
186         else
187                 encode_uint32(xdr, 0);
188 }
189
190 static void encode_clone(struct xdr_stream *xdr,
191                          struct nfs42_clone_args *args,
192                          struct compound_hdr *hdr)
193 {
194         __be32 *p;
195
196         encode_op_hdr(xdr, OP_CLONE, decode_clone_maxsz, hdr);
197         encode_nfs4_stateid(xdr, &args->src_stateid);
198         encode_nfs4_stateid(xdr, &args->dst_stateid);
199         p = reserve_space(xdr, 3*8);
200         p = xdr_encode_hyper(p, args->src_offset);
201         p = xdr_encode_hyper(p, args->dst_offset);
202         xdr_encode_hyper(p, args->count);
203 }
204
205 /*
206  * Encode ALLOCATE request
207  */
208 static void nfs4_xdr_enc_allocate(struct rpc_rqst *req,
209                                   struct xdr_stream *xdr,
210                                   struct nfs42_falloc_args *args)
211 {
212         struct compound_hdr hdr = {
213                 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
214         };
215
216         encode_compound_hdr(xdr, req, &hdr);
217         encode_sequence(xdr, &args->seq_args, &hdr);
218         encode_putfh(xdr, args->falloc_fh, &hdr);
219         encode_allocate(xdr, args, &hdr);
220         encode_getfattr(xdr, args->falloc_bitmask, &hdr);
221         encode_nops(&hdr);
222 }
223
224 /*
225  * Encode COPY request
226  */
227 static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
228                               struct xdr_stream *xdr,
229                               struct nfs42_copy_args *args)
230 {
231         struct compound_hdr hdr = {
232                 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
233         };
234
235         encode_compound_hdr(xdr, req, &hdr);
236         encode_sequence(xdr, &args->seq_args, &hdr);
237         encode_putfh(xdr, args->src_fh, &hdr);
238         encode_savefh(xdr, &hdr);
239         encode_putfh(xdr, args->dst_fh, &hdr);
240         encode_copy(xdr, args, &hdr);
241         encode_nops(&hdr);
242 }
243
244 /*
245  * Encode DEALLOCATE request
246  */
247 static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
248                                     struct xdr_stream *xdr,
249                                     struct nfs42_falloc_args *args)
250 {
251         struct compound_hdr hdr = {
252                 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
253         };
254
255         encode_compound_hdr(xdr, req, &hdr);
256         encode_sequence(xdr, &args->seq_args, &hdr);
257         encode_putfh(xdr, args->falloc_fh, &hdr);
258         encode_deallocate(xdr, args, &hdr);
259         encode_getfattr(xdr, args->falloc_bitmask, &hdr);
260         encode_nops(&hdr);
261 }
262
263 /*
264  * Encode SEEK request
265  */
266 static void nfs4_xdr_enc_seek(struct rpc_rqst *req,
267                               struct xdr_stream *xdr,
268                               struct nfs42_seek_args *args)
269 {
270         struct compound_hdr hdr = {
271                 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
272         };
273
274         encode_compound_hdr(xdr, req, &hdr);
275         encode_sequence(xdr, &args->seq_args, &hdr);
276         encode_putfh(xdr, args->sa_fh, &hdr);
277         encode_seek(xdr, args, &hdr);
278         encode_nops(&hdr);
279 }
280
281 /*
282  * Encode LAYOUTSTATS request
283  */
284 static void nfs4_xdr_enc_layoutstats(struct rpc_rqst *req,
285                                      struct xdr_stream *xdr,
286                                      struct nfs42_layoutstat_args *args)
287 {
288         int i;
289
290         struct compound_hdr hdr = {
291                 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
292         };
293
294         encode_compound_hdr(xdr, req, &hdr);
295         encode_sequence(xdr, &args->seq_args, &hdr);
296         encode_putfh(xdr, args->fh, &hdr);
297         WARN_ON(args->num_dev > PNFS_LAYOUTSTATS_MAXDEV);
298         for (i = 0; i < args->num_dev; i++)
299                 encode_layoutstats(xdr, args, &args->devinfo[i], &hdr);
300         encode_nops(&hdr);
301 }
302
303 /*
304  * Encode CLONE request
305  */
306 static void nfs4_xdr_enc_clone(struct rpc_rqst *req,
307                                struct xdr_stream *xdr,
308                                struct nfs42_clone_args *args)
309 {
310         struct compound_hdr hdr = {
311                 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
312         };
313
314         encode_compound_hdr(xdr, req, &hdr);
315         encode_sequence(xdr, &args->seq_args, &hdr);
316         encode_putfh(xdr, args->src_fh, &hdr);
317         encode_savefh(xdr, &hdr);
318         encode_putfh(xdr, args->dst_fh, &hdr);
319         encode_clone(xdr, args, &hdr);
320         encode_getfattr(xdr, args->dst_bitmask, &hdr);
321         encode_nops(&hdr);
322 }
323
324 static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
325 {
326         return decode_op_hdr(xdr, OP_ALLOCATE);
327 }
328
329 static int decode_write_response(struct xdr_stream *xdr,
330                                  struct nfs42_write_res *res)
331 {
332         __be32 *p;
333
334         p = xdr_inline_decode(xdr, 4 + 8 + 4);
335         if (unlikely(!p))
336                 goto out_overflow;
337
338         /*
339          * We never use asynchronous mode, so warn if a server returns
340          * a stateid.
341          */
342         if (unlikely(*p != 0)) {
343                 pr_err_once("%s: server has set unrequested "
344                                 "asynchronous mode\n", __func__);
345                 return -EREMOTEIO;
346         }
347         p++;
348         p = xdr_decode_hyper(p, &res->count);
349         res->verifier.committed = be32_to_cpup(p);
350         return decode_verifier(xdr, &res->verifier.verifier);
351
352 out_overflow:
353         print_overflow_msg(__func__, xdr);
354         return -EIO;
355 }
356
357 static int decode_copy_requirements(struct xdr_stream *xdr,
358                                     struct nfs42_copy_res *res) {
359         __be32 *p;
360
361         p = xdr_inline_decode(xdr, 4 + 4);
362         if (unlikely(!p))
363                 goto out_overflow;
364
365         res->consecutive = be32_to_cpup(p++);
366         res->synchronous = be32_to_cpup(p++);
367         return 0;
368 out_overflow:
369         print_overflow_msg(__func__, xdr);
370         return -EIO;
371 }
372
373 static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res)
374 {
375         int status;
376
377         status = decode_op_hdr(xdr, OP_COPY);
378         if (status == NFS4ERR_OFFLOAD_NO_REQS) {
379                 status = decode_copy_requirements(xdr, res);
380                 if (status)
381                         return status;
382                 return NFS4ERR_OFFLOAD_NO_REQS;
383         } else if (status)
384                 return status;
385
386         status = decode_write_response(xdr, &res->write_res);
387         if (status)
388                 return status;
389
390         return decode_copy_requirements(xdr, res);
391 }
392
393 static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
394 {
395         return decode_op_hdr(xdr, OP_DEALLOCATE);
396 }
397
398 static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res)
399 {
400         int status;
401         __be32 *p;
402
403         status = decode_op_hdr(xdr, OP_SEEK);
404         if (status)
405                 return status;
406
407         p = xdr_inline_decode(xdr, 4 + 8);
408         if (unlikely(!p))
409                 goto out_overflow;
410
411         res->sr_eof = be32_to_cpup(p++);
412         p = xdr_decode_hyper(p, &res->sr_offset);
413         return 0;
414
415 out_overflow:
416         print_overflow_msg(__func__, xdr);
417         return -EIO;
418 }
419
420 static int decode_layoutstats(struct xdr_stream *xdr)
421 {
422         return decode_op_hdr(xdr, OP_LAYOUTSTATS);
423 }
424
425 static int decode_clone(struct xdr_stream *xdr)
426 {
427         return decode_op_hdr(xdr, OP_CLONE);
428 }
429
430 /*
431  * Decode ALLOCATE request
432  */
433 static int nfs4_xdr_dec_allocate(struct rpc_rqst *rqstp,
434                                  struct xdr_stream *xdr,
435                                  struct nfs42_falloc_res *res)
436 {
437         struct compound_hdr hdr;
438         int status;
439
440         status = decode_compound_hdr(xdr, &hdr);
441         if (status)
442                 goto out;
443         status = decode_sequence(xdr, &res->seq_res, rqstp);
444         if (status)
445                 goto out;
446         status = decode_putfh(xdr);
447         if (status)
448                 goto out;
449         status = decode_allocate(xdr, res);
450         if (status)
451                 goto out;
452         decode_getfattr(xdr, res->falloc_fattr, res->falloc_server);
453 out:
454         return status;
455 }
456
457 /*
458  * Decode COPY response
459  */
460 static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp,
461                              struct xdr_stream *xdr,
462                              struct nfs42_copy_res *res)
463 {
464         struct compound_hdr hdr;
465         int status;
466
467         status = decode_compound_hdr(xdr, &hdr);
468         if (status)
469                 goto out;
470         status = decode_sequence(xdr, &res->seq_res, rqstp);
471         if (status)
472                 goto out;
473         status = decode_putfh(xdr);
474         if (status)
475                 goto out;
476         status = decode_savefh(xdr);
477         if (status)
478                 goto out;
479         status = decode_putfh(xdr);
480         if (status)
481                 goto out;
482         status = decode_copy(xdr, res);
483 out:
484         return status;
485 }
486
487 /*
488  * Decode DEALLOCATE request
489  */
490 static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
491                                    struct xdr_stream *xdr,
492                                    struct nfs42_falloc_res *res)
493 {
494         struct compound_hdr hdr;
495         int status;
496
497         status = decode_compound_hdr(xdr, &hdr);
498         if (status)
499                 goto out;
500         status = decode_sequence(xdr, &res->seq_res, rqstp);
501         if (status)
502                 goto out;
503         status = decode_putfh(xdr);
504         if (status)
505                 goto out;
506         status = decode_deallocate(xdr, res);
507         if (status)
508                 goto out;
509         decode_getfattr(xdr, res->falloc_fattr, res->falloc_server);
510 out:
511         return status;
512 }
513
514 /*
515  * Decode SEEK request
516  */
517 static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp,
518                              struct xdr_stream *xdr,
519                              struct nfs42_seek_res *res)
520 {
521         struct compound_hdr hdr;
522         int status;
523
524         status = decode_compound_hdr(xdr, &hdr);
525         if (status)
526                 goto out;
527         status = decode_sequence(xdr, &res->seq_res, rqstp);
528         if (status)
529                 goto out;
530         status = decode_putfh(xdr);
531         if (status)
532                 goto out;
533         status = decode_seek(xdr, res);
534 out:
535         return status;
536 }
537
538 /*
539  * Decode LAYOUTSTATS request
540  */
541 static int nfs4_xdr_dec_layoutstats(struct rpc_rqst *rqstp,
542                                     struct xdr_stream *xdr,
543                                     struct nfs42_layoutstat_res *res)
544 {
545         struct compound_hdr hdr;
546         int status, i;
547
548         status = decode_compound_hdr(xdr, &hdr);
549         if (status)
550                 goto out;
551         status = decode_sequence(xdr, &res->seq_res, rqstp);
552         if (status)
553                 goto out;
554         status = decode_putfh(xdr);
555         if (status)
556                 goto out;
557         WARN_ON(res->num_dev > PNFS_LAYOUTSTATS_MAXDEV);
558         for (i = 0; i < res->num_dev; i++) {
559                 status = decode_layoutstats(xdr);
560                 if (status)
561                         goto out;
562         }
563 out:
564         res->rpc_status = status;
565         return status;
566 }
567
568 /*
569  * Decode CLONE request
570  */
571 static int nfs4_xdr_dec_clone(struct rpc_rqst *rqstp,
572                               struct xdr_stream *xdr,
573                               struct nfs42_clone_res *res)
574 {
575         struct compound_hdr hdr;
576         int status;
577
578         status = decode_compound_hdr(xdr, &hdr);
579         if (status)
580                 goto out;
581         status = decode_sequence(xdr, &res->seq_res, rqstp);
582         if (status)
583                 goto out;
584         status = decode_putfh(xdr);
585         if (status)
586                 goto out;
587         status = decode_savefh(xdr);
588         if (status)
589                 goto out;
590         status = decode_putfh(xdr);
591         if (status)
592                 goto out;
593         status = decode_clone(xdr);
594         if (status)
595                 goto out;
596         status = decode_getfattr(xdr, res->dst_fattr, res->server);
597
598 out:
599         res->rpc_status = status;
600         return status;
601 }
602
603 #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */