xref: /openbmc/linux/fs/nfs/nfs42xdr.c (revision aac5987a)
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->ld_private.ops)
185 		devinfo->ld_private.ops->encode(xdr, args,
186 				&devinfo->ld_private);
187 	else
188 		encode_uint32(xdr, 0);
189 }
190 
191 static void encode_clone(struct xdr_stream *xdr,
192 			 struct nfs42_clone_args *args,
193 			 struct compound_hdr *hdr)
194 {
195 	__be32 *p;
196 
197 	encode_op_hdr(xdr, OP_CLONE, decode_clone_maxsz, hdr);
198 	encode_nfs4_stateid(xdr, &args->src_stateid);
199 	encode_nfs4_stateid(xdr, &args->dst_stateid);
200 	p = reserve_space(xdr, 3*8);
201 	p = xdr_encode_hyper(p, args->src_offset);
202 	p = xdr_encode_hyper(p, args->dst_offset);
203 	xdr_encode_hyper(p, args->count);
204 }
205 
206 /*
207  * Encode ALLOCATE request
208  */
209 static void nfs4_xdr_enc_allocate(struct rpc_rqst *req,
210 				  struct xdr_stream *xdr,
211 				  struct nfs42_falloc_args *args)
212 {
213 	struct compound_hdr hdr = {
214 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
215 	};
216 
217 	encode_compound_hdr(xdr, req, &hdr);
218 	encode_sequence(xdr, &args->seq_args, &hdr);
219 	encode_putfh(xdr, args->falloc_fh, &hdr);
220 	encode_allocate(xdr, args, &hdr);
221 	encode_getfattr(xdr, args->falloc_bitmask, &hdr);
222 	encode_nops(&hdr);
223 }
224 
225 /*
226  * Encode COPY request
227  */
228 static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
229 			      struct xdr_stream *xdr,
230 			      struct nfs42_copy_args *args)
231 {
232 	struct compound_hdr hdr = {
233 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
234 	};
235 
236 	encode_compound_hdr(xdr, req, &hdr);
237 	encode_sequence(xdr, &args->seq_args, &hdr);
238 	encode_putfh(xdr, args->src_fh, &hdr);
239 	encode_savefh(xdr, &hdr);
240 	encode_putfh(xdr, args->dst_fh, &hdr);
241 	encode_copy(xdr, args, &hdr);
242 	encode_nops(&hdr);
243 }
244 
245 /*
246  * Encode DEALLOCATE request
247  */
248 static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
249 				    struct xdr_stream *xdr,
250 				    struct nfs42_falloc_args *args)
251 {
252 	struct compound_hdr hdr = {
253 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
254 	};
255 
256 	encode_compound_hdr(xdr, req, &hdr);
257 	encode_sequence(xdr, &args->seq_args, &hdr);
258 	encode_putfh(xdr, args->falloc_fh, &hdr);
259 	encode_deallocate(xdr, args, &hdr);
260 	encode_getfattr(xdr, args->falloc_bitmask, &hdr);
261 	encode_nops(&hdr);
262 }
263 
264 /*
265  * Encode SEEK request
266  */
267 static void nfs4_xdr_enc_seek(struct rpc_rqst *req,
268 			      struct xdr_stream *xdr,
269 			      struct nfs42_seek_args *args)
270 {
271 	struct compound_hdr hdr = {
272 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
273 	};
274 
275 	encode_compound_hdr(xdr, req, &hdr);
276 	encode_sequence(xdr, &args->seq_args, &hdr);
277 	encode_putfh(xdr, args->sa_fh, &hdr);
278 	encode_seek(xdr, args, &hdr);
279 	encode_nops(&hdr);
280 }
281 
282 /*
283  * Encode LAYOUTSTATS request
284  */
285 static void nfs4_xdr_enc_layoutstats(struct rpc_rqst *req,
286 				     struct xdr_stream *xdr,
287 				     struct nfs42_layoutstat_args *args)
288 {
289 	int i;
290 
291 	struct compound_hdr hdr = {
292 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
293 	};
294 
295 	encode_compound_hdr(xdr, req, &hdr);
296 	encode_sequence(xdr, &args->seq_args, &hdr);
297 	encode_putfh(xdr, args->fh, &hdr);
298 	WARN_ON(args->num_dev > PNFS_LAYOUTSTATS_MAXDEV);
299 	for (i = 0; i < args->num_dev; i++)
300 		encode_layoutstats(xdr, args, &args->devinfo[i], &hdr);
301 	encode_nops(&hdr);
302 }
303 
304 /*
305  * Encode CLONE request
306  */
307 static void nfs4_xdr_enc_clone(struct rpc_rqst *req,
308 			       struct xdr_stream *xdr,
309 			       struct nfs42_clone_args *args)
310 {
311 	struct compound_hdr hdr = {
312 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
313 	};
314 
315 	encode_compound_hdr(xdr, req, &hdr);
316 	encode_sequence(xdr, &args->seq_args, &hdr);
317 	encode_putfh(xdr, args->src_fh, &hdr);
318 	encode_savefh(xdr, &hdr);
319 	encode_putfh(xdr, args->dst_fh, &hdr);
320 	encode_clone(xdr, args, &hdr);
321 	encode_getfattr(xdr, args->dst_bitmask, &hdr);
322 	encode_nops(&hdr);
323 }
324 
325 static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
326 {
327 	return decode_op_hdr(xdr, OP_ALLOCATE);
328 }
329 
330 static int decode_write_response(struct xdr_stream *xdr,
331 				 struct nfs42_write_res *res)
332 {
333 	__be32 *p;
334 
335 	p = xdr_inline_decode(xdr, 4 + 8 + 4);
336 	if (unlikely(!p))
337 		goto out_overflow;
338 
339 	/*
340 	 * We never use asynchronous mode, so warn if a server returns
341 	 * a stateid.
342 	 */
343 	if (unlikely(*p != 0)) {
344 		pr_err_once("%s: server has set unrequested "
345 				"asynchronous mode\n", __func__);
346 		return -EREMOTEIO;
347 	}
348 	p++;
349 	p = xdr_decode_hyper(p, &res->count);
350 	res->verifier.committed = be32_to_cpup(p);
351 	return decode_verifier(xdr, &res->verifier.verifier);
352 
353 out_overflow:
354 	print_overflow_msg(__func__, xdr);
355 	return -EIO;
356 }
357 
358 static int decode_copy_requirements(struct xdr_stream *xdr,
359 				    struct nfs42_copy_res *res) {
360 	__be32 *p;
361 
362 	p = xdr_inline_decode(xdr, 4 + 4);
363 	if (unlikely(!p))
364 		goto out_overflow;
365 
366 	res->consecutive = be32_to_cpup(p++);
367 	res->synchronous = be32_to_cpup(p++);
368 	return 0;
369 out_overflow:
370 	print_overflow_msg(__func__, xdr);
371 	return -EIO;
372 }
373 
374 static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res)
375 {
376 	int status;
377 
378 	status = decode_op_hdr(xdr, OP_COPY);
379 	if (status == NFS4ERR_OFFLOAD_NO_REQS) {
380 		status = decode_copy_requirements(xdr, res);
381 		if (status)
382 			return status;
383 		return NFS4ERR_OFFLOAD_NO_REQS;
384 	} else if (status)
385 		return status;
386 
387 	status = decode_write_response(xdr, &res->write_res);
388 	if (status)
389 		return status;
390 
391 	return decode_copy_requirements(xdr, res);
392 }
393 
394 static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
395 {
396 	return decode_op_hdr(xdr, OP_DEALLOCATE);
397 }
398 
399 static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res)
400 {
401 	int status;
402 	__be32 *p;
403 
404 	status = decode_op_hdr(xdr, OP_SEEK);
405 	if (status)
406 		return status;
407 
408 	p = xdr_inline_decode(xdr, 4 + 8);
409 	if (unlikely(!p))
410 		goto out_overflow;
411 
412 	res->sr_eof = be32_to_cpup(p++);
413 	p = xdr_decode_hyper(p, &res->sr_offset);
414 	return 0;
415 
416 out_overflow:
417 	print_overflow_msg(__func__, xdr);
418 	return -EIO;
419 }
420 
421 static int decode_layoutstats(struct xdr_stream *xdr)
422 {
423 	return decode_op_hdr(xdr, OP_LAYOUTSTATS);
424 }
425 
426 static int decode_clone(struct xdr_stream *xdr)
427 {
428 	return decode_op_hdr(xdr, OP_CLONE);
429 }
430 
431 /*
432  * Decode ALLOCATE request
433  */
434 static int nfs4_xdr_dec_allocate(struct rpc_rqst *rqstp,
435 				 struct xdr_stream *xdr,
436 				 struct nfs42_falloc_res *res)
437 {
438 	struct compound_hdr hdr;
439 	int status;
440 
441 	status = decode_compound_hdr(xdr, &hdr);
442 	if (status)
443 		goto out;
444 	status = decode_sequence(xdr, &res->seq_res, rqstp);
445 	if (status)
446 		goto out;
447 	status = decode_putfh(xdr);
448 	if (status)
449 		goto out;
450 	status = decode_allocate(xdr, res);
451 	if (status)
452 		goto out;
453 	decode_getfattr(xdr, res->falloc_fattr, res->falloc_server);
454 out:
455 	return status;
456 }
457 
458 /*
459  * Decode COPY response
460  */
461 static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp,
462 			     struct xdr_stream *xdr,
463 			     struct nfs42_copy_res *res)
464 {
465 	struct compound_hdr hdr;
466 	int status;
467 
468 	status = decode_compound_hdr(xdr, &hdr);
469 	if (status)
470 		goto out;
471 	status = decode_sequence(xdr, &res->seq_res, rqstp);
472 	if (status)
473 		goto out;
474 	status = decode_putfh(xdr);
475 	if (status)
476 		goto out;
477 	status = decode_savefh(xdr);
478 	if (status)
479 		goto out;
480 	status = decode_putfh(xdr);
481 	if (status)
482 		goto out;
483 	status = decode_copy(xdr, res);
484 out:
485 	return status;
486 }
487 
488 /*
489  * Decode DEALLOCATE request
490  */
491 static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
492 				   struct xdr_stream *xdr,
493 				   struct nfs42_falloc_res *res)
494 {
495 	struct compound_hdr hdr;
496 	int status;
497 
498 	status = decode_compound_hdr(xdr, &hdr);
499 	if (status)
500 		goto out;
501 	status = decode_sequence(xdr, &res->seq_res, rqstp);
502 	if (status)
503 		goto out;
504 	status = decode_putfh(xdr);
505 	if (status)
506 		goto out;
507 	status = decode_deallocate(xdr, res);
508 	if (status)
509 		goto out;
510 	decode_getfattr(xdr, res->falloc_fattr, res->falloc_server);
511 out:
512 	return status;
513 }
514 
515 /*
516  * Decode SEEK request
517  */
518 static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp,
519 			     struct xdr_stream *xdr,
520 			     struct nfs42_seek_res *res)
521 {
522 	struct compound_hdr hdr;
523 	int status;
524 
525 	status = decode_compound_hdr(xdr, &hdr);
526 	if (status)
527 		goto out;
528 	status = decode_sequence(xdr, &res->seq_res, rqstp);
529 	if (status)
530 		goto out;
531 	status = decode_putfh(xdr);
532 	if (status)
533 		goto out;
534 	status = decode_seek(xdr, res);
535 out:
536 	return status;
537 }
538 
539 /*
540  * Decode LAYOUTSTATS request
541  */
542 static int nfs4_xdr_dec_layoutstats(struct rpc_rqst *rqstp,
543 				    struct xdr_stream *xdr,
544 				    struct nfs42_layoutstat_res *res)
545 {
546 	struct compound_hdr hdr;
547 	int status, i;
548 
549 	status = decode_compound_hdr(xdr, &hdr);
550 	if (status)
551 		goto out;
552 	status = decode_sequence(xdr, &res->seq_res, rqstp);
553 	if (status)
554 		goto out;
555 	status = decode_putfh(xdr);
556 	if (status)
557 		goto out;
558 	WARN_ON(res->num_dev > PNFS_LAYOUTSTATS_MAXDEV);
559 	for (i = 0; i < res->num_dev; i++) {
560 		status = decode_layoutstats(xdr);
561 		if (status)
562 			goto out;
563 	}
564 out:
565 	res->rpc_status = status;
566 	return status;
567 }
568 
569 /*
570  * Decode CLONE request
571  */
572 static int nfs4_xdr_dec_clone(struct rpc_rqst *rqstp,
573 			      struct xdr_stream *xdr,
574 			      struct nfs42_clone_res *res)
575 {
576 	struct compound_hdr hdr;
577 	int status;
578 
579 	status = decode_compound_hdr(xdr, &hdr);
580 	if (status)
581 		goto out;
582 	status = decode_sequence(xdr, &res->seq_res, rqstp);
583 	if (status)
584 		goto out;
585 	status = decode_putfh(xdr);
586 	if (status)
587 		goto out;
588 	status = decode_savefh(xdr);
589 	if (status)
590 		goto out;
591 	status = decode_putfh(xdr);
592 	if (status)
593 		goto out;
594 	status = decode_clone(xdr);
595 	if (status)
596 		goto out;
597 	status = decode_getfattr(xdr, res->dst_fattr, res->server);
598 
599 out:
600 	res->rpc_status = status;
601 	return status;
602 }
603 
604 #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */
605