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