1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com> |
4 | */ |
5 | #ifndef __LINUX_FS_NFS_NFS4_2XDR_H |
6 | #define __LINUX_FS_NFS_NFS4_2XDR_H |
7 | |
8 | #include "nfs42.h" |
9 | |
10 | /* Not limited by NFS itself, limited by the generic xattr code */ |
11 | #define nfs4_xattr_name_maxsz XDR_QUADLEN(XATTR_NAME_MAX) |
12 | |
13 | #define encode_fallocate_maxsz (encode_stateid_maxsz + \ |
14 | 2 /* offset */ + \ |
15 | 2 /* length */) |
16 | #define NFS42_WRITE_RES_SIZE (1 /* wr_callback_id size */ +\ |
17 | XDR_QUADLEN(NFS4_STATEID_SIZE) + \ |
18 | 2 /* wr_count */ + \ |
19 | 1 /* wr_committed */ + \ |
20 | XDR_QUADLEN(NFS4_VERIFIER_SIZE)) |
21 | #define encode_allocate_maxsz (op_encode_hdr_maxsz + \ |
22 | encode_fallocate_maxsz) |
23 | #define decode_allocate_maxsz (op_decode_hdr_maxsz) |
24 | #define encode_copy_maxsz (op_encode_hdr_maxsz + \ |
25 | XDR_QUADLEN(NFS4_STATEID_SIZE) + \ |
26 | XDR_QUADLEN(NFS4_STATEID_SIZE) + \ |
27 | 2 + 2 + 2 + 1 + 1 + 1 +\ |
28 | 1 + /* One cnr_source_server */\ |
29 | 1 + /* nl4_type */ \ |
30 | 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT)) |
31 | #define decode_copy_maxsz (op_decode_hdr_maxsz + \ |
32 | NFS42_WRITE_RES_SIZE + \ |
33 | 1 /* cr_consecutive */ + \ |
34 | 1 /* cr_synchronous */) |
35 | #define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \ |
36 | XDR_QUADLEN(NFS4_STATEID_SIZE)) |
37 | #define decode_offload_cancel_maxsz (op_decode_hdr_maxsz) |
38 | #define encode_copy_notify_maxsz (op_encode_hdr_maxsz + \ |
39 | XDR_QUADLEN(NFS4_STATEID_SIZE) + \ |
40 | 1 + /* nl4_type */ \ |
41 | 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT)) |
42 | #define decode_copy_notify_maxsz (op_decode_hdr_maxsz + \ |
43 | 3 + /* cnr_lease_time */\ |
44 | XDR_QUADLEN(NFS4_STATEID_SIZE) + \ |
45 | 1 + /* Support 1 cnr_source_server */\ |
46 | 1 + /* nl4_type */ \ |
47 | 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT)) |
48 | #define encode_deallocate_maxsz (op_encode_hdr_maxsz + \ |
49 | encode_fallocate_maxsz) |
50 | #define decode_deallocate_maxsz (op_decode_hdr_maxsz) |
51 | #define encode_read_plus_maxsz (op_encode_hdr_maxsz + \ |
52 | encode_stateid_maxsz + 3) |
53 | #define NFS42_READ_PLUS_DATA_SEGMENT_SIZE \ |
54 | (1 /* data_content4 */ + \ |
55 | 2 /* data_info4.di_offset */ + \ |
56 | 1 /* data_info4.di_length */) |
57 | #define NFS42_READ_PLUS_HOLE_SEGMENT_SIZE \ |
58 | (1 /* data_content4 */ + \ |
59 | 2 /* data_info4.di_offset */ + \ |
60 | 2 /* data_info4.di_length */) |
61 | #define READ_PLUS_SEGMENT_SIZE_DIFF (NFS42_READ_PLUS_HOLE_SEGMENT_SIZE - \ |
62 | NFS42_READ_PLUS_DATA_SEGMENT_SIZE) |
63 | #define decode_read_plus_maxsz (op_decode_hdr_maxsz + \ |
64 | 1 /* rpr_eof */ + \ |
65 | 1 /* rpr_contents count */ + \ |
66 | NFS42_READ_PLUS_HOLE_SEGMENT_SIZE) |
67 | #define encode_seek_maxsz (op_encode_hdr_maxsz + \ |
68 | encode_stateid_maxsz + \ |
69 | 2 /* offset */ + \ |
70 | 1 /* whence */) |
71 | #define decode_seek_maxsz (op_decode_hdr_maxsz + \ |
72 | 1 /* eof */ + \ |
73 | 1 /* whence */ + \ |
74 | 2 /* offset */ + \ |
75 | 2 /* length */) |
76 | #define encode_io_info_maxsz 4 |
77 | #define encode_layoutstats_maxsz (op_decode_hdr_maxsz + \ |
78 | 2 /* offset */ + \ |
79 | 2 /* length */ + \ |
80 | encode_stateid_maxsz + \ |
81 | encode_io_info_maxsz + \ |
82 | encode_io_info_maxsz + \ |
83 | 1 /* opaque devaddr4 length */ + \ |
84 | XDR_QUADLEN(PNFS_LAYOUTSTATS_MAXSIZE)) |
85 | #define decode_layoutstats_maxsz (op_decode_hdr_maxsz) |
86 | #define encode_device_error_maxsz (XDR_QUADLEN(NFS4_DEVICEID4_SIZE) + \ |
87 | 1 /* status */ + 1 /* opnum */) |
88 | #define encode_layouterror_maxsz (op_decode_hdr_maxsz + \ |
89 | 2 /* offset */ + \ |
90 | 2 /* length */ + \ |
91 | encode_stateid_maxsz + \ |
92 | 1 /* Array size */ + \ |
93 | encode_device_error_maxsz) |
94 | #define decode_layouterror_maxsz (op_decode_hdr_maxsz) |
95 | #define encode_clone_maxsz (encode_stateid_maxsz + \ |
96 | encode_stateid_maxsz + \ |
97 | 2 /* src offset */ + \ |
98 | 2 /* dst offset */ + \ |
99 | 2 /* count */) |
100 | #define decode_clone_maxsz (op_decode_hdr_maxsz) |
101 | #define encode_getxattr_maxsz (op_encode_hdr_maxsz + 1 + \ |
102 | nfs4_xattr_name_maxsz) |
103 | #define decode_getxattr_maxsz (op_decode_hdr_maxsz + 1 + pagepad_maxsz) |
104 | #define encode_setxattr_maxsz (op_encode_hdr_maxsz + \ |
105 | 1 + nfs4_xattr_name_maxsz + 1) |
106 | #define decode_setxattr_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
107 | #define encode_listxattrs_maxsz (op_encode_hdr_maxsz + 2 + 1) |
108 | #define decode_listxattrs_maxsz (op_decode_hdr_maxsz + 2 + 1 + 1 + 1) |
109 | #define encode_removexattr_maxsz (op_encode_hdr_maxsz + 1 + \ |
110 | nfs4_xattr_name_maxsz) |
111 | #define decode_removexattr_maxsz (op_decode_hdr_maxsz + \ |
112 | decode_change_info_maxsz) |
113 | |
114 | #define NFS4_enc_allocate_sz (compound_encode_hdr_maxsz + \ |
115 | encode_sequence_maxsz + \ |
116 | encode_putfh_maxsz + \ |
117 | encode_allocate_maxsz + \ |
118 | encode_getattr_maxsz) |
119 | #define NFS4_dec_allocate_sz (compound_decode_hdr_maxsz + \ |
120 | decode_sequence_maxsz + \ |
121 | decode_putfh_maxsz + \ |
122 | decode_allocate_maxsz + \ |
123 | decode_getattr_maxsz) |
124 | #define NFS4_enc_copy_sz (compound_encode_hdr_maxsz + \ |
125 | encode_sequence_maxsz + \ |
126 | encode_putfh_maxsz + \ |
127 | encode_savefh_maxsz + \ |
128 | encode_putfh_maxsz + \ |
129 | encode_copy_maxsz + \ |
130 | encode_commit_maxsz) |
131 | #define NFS4_dec_copy_sz (compound_decode_hdr_maxsz + \ |
132 | decode_sequence_maxsz + \ |
133 | decode_putfh_maxsz + \ |
134 | decode_savefh_maxsz + \ |
135 | decode_putfh_maxsz + \ |
136 | decode_copy_maxsz + \ |
137 | decode_commit_maxsz) |
138 | #define NFS4_enc_offload_cancel_sz (compound_encode_hdr_maxsz + \ |
139 | encode_sequence_maxsz + \ |
140 | encode_putfh_maxsz + \ |
141 | encode_offload_cancel_maxsz) |
142 | #define NFS4_dec_offload_cancel_sz (compound_decode_hdr_maxsz + \ |
143 | decode_sequence_maxsz + \ |
144 | decode_putfh_maxsz + \ |
145 | decode_offload_cancel_maxsz) |
146 | #define NFS4_enc_copy_notify_sz (compound_encode_hdr_maxsz + \ |
147 | encode_putfh_maxsz + \ |
148 | encode_copy_notify_maxsz) |
149 | #define NFS4_dec_copy_notify_sz (compound_decode_hdr_maxsz + \ |
150 | decode_putfh_maxsz + \ |
151 | decode_copy_notify_maxsz) |
152 | #define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \ |
153 | encode_sequence_maxsz + \ |
154 | encode_putfh_maxsz + \ |
155 | encode_deallocate_maxsz + \ |
156 | encode_getattr_maxsz) |
157 | #define NFS4_dec_deallocate_sz (compound_decode_hdr_maxsz + \ |
158 | decode_sequence_maxsz + \ |
159 | decode_putfh_maxsz + \ |
160 | decode_deallocate_maxsz + \ |
161 | decode_getattr_maxsz) |
162 | #define NFS4_enc_read_plus_sz (compound_encode_hdr_maxsz + \ |
163 | encode_sequence_maxsz + \ |
164 | encode_putfh_maxsz + \ |
165 | encode_read_plus_maxsz) |
166 | #define NFS4_dec_read_plus_sz (compound_decode_hdr_maxsz + \ |
167 | decode_sequence_maxsz + \ |
168 | decode_putfh_maxsz + \ |
169 | decode_read_plus_maxsz) |
170 | #define NFS4_enc_seek_sz (compound_encode_hdr_maxsz + \ |
171 | encode_sequence_maxsz + \ |
172 | encode_putfh_maxsz + \ |
173 | encode_seek_maxsz) |
174 | #define NFS4_dec_seek_sz (compound_decode_hdr_maxsz + \ |
175 | decode_sequence_maxsz + \ |
176 | decode_putfh_maxsz + \ |
177 | decode_seek_maxsz) |
178 | #define NFS4_enc_layoutstats_sz (compound_encode_hdr_maxsz + \ |
179 | encode_sequence_maxsz + \ |
180 | encode_putfh_maxsz + \ |
181 | PNFS_LAYOUTSTATS_MAXDEV * encode_layoutstats_maxsz) |
182 | #define NFS4_dec_layoutstats_sz (compound_decode_hdr_maxsz + \ |
183 | decode_sequence_maxsz + \ |
184 | decode_putfh_maxsz + \ |
185 | PNFS_LAYOUTSTATS_MAXDEV * decode_layoutstats_maxsz) |
186 | #define NFS4_enc_layouterror_sz (compound_encode_hdr_maxsz + \ |
187 | encode_sequence_maxsz + \ |
188 | encode_putfh_maxsz + \ |
189 | NFS42_LAYOUTERROR_MAX * \ |
190 | encode_layouterror_maxsz) |
191 | #define NFS4_dec_layouterror_sz (compound_decode_hdr_maxsz + \ |
192 | decode_sequence_maxsz + \ |
193 | decode_putfh_maxsz + \ |
194 | NFS42_LAYOUTERROR_MAX * \ |
195 | decode_layouterror_maxsz) |
196 | #define NFS4_enc_clone_sz (compound_encode_hdr_maxsz + \ |
197 | encode_sequence_maxsz + \ |
198 | encode_putfh_maxsz + \ |
199 | encode_savefh_maxsz + \ |
200 | encode_putfh_maxsz + \ |
201 | encode_clone_maxsz + \ |
202 | encode_getattr_maxsz) |
203 | #define NFS4_dec_clone_sz (compound_decode_hdr_maxsz + \ |
204 | decode_sequence_maxsz + \ |
205 | decode_putfh_maxsz + \ |
206 | decode_savefh_maxsz + \ |
207 | decode_putfh_maxsz + \ |
208 | decode_clone_maxsz + \ |
209 | decode_getattr_maxsz) |
210 | #define NFS4_enc_getxattr_sz (compound_encode_hdr_maxsz + \ |
211 | encode_sequence_maxsz + \ |
212 | encode_putfh_maxsz + \ |
213 | encode_getxattr_maxsz) |
214 | #define NFS4_dec_getxattr_sz (compound_decode_hdr_maxsz + \ |
215 | decode_sequence_maxsz + \ |
216 | decode_putfh_maxsz + \ |
217 | decode_getxattr_maxsz) |
218 | #define NFS4_enc_setxattr_sz (compound_encode_hdr_maxsz + \ |
219 | encode_sequence_maxsz + \ |
220 | encode_putfh_maxsz + \ |
221 | encode_setxattr_maxsz + \ |
222 | encode_getattr_maxsz) |
223 | #define NFS4_dec_setxattr_sz (compound_decode_hdr_maxsz + \ |
224 | decode_sequence_maxsz + \ |
225 | decode_putfh_maxsz + \ |
226 | decode_setxattr_maxsz + \ |
227 | decode_getattr_maxsz) |
228 | #define NFS4_enc_listxattrs_sz (compound_encode_hdr_maxsz + \ |
229 | encode_sequence_maxsz + \ |
230 | encode_putfh_maxsz + \ |
231 | encode_listxattrs_maxsz) |
232 | #define NFS4_dec_listxattrs_sz (compound_decode_hdr_maxsz + \ |
233 | decode_sequence_maxsz + \ |
234 | decode_putfh_maxsz + \ |
235 | decode_listxattrs_maxsz) |
236 | #define NFS4_enc_removexattr_sz (compound_encode_hdr_maxsz + \ |
237 | encode_sequence_maxsz + \ |
238 | encode_putfh_maxsz + \ |
239 | encode_removexattr_maxsz) |
240 | #define NFS4_dec_removexattr_sz (compound_decode_hdr_maxsz + \ |
241 | decode_sequence_maxsz + \ |
242 | decode_putfh_maxsz + \ |
243 | decode_removexattr_maxsz) |
244 | |
245 | /* |
246 | * These values specify the maximum amount of data that is not |
247 | * associated with the extended attribute name or extended |
248 | * attribute list in the SETXATTR, GETXATTR and LISTXATTR |
249 | * respectively. |
250 | */ |
251 | const u32 nfs42_maxsetxattr_overhead = ((RPC_MAX_HEADER_WITH_AUTH + |
252 | compound_encode_hdr_maxsz + |
253 | encode_sequence_maxsz + |
254 | encode_putfh_maxsz + 1 + |
255 | nfs4_xattr_name_maxsz) |
256 | * XDR_UNIT); |
257 | |
258 | const u32 nfs42_maxgetxattr_overhead = ((RPC_MAX_HEADER_WITH_AUTH + |
259 | compound_decode_hdr_maxsz + |
260 | decode_sequence_maxsz + |
261 | decode_putfh_maxsz + 1) * XDR_UNIT); |
262 | |
263 | const u32 nfs42_maxlistxattrs_overhead = ((RPC_MAX_HEADER_WITH_AUTH + |
264 | compound_decode_hdr_maxsz + |
265 | decode_sequence_maxsz + |
266 | decode_putfh_maxsz + 3) * XDR_UNIT); |
267 | |
268 | static void encode_fallocate(struct xdr_stream *xdr, |
269 | const struct nfs42_falloc_args *args) |
270 | { |
271 | encode_nfs4_stateid(xdr, &args->falloc_stateid); |
272 | encode_uint64(xdr, args->falloc_offset); |
273 | encode_uint64(xdr, args->falloc_length); |
274 | } |
275 | |
276 | static void encode_allocate(struct xdr_stream *xdr, |
277 | const struct nfs42_falloc_args *args, |
278 | struct compound_hdr *hdr) |
279 | { |
280 | encode_op_hdr(xdr, OP_ALLOCATE, decode_allocate_maxsz, hdr); |
281 | encode_fallocate(xdr, args); |
282 | } |
283 | |
284 | static void encode_nl4_server(struct xdr_stream *xdr, |
285 | const struct nl4_server *ns) |
286 | { |
287 | encode_uint32(xdr, ns->nl4_type); |
288 | switch (ns->nl4_type) { |
289 | case NL4_NAME: |
290 | case NL4_URL: |
291 | encode_string(xdr, ns->u.nl4_str_sz, ns->u.nl4_str); |
292 | break; |
293 | case NL4_NETADDR: |
294 | encode_string(xdr, ns->u.nl4_addr.netid_len, |
295 | ns->u.nl4_addr.netid); |
296 | encode_string(xdr, ns->u.nl4_addr.addr_len, |
297 | ns->u.nl4_addr.addr); |
298 | break; |
299 | default: |
300 | WARN_ON_ONCE(1); |
301 | } |
302 | } |
303 | |
304 | static void encode_copy(struct xdr_stream *xdr, |
305 | const struct nfs42_copy_args *args, |
306 | struct compound_hdr *hdr) |
307 | { |
308 | encode_op_hdr(xdr, OP_COPY, decode_copy_maxsz, hdr); |
309 | encode_nfs4_stateid(xdr, &args->src_stateid); |
310 | encode_nfs4_stateid(xdr, &args->dst_stateid); |
311 | |
312 | encode_uint64(xdr, args->src_pos); |
313 | encode_uint64(xdr, args->dst_pos); |
314 | encode_uint64(xdr, args->count); |
315 | |
316 | encode_uint32(xdr, 1); /* consecutive = true */ |
317 | encode_uint32(xdr, args->sync); |
318 | if (args->cp_src == NULL) { /* intra-ssc */ |
319 | encode_uint32(xdr, 0); /* no src server list */ |
320 | return; |
321 | } |
322 | encode_uint32(xdr, 1); /* supporting 1 server */ |
323 | encode_nl4_server(xdr, ns: args->cp_src); |
324 | } |
325 | |
326 | static void encode_copy_commit(struct xdr_stream *xdr, |
327 | const struct nfs42_copy_args *args, |
328 | struct compound_hdr *hdr) |
329 | { |
330 | __be32 *p; |
331 | |
332 | encode_op_hdr(xdr, OP_COMMIT, decode_commit_maxsz, hdr); |
333 | p = reserve_space(xdr, 12); |
334 | p = xdr_encode_hyper(p, args->dst_pos); |
335 | *p = cpu_to_be32(args->count); |
336 | } |
337 | |
338 | static void encode_offload_cancel(struct xdr_stream *xdr, |
339 | const struct nfs42_offload_status_args *args, |
340 | struct compound_hdr *hdr) |
341 | { |
342 | encode_op_hdr(xdr, OP_OFFLOAD_CANCEL, decode_offload_cancel_maxsz, hdr); |
343 | encode_nfs4_stateid(xdr, &args->osa_stateid); |
344 | } |
345 | |
346 | static void encode_copy_notify(struct xdr_stream *xdr, |
347 | const struct nfs42_copy_notify_args *args, |
348 | struct compound_hdr *hdr) |
349 | { |
350 | encode_op_hdr(xdr, OP_COPY_NOTIFY, decode_copy_notify_maxsz, hdr); |
351 | encode_nfs4_stateid(xdr, &args->cna_src_stateid); |
352 | encode_nl4_server(xdr, ns: &args->cna_dst); |
353 | } |
354 | |
355 | static void encode_deallocate(struct xdr_stream *xdr, |
356 | const struct nfs42_falloc_args *args, |
357 | struct compound_hdr *hdr) |
358 | { |
359 | encode_op_hdr(xdr, OP_DEALLOCATE, decode_deallocate_maxsz, hdr); |
360 | encode_fallocate(xdr, args); |
361 | } |
362 | |
363 | static void encode_read_plus(struct xdr_stream *xdr, |
364 | const struct nfs_pgio_args *args, |
365 | struct compound_hdr *hdr) |
366 | { |
367 | encode_op_hdr(xdr, OP_READ_PLUS, decode_read_plus_maxsz, hdr); |
368 | encode_nfs4_stateid(xdr, &args->stateid); |
369 | encode_uint64(xdr, args->offset); |
370 | encode_uint32(xdr, args->count); |
371 | } |
372 | |
373 | static void encode_seek(struct xdr_stream *xdr, |
374 | const struct nfs42_seek_args *args, |
375 | struct compound_hdr *hdr) |
376 | { |
377 | encode_op_hdr(xdr, OP_SEEK, decode_seek_maxsz, hdr); |
378 | encode_nfs4_stateid(xdr, &args->sa_stateid); |
379 | encode_uint64(xdr, args->sa_offset); |
380 | encode_uint32(xdr, args->sa_what); |
381 | } |
382 | |
383 | static void encode_layoutstats(struct xdr_stream *xdr, |
384 | const struct nfs42_layoutstat_args *args, |
385 | struct nfs42_layoutstat_devinfo *devinfo, |
386 | struct compound_hdr *hdr) |
387 | { |
388 | __be32 *p; |
389 | |
390 | encode_op_hdr(xdr, OP_LAYOUTSTATS, decode_layoutstats_maxsz, hdr); |
391 | p = reserve_space(xdr, 8 + 8); |
392 | p = xdr_encode_hyper(p, devinfo->offset); |
393 | p = xdr_encode_hyper(p, devinfo->length); |
394 | encode_nfs4_stateid(xdr, &args->stateid); |
395 | p = reserve_space(xdr, 4*8 + NFS4_DEVICEID4_SIZE + 4); |
396 | p = xdr_encode_hyper(p, devinfo->read_count); |
397 | p = xdr_encode_hyper(p, devinfo->read_bytes); |
398 | p = xdr_encode_hyper(p, devinfo->write_count); |
399 | p = xdr_encode_hyper(p, devinfo->write_bytes); |
400 | p = xdr_encode_opaque_fixed(p, devinfo->dev_id.data, |
401 | NFS4_DEVICEID4_SIZE); |
402 | /* Encode layoutupdate4 */ |
403 | *p++ = cpu_to_be32(devinfo->layout_type); |
404 | if (devinfo->ld_private.ops) |
405 | devinfo->ld_private.ops->encode(xdr, args, |
406 | &devinfo->ld_private); |
407 | else |
408 | encode_uint32(xdr, 0); |
409 | } |
410 | |
411 | static void encode_clone(struct xdr_stream *xdr, |
412 | const struct nfs42_clone_args *args, |
413 | struct compound_hdr *hdr) |
414 | { |
415 | __be32 *p; |
416 | |
417 | encode_op_hdr(xdr, OP_CLONE, decode_clone_maxsz, hdr); |
418 | encode_nfs4_stateid(xdr, &args->src_stateid); |
419 | encode_nfs4_stateid(xdr, &args->dst_stateid); |
420 | p = reserve_space(xdr, 3*8); |
421 | p = xdr_encode_hyper(p, args->src_offset); |
422 | p = xdr_encode_hyper(p, args->dst_offset); |
423 | xdr_encode_hyper(p, args->count); |
424 | } |
425 | |
426 | static void encode_device_error(struct xdr_stream *xdr, |
427 | const struct nfs42_device_error *error) |
428 | { |
429 | __be32 *p; |
430 | |
431 | p = reserve_space(xdr, NFS4_DEVICEID4_SIZE + 2*4); |
432 | p = xdr_encode_opaque_fixed(p, error->dev_id.data, |
433 | NFS4_DEVICEID4_SIZE); |
434 | *p++ = cpu_to_be32(error->status); |
435 | *p = cpu_to_be32(error->opnum); |
436 | } |
437 | |
438 | static void encode_layouterror(struct xdr_stream *xdr, |
439 | const struct nfs42_layout_error *args, |
440 | struct compound_hdr *hdr) |
441 | { |
442 | __be32 *p; |
443 | |
444 | encode_op_hdr(xdr, OP_LAYOUTERROR, decode_layouterror_maxsz, hdr); |
445 | p = reserve_space(xdr, 8 + 8); |
446 | p = xdr_encode_hyper(p, args->offset); |
447 | p = xdr_encode_hyper(p, args->length); |
448 | encode_nfs4_stateid(xdr, &args->stateid); |
449 | p = reserve_space(xdr, 4); |
450 | *p = cpu_to_be32(1); |
451 | encode_device_error(xdr, error: &args->errors[0]); |
452 | } |
453 | |
454 | static void encode_setxattr(struct xdr_stream *xdr, |
455 | const struct nfs42_setxattrargs *arg, |
456 | struct compound_hdr *hdr) |
457 | { |
458 | __be32 *p; |
459 | |
460 | BUILD_BUG_ON(XATTR_CREATE != SETXATTR4_CREATE); |
461 | BUILD_BUG_ON(XATTR_REPLACE != SETXATTR4_REPLACE); |
462 | |
463 | encode_op_hdr(xdr, OP_SETXATTR, decode_setxattr_maxsz, hdr); |
464 | p = reserve_space(xdr, 4); |
465 | *p = cpu_to_be32(arg->xattr_flags); |
466 | encode_string(xdr, strlen(arg->xattr_name), arg->xattr_name); |
467 | p = reserve_space(xdr, 4); |
468 | *p = cpu_to_be32(arg->xattr_len); |
469 | if (arg->xattr_len) |
470 | xdr_write_pages(xdr, arg->xattr_pages, 0, arg->xattr_len); |
471 | } |
472 | |
473 | static void encode_getxattr(struct xdr_stream *xdr, const char *name, |
474 | struct compound_hdr *hdr) |
475 | { |
476 | encode_op_hdr(xdr, OP_GETXATTR, decode_getxattr_maxsz, hdr); |
477 | encode_string(xdr, strlen(name), name); |
478 | } |
479 | |
480 | static void encode_removexattr(struct xdr_stream *xdr, const char *name, |
481 | struct compound_hdr *hdr) |
482 | { |
483 | encode_op_hdr(xdr, OP_REMOVEXATTR, decode_removexattr_maxsz, hdr); |
484 | encode_string(xdr, strlen(name), name); |
485 | } |
486 | |
487 | static void encode_listxattrs(struct xdr_stream *xdr, |
488 | const struct nfs42_listxattrsargs *arg, |
489 | struct compound_hdr *hdr) |
490 | { |
491 | __be32 *p; |
492 | |
493 | encode_op_hdr(xdr, OP_LISTXATTRS, decode_listxattrs_maxsz, hdr); |
494 | |
495 | p = reserve_space(xdr, 12); |
496 | if (unlikely(!p)) |
497 | return; |
498 | |
499 | p = xdr_encode_hyper(p, arg->cookie); |
500 | /* |
501 | * RFC 8276 says to specify the full max length of the LISTXATTRS |
502 | * XDR reply. Count is set to the XDR length of the names array |
503 | * plus the EOF marker. So, add the cookie and the names count. |
504 | */ |
505 | *p = cpu_to_be32(arg->count + 8 + 4); |
506 | } |
507 | |
508 | /* |
509 | * Encode ALLOCATE request |
510 | */ |
511 | static void nfs4_xdr_enc_allocate(struct rpc_rqst *req, |
512 | struct xdr_stream *xdr, |
513 | const void *data) |
514 | { |
515 | const struct nfs42_falloc_args *args = data; |
516 | struct compound_hdr hdr = { |
517 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
518 | }; |
519 | |
520 | encode_compound_hdr(xdr, req, &hdr); |
521 | encode_sequence(xdr, &args->seq_args, &hdr); |
522 | encode_putfh(xdr, args->falloc_fh, &hdr); |
523 | encode_allocate(xdr, args, hdr: &hdr); |
524 | encode_getfattr(xdr, args->falloc_bitmask, &hdr); |
525 | encode_nops(&hdr); |
526 | } |
527 | |
528 | /* |
529 | * Encode COPY request |
530 | */ |
531 | static void nfs4_xdr_enc_copy(struct rpc_rqst *req, |
532 | struct xdr_stream *xdr, |
533 | const void *data) |
534 | { |
535 | const struct nfs42_copy_args *args = data; |
536 | struct compound_hdr hdr = { |
537 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
538 | }; |
539 | |
540 | encode_compound_hdr(xdr, req, &hdr); |
541 | encode_sequence(xdr, &args->seq_args, &hdr); |
542 | encode_putfh(xdr, args->src_fh, &hdr); |
543 | encode_savefh(xdr, &hdr); |
544 | encode_putfh(xdr, args->dst_fh, &hdr); |
545 | encode_copy(xdr, args, hdr: &hdr); |
546 | if (args->sync) |
547 | encode_copy_commit(xdr, args, hdr: &hdr); |
548 | encode_nops(&hdr); |
549 | } |
550 | |
551 | /* |
552 | * Encode OFFLOAD_CANEL request |
553 | */ |
554 | static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req, |
555 | struct xdr_stream *xdr, |
556 | const void *data) |
557 | { |
558 | const struct nfs42_offload_status_args *args = data; |
559 | struct compound_hdr hdr = { |
560 | .minorversion = nfs4_xdr_minorversion(&args->osa_seq_args), |
561 | }; |
562 | |
563 | encode_compound_hdr(xdr, req, &hdr); |
564 | encode_sequence(xdr, &args->osa_seq_args, &hdr); |
565 | encode_putfh(xdr, args->osa_src_fh, &hdr); |
566 | encode_offload_cancel(xdr, args, hdr: &hdr); |
567 | encode_nops(&hdr); |
568 | } |
569 | |
570 | /* |
571 | * Encode COPY_NOTIFY request |
572 | */ |
573 | static void nfs4_xdr_enc_copy_notify(struct rpc_rqst *req, |
574 | struct xdr_stream *xdr, |
575 | const void *data) |
576 | { |
577 | const struct nfs42_copy_notify_args *args = data; |
578 | struct compound_hdr hdr = { |
579 | .minorversion = nfs4_xdr_minorversion(&args->cna_seq_args), |
580 | }; |
581 | |
582 | encode_compound_hdr(xdr, req, &hdr); |
583 | encode_sequence(xdr, &args->cna_seq_args, &hdr); |
584 | encode_putfh(xdr, args->cna_src_fh, &hdr); |
585 | encode_copy_notify(xdr, args, hdr: &hdr); |
586 | encode_nops(&hdr); |
587 | } |
588 | |
589 | /* |
590 | * Encode DEALLOCATE request |
591 | */ |
592 | static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req, |
593 | struct xdr_stream *xdr, |
594 | const void *data) |
595 | { |
596 | const struct nfs42_falloc_args *args = data; |
597 | struct compound_hdr hdr = { |
598 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
599 | }; |
600 | |
601 | encode_compound_hdr(xdr, req, &hdr); |
602 | encode_sequence(xdr, &args->seq_args, &hdr); |
603 | encode_putfh(xdr, args->falloc_fh, &hdr); |
604 | encode_deallocate(xdr, args, hdr: &hdr); |
605 | encode_getfattr(xdr, args->falloc_bitmask, &hdr); |
606 | encode_nops(&hdr); |
607 | } |
608 | |
609 | /* |
610 | * Encode READ_PLUS request |
611 | */ |
612 | static void nfs4_xdr_enc_read_plus(struct rpc_rqst *req, |
613 | struct xdr_stream *xdr, |
614 | const void *data) |
615 | { |
616 | const struct nfs_pgio_args *args = data; |
617 | struct compound_hdr hdr = { |
618 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
619 | }; |
620 | |
621 | encode_compound_hdr(xdr, req, &hdr); |
622 | encode_sequence(xdr, &args->seq_args, &hdr); |
623 | encode_putfh(xdr, args->fh, &hdr); |
624 | encode_read_plus(xdr, args, hdr: &hdr); |
625 | |
626 | rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->count, |
627 | hdr.replen - READ_PLUS_SEGMENT_SIZE_DIFF); |
628 | encode_nops(&hdr); |
629 | } |
630 | |
631 | /* |
632 | * Encode SEEK request |
633 | */ |
634 | static void nfs4_xdr_enc_seek(struct rpc_rqst *req, |
635 | struct xdr_stream *xdr, |
636 | const void *data) |
637 | { |
638 | const struct nfs42_seek_args *args = data; |
639 | struct compound_hdr hdr = { |
640 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
641 | }; |
642 | |
643 | encode_compound_hdr(xdr, req, &hdr); |
644 | encode_sequence(xdr, &args->seq_args, &hdr); |
645 | encode_putfh(xdr, args->sa_fh, &hdr); |
646 | encode_seek(xdr, args, hdr: &hdr); |
647 | encode_nops(&hdr); |
648 | } |
649 | |
650 | /* |
651 | * Encode LAYOUTSTATS request |
652 | */ |
653 | static void nfs4_xdr_enc_layoutstats(struct rpc_rqst *req, |
654 | struct xdr_stream *xdr, |
655 | const void *data) |
656 | { |
657 | const struct nfs42_layoutstat_args *args = data; |
658 | int i; |
659 | |
660 | struct compound_hdr hdr = { |
661 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
662 | }; |
663 | |
664 | encode_compound_hdr(xdr, req, &hdr); |
665 | encode_sequence(xdr, &args->seq_args, &hdr); |
666 | encode_putfh(xdr, args->fh, &hdr); |
667 | WARN_ON(args->num_dev > PNFS_LAYOUTSTATS_MAXDEV); |
668 | for (i = 0; i < args->num_dev; i++) |
669 | encode_layoutstats(xdr, args, devinfo: &args->devinfo[i], hdr: &hdr); |
670 | encode_nops(&hdr); |
671 | } |
672 | |
673 | /* |
674 | * Encode CLONE request |
675 | */ |
676 | static void nfs4_xdr_enc_clone(struct rpc_rqst *req, |
677 | struct xdr_stream *xdr, |
678 | const void *data) |
679 | { |
680 | const struct nfs42_clone_args *args = data; |
681 | struct compound_hdr hdr = { |
682 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
683 | }; |
684 | |
685 | encode_compound_hdr(xdr, req, &hdr); |
686 | encode_sequence(xdr, &args->seq_args, &hdr); |
687 | encode_putfh(xdr, args->src_fh, &hdr); |
688 | encode_savefh(xdr, &hdr); |
689 | encode_putfh(xdr, args->dst_fh, &hdr); |
690 | encode_clone(xdr, args, hdr: &hdr); |
691 | encode_getfattr(xdr, args->dst_bitmask, &hdr); |
692 | encode_nops(&hdr); |
693 | } |
694 | |
695 | /* |
696 | * Encode LAYOUTERROR request |
697 | */ |
698 | static void nfs4_xdr_enc_layouterror(struct rpc_rqst *req, |
699 | struct xdr_stream *xdr, |
700 | const void *data) |
701 | { |
702 | const struct nfs42_layouterror_args *args = data; |
703 | struct compound_hdr hdr = { |
704 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
705 | }; |
706 | int i; |
707 | |
708 | encode_compound_hdr(xdr, req, &hdr); |
709 | encode_sequence(xdr, &args->seq_args, &hdr); |
710 | encode_putfh(xdr, NFS_FH(args->inode), &hdr); |
711 | for (i = 0; i < args->num_errors; i++) |
712 | encode_layouterror(xdr, args: &args->errors[i], hdr: &hdr); |
713 | encode_nops(&hdr); |
714 | } |
715 | |
716 | /* |
717 | * Encode SETXATTR request |
718 | */ |
719 | static void nfs4_xdr_enc_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr, |
720 | const void *data) |
721 | { |
722 | const struct nfs42_setxattrargs *args = data; |
723 | struct compound_hdr hdr = { |
724 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
725 | }; |
726 | |
727 | encode_compound_hdr(xdr, req, &hdr); |
728 | encode_sequence(xdr, &args->seq_args, &hdr); |
729 | encode_putfh(xdr, args->fh, &hdr); |
730 | encode_setxattr(xdr, arg: args, hdr: &hdr); |
731 | encode_getfattr(xdr, args->bitmask, &hdr); |
732 | encode_nops(&hdr); |
733 | } |
734 | |
735 | /* |
736 | * Encode GETXATTR request |
737 | */ |
738 | static void nfs4_xdr_enc_getxattr(struct rpc_rqst *req, struct xdr_stream *xdr, |
739 | const void *data) |
740 | { |
741 | const struct nfs42_getxattrargs *args = data; |
742 | struct compound_hdr hdr = { |
743 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
744 | }; |
745 | uint32_t replen; |
746 | |
747 | encode_compound_hdr(xdr, req, &hdr); |
748 | encode_sequence(xdr, &args->seq_args, &hdr); |
749 | encode_putfh(xdr, args->fh, &hdr); |
750 | replen = hdr.replen + op_decode_hdr_maxsz + 1; |
751 | encode_getxattr(xdr, name: args->xattr_name, hdr: &hdr); |
752 | |
753 | rpc_prepare_reply_pages(req, args->xattr_pages, 0, args->xattr_len, |
754 | replen); |
755 | |
756 | encode_nops(&hdr); |
757 | } |
758 | |
759 | /* |
760 | * Encode LISTXATTR request |
761 | */ |
762 | static void nfs4_xdr_enc_listxattrs(struct rpc_rqst *req, |
763 | struct xdr_stream *xdr, const void *data) |
764 | { |
765 | const struct nfs42_listxattrsargs *args = data; |
766 | struct compound_hdr hdr = { |
767 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
768 | }; |
769 | uint32_t replen; |
770 | |
771 | encode_compound_hdr(xdr, req, &hdr); |
772 | encode_sequence(xdr, &args->seq_args, &hdr); |
773 | encode_putfh(xdr, args->fh, &hdr); |
774 | replen = hdr.replen + op_decode_hdr_maxsz + 2 + 1; |
775 | encode_listxattrs(xdr, arg: args, hdr: &hdr); |
776 | |
777 | rpc_prepare_reply_pages(req, args->xattr_pages, 0, args->count, replen); |
778 | |
779 | encode_nops(&hdr); |
780 | } |
781 | |
782 | /* |
783 | * Encode REMOVEXATTR request |
784 | */ |
785 | static void nfs4_xdr_enc_removexattr(struct rpc_rqst *req, |
786 | struct xdr_stream *xdr, const void *data) |
787 | { |
788 | const struct nfs42_removexattrargs *args = data; |
789 | struct compound_hdr hdr = { |
790 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
791 | }; |
792 | |
793 | encode_compound_hdr(xdr, req, &hdr); |
794 | encode_sequence(xdr, &args->seq_args, &hdr); |
795 | encode_putfh(xdr, args->fh, &hdr); |
796 | encode_removexattr(xdr, name: args->xattr_name, hdr: &hdr); |
797 | encode_nops(&hdr); |
798 | } |
799 | |
800 | static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) |
801 | { |
802 | return decode_op_hdr(xdr, OP_ALLOCATE); |
803 | } |
804 | |
805 | static int decode_write_response(struct xdr_stream *xdr, |
806 | struct nfs42_write_res *res) |
807 | { |
808 | __be32 *p; |
809 | int status, count; |
810 | |
811 | p = xdr_inline_decode(xdr, 4); |
812 | if (unlikely(!p)) |
813 | return -EIO; |
814 | count = be32_to_cpup(p); |
815 | if (count > 1) |
816 | return -EREMOTEIO; |
817 | else if (count == 1) { |
818 | status = decode_opaque_fixed(xdr, &res->stateid, |
819 | NFS4_STATEID_SIZE); |
820 | if (unlikely(status)) |
821 | return -EIO; |
822 | } |
823 | p = xdr_inline_decode(xdr, 8 + 4); |
824 | if (unlikely(!p)) |
825 | return -EIO; |
826 | p = xdr_decode_hyper(p, &res->count); |
827 | res->verifier.committed = be32_to_cpup(p); |
828 | return decode_verifier(xdr, &res->verifier.verifier); |
829 | } |
830 | |
831 | static int decode_nl4_server(struct xdr_stream *xdr, struct nl4_server *ns) |
832 | { |
833 | struct nfs42_netaddr *naddr; |
834 | uint32_t dummy; |
835 | char *dummy_str; |
836 | __be32 *p; |
837 | int status; |
838 | |
839 | /* nl_type */ |
840 | p = xdr_inline_decode(xdr, 4); |
841 | if (unlikely(!p)) |
842 | return -EIO; |
843 | ns->nl4_type = be32_to_cpup(p); |
844 | switch (ns->nl4_type) { |
845 | case NL4_NAME: |
846 | case NL4_URL: |
847 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
848 | if (unlikely(status)) |
849 | return status; |
850 | if (unlikely(dummy > NFS4_OPAQUE_LIMIT)) |
851 | return -EIO; |
852 | memcpy(&ns->u.nl4_str, dummy_str, dummy); |
853 | ns->u.nl4_str_sz = dummy; |
854 | break; |
855 | case NL4_NETADDR: |
856 | naddr = &ns->u.nl4_addr; |
857 | |
858 | /* netid string */ |
859 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
860 | if (unlikely(status)) |
861 | return status; |
862 | if (unlikely(dummy > RPCBIND_MAXNETIDLEN)) |
863 | return -EIO; |
864 | naddr->netid_len = dummy; |
865 | memcpy(naddr->netid, dummy_str, naddr->netid_len); |
866 | |
867 | /* uaddr string */ |
868 | status = decode_opaque_inline(xdr, &dummy, &dummy_str); |
869 | if (unlikely(status)) |
870 | return status; |
871 | if (unlikely(dummy > RPCBIND_MAXUADDRLEN)) |
872 | return -EIO; |
873 | naddr->addr_len = dummy; |
874 | memcpy(naddr->addr, dummy_str, naddr->addr_len); |
875 | break; |
876 | default: |
877 | WARN_ON_ONCE(1); |
878 | return -EIO; |
879 | } |
880 | return 0; |
881 | } |
882 | |
883 | static int decode_copy_requirements(struct xdr_stream *xdr, |
884 | struct nfs42_copy_res *res) { |
885 | __be32 *p; |
886 | |
887 | p = xdr_inline_decode(xdr, 4 + 4); |
888 | if (unlikely(!p)) |
889 | return -EIO; |
890 | |
891 | res->consecutive = be32_to_cpup(p: p++); |
892 | res->synchronous = be32_to_cpup(p: p++); |
893 | return 0; |
894 | } |
895 | |
896 | static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res) |
897 | { |
898 | int status; |
899 | |
900 | status = decode_op_hdr(xdr, OP_COPY); |
901 | if (status == NFS4ERR_OFFLOAD_NO_REQS) { |
902 | status = decode_copy_requirements(xdr, res); |
903 | if (status) |
904 | return status; |
905 | return NFS4ERR_OFFLOAD_NO_REQS; |
906 | } else if (status) |
907 | return status; |
908 | |
909 | status = decode_write_response(xdr, res: &res->write_res); |
910 | if (status) |
911 | return status; |
912 | |
913 | return decode_copy_requirements(xdr, res); |
914 | } |
915 | |
916 | static int decode_offload_cancel(struct xdr_stream *xdr, |
917 | struct nfs42_offload_status_res *res) |
918 | { |
919 | return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL); |
920 | } |
921 | |
922 | static int decode_copy_notify(struct xdr_stream *xdr, |
923 | struct nfs42_copy_notify_res *res) |
924 | { |
925 | __be32 *p; |
926 | int status, count; |
927 | |
928 | status = decode_op_hdr(xdr, OP_COPY_NOTIFY); |
929 | if (status) |
930 | return status; |
931 | /* cnr_lease_time */ |
932 | p = xdr_inline_decode(xdr, 12); |
933 | if (unlikely(!p)) |
934 | return -EIO; |
935 | p = xdr_decode_hyper(p, &res->cnr_lease_time.seconds); |
936 | res->cnr_lease_time.nseconds = be32_to_cpup(p); |
937 | |
938 | status = decode_opaque_fixed(xdr, &res->cnr_stateid, NFS4_STATEID_SIZE); |
939 | if (unlikely(status)) |
940 | return -EIO; |
941 | |
942 | /* number of source addresses */ |
943 | p = xdr_inline_decode(xdr, 4); |
944 | if (unlikely(!p)) |
945 | return -EIO; |
946 | |
947 | count = be32_to_cpup(p); |
948 | if (count > 1) |
949 | pr_warn("NFS: %s: nsvr %d > Supported. Use first servers\n" , |
950 | __func__, count); |
951 | |
952 | status = decode_nl4_server(xdr, ns: &res->cnr_src); |
953 | if (unlikely(status)) |
954 | return -EIO; |
955 | return 0; |
956 | } |
957 | |
958 | static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) |
959 | { |
960 | return decode_op_hdr(xdr, OP_DEALLOCATE); |
961 | } |
962 | |
963 | struct read_plus_segment { |
964 | enum data_content4 type; |
965 | uint64_t offset; |
966 | union { |
967 | struct { |
968 | uint64_t length; |
969 | } hole; |
970 | |
971 | struct { |
972 | uint32_t length; |
973 | unsigned int from; |
974 | } data; |
975 | }; |
976 | }; |
977 | |
978 | static inline uint64_t read_plus_segment_length(struct read_plus_segment *seg) |
979 | { |
980 | return seg->type == NFS4_CONTENT_DATA ? seg->data.length : seg->hole.length; |
981 | } |
982 | |
983 | static int decode_read_plus_segment(struct xdr_stream *xdr, |
984 | struct read_plus_segment *seg) |
985 | { |
986 | __be32 *p; |
987 | |
988 | p = xdr_inline_decode(xdr, 4); |
989 | if (!p) |
990 | return -EIO; |
991 | seg->type = be32_to_cpup(p: p++); |
992 | |
993 | p = xdr_inline_decode(xdr, seg->type == NFS4_CONTENT_DATA ? 12 : 16); |
994 | if (!p) |
995 | return -EIO; |
996 | p = xdr_decode_hyper(p, &seg->offset); |
997 | |
998 | if (seg->type == NFS4_CONTENT_DATA) { |
999 | struct xdr_buf buf; |
1000 | uint32_t len = be32_to_cpup(p); |
1001 | |
1002 | seg->data.length = len; |
1003 | seg->data.from = xdr_stream_pos(xdr); |
1004 | |
1005 | if (!xdr_stream_subsegment(xdr, &buf, xdr_align_size(len))) |
1006 | return -EIO; |
1007 | } else if (seg->type == NFS4_CONTENT_HOLE) { |
1008 | xdr_decode_hyper(p, &seg->hole.length); |
1009 | } else |
1010 | return -EINVAL; |
1011 | return 0; |
1012 | } |
1013 | |
1014 | static int process_read_plus_segment(struct xdr_stream *xdr, |
1015 | struct nfs_pgio_args *args, |
1016 | struct nfs_pgio_res *res, |
1017 | struct read_plus_segment *seg) |
1018 | { |
1019 | unsigned long offset = seg->offset; |
1020 | unsigned long length = read_plus_segment_length(seg); |
1021 | unsigned int bufpos; |
1022 | |
1023 | if (offset + length < args->offset) |
1024 | return 0; |
1025 | else if (offset > args->offset + args->count) { |
1026 | res->eof = 0; |
1027 | return 0; |
1028 | } else if (offset < args->offset) { |
1029 | length -= (args->offset - offset); |
1030 | offset = args->offset; |
1031 | } else if (offset + length > args->offset + args->count) { |
1032 | length = (args->offset + args->count) - offset; |
1033 | res->eof = 0; |
1034 | } |
1035 | |
1036 | bufpos = xdr->buf->head[0].iov_len + (offset - args->offset); |
1037 | if (seg->type == NFS4_CONTENT_HOLE) |
1038 | return xdr_stream_zero(xdr, bufpos, length); |
1039 | else |
1040 | return xdr_stream_move_subsegment(xdr, seg->data.from, bufpos, length); |
1041 | } |
1042 | |
1043 | static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res) |
1044 | { |
1045 | struct *hdr = |
1046 | container_of(res, struct nfs_pgio_header, res); |
1047 | struct nfs_pgio_args *args = &hdr->args; |
1048 | uint32_t segments; |
1049 | struct read_plus_segment *segs; |
1050 | int status, i; |
1051 | __be32 *p; |
1052 | |
1053 | status = decode_op_hdr(xdr, OP_READ_PLUS); |
1054 | if (status) |
1055 | return status; |
1056 | |
1057 | p = xdr_inline_decode(xdr, 4 + 4); |
1058 | if (unlikely(!p)) |
1059 | return -EIO; |
1060 | |
1061 | res->count = 0; |
1062 | res->eof = be32_to_cpup(p: p++); |
1063 | segments = be32_to_cpup(p: p++); |
1064 | if (segments == 0) |
1065 | return 0; |
1066 | |
1067 | segs = kmalloc_array(n: segments, size: sizeof(*segs), GFP_KERNEL); |
1068 | if (!segs) |
1069 | return -ENOMEM; |
1070 | |
1071 | for (i = 0; i < segments; i++) { |
1072 | status = decode_read_plus_segment(xdr, seg: &segs[i]); |
1073 | if (status < 0) |
1074 | goto out; |
1075 | } |
1076 | |
1077 | xdr_set_pagelen(xdr, xdr_align_size(args->count)); |
1078 | for (i = segments; i > 0; i--) |
1079 | res->count += process_read_plus_segment(xdr, args, res, seg: &segs[i-1]); |
1080 | status = 0; |
1081 | |
1082 | out: |
1083 | kfree(objp: segs); |
1084 | return status; |
1085 | } |
1086 | |
1087 | static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res) |
1088 | { |
1089 | int status; |
1090 | __be32 *p; |
1091 | |
1092 | status = decode_op_hdr(xdr, OP_SEEK); |
1093 | if (status) |
1094 | return status; |
1095 | |
1096 | p = xdr_inline_decode(xdr, 4 + 8); |
1097 | if (unlikely(!p)) |
1098 | return -EIO; |
1099 | |
1100 | res->sr_eof = be32_to_cpup(p: p++); |
1101 | p = xdr_decode_hyper(p, &res->sr_offset); |
1102 | return 0; |
1103 | } |
1104 | |
1105 | static int decode_layoutstats(struct xdr_stream *xdr) |
1106 | { |
1107 | return decode_op_hdr(xdr, OP_LAYOUTSTATS); |
1108 | } |
1109 | |
1110 | static int decode_clone(struct xdr_stream *xdr) |
1111 | { |
1112 | return decode_op_hdr(xdr, OP_CLONE); |
1113 | } |
1114 | |
1115 | static int decode_layouterror(struct xdr_stream *xdr) |
1116 | { |
1117 | return decode_op_hdr(xdr, OP_LAYOUTERROR); |
1118 | } |
1119 | |
1120 | static int decode_setxattr(struct xdr_stream *xdr, |
1121 | struct nfs4_change_info *cinfo) |
1122 | { |
1123 | int status; |
1124 | |
1125 | status = decode_op_hdr(xdr, OP_SETXATTR); |
1126 | if (status) |
1127 | goto out; |
1128 | status = decode_change_info(xdr, cinfo); |
1129 | out: |
1130 | return status; |
1131 | } |
1132 | |
1133 | static int decode_getxattr(struct xdr_stream *xdr, |
1134 | struct nfs42_getxattrres *res, |
1135 | struct rpc_rqst *req) |
1136 | { |
1137 | int status; |
1138 | __be32 *p; |
1139 | u32 len, rdlen; |
1140 | |
1141 | status = decode_op_hdr(xdr, OP_GETXATTR); |
1142 | if (status) |
1143 | return status; |
1144 | |
1145 | p = xdr_inline_decode(xdr, 4); |
1146 | if (unlikely(!p)) |
1147 | return -EIO; |
1148 | |
1149 | len = be32_to_cpup(p); |
1150 | |
1151 | /* |
1152 | * Only check against the page length here. The actual |
1153 | * requested length may be smaller, but that is only |
1154 | * checked against after possibly caching a valid reply. |
1155 | */ |
1156 | if (len > req->rq_rcv_buf.page_len) |
1157 | return -ERANGE; |
1158 | |
1159 | res->xattr_len = len; |
1160 | |
1161 | if (len > 0) { |
1162 | rdlen = xdr_read_pages(xdr, len); |
1163 | if (rdlen < len) |
1164 | return -EIO; |
1165 | } |
1166 | |
1167 | return 0; |
1168 | } |
1169 | |
1170 | static int decode_removexattr(struct xdr_stream *xdr, |
1171 | struct nfs4_change_info *cinfo) |
1172 | { |
1173 | int status; |
1174 | |
1175 | status = decode_op_hdr(xdr, OP_REMOVEXATTR); |
1176 | if (status) |
1177 | goto out; |
1178 | |
1179 | status = decode_change_info(xdr, cinfo); |
1180 | out: |
1181 | return status; |
1182 | } |
1183 | |
1184 | static int decode_listxattrs(struct xdr_stream *xdr, |
1185 | struct nfs42_listxattrsres *res) |
1186 | { |
1187 | int status; |
1188 | __be32 *p; |
1189 | u32 count, len, ulen; |
1190 | size_t left, copied; |
1191 | char *buf; |
1192 | |
1193 | status = decode_op_hdr(xdr, OP_LISTXATTRS); |
1194 | if (status) { |
1195 | /* |
1196 | * Special case: for LISTXATTRS, NFS4ERR_TOOSMALL |
1197 | * should be translated to ERANGE. |
1198 | */ |
1199 | if (status == -ETOOSMALL) |
1200 | status = -ERANGE; |
1201 | /* |
1202 | * Special case: for LISTXATTRS, NFS4ERR_NOXATTR |
1203 | * should be translated to success with zero-length reply. |
1204 | */ |
1205 | if (status == -ENODATA) { |
1206 | res->eof = true; |
1207 | status = 0; |
1208 | } |
1209 | goto out; |
1210 | } |
1211 | |
1212 | p = xdr_inline_decode(xdr, 8); |
1213 | if (unlikely(!p)) |
1214 | return -EIO; |
1215 | |
1216 | xdr_decode_hyper(p, &res->cookie); |
1217 | |
1218 | p = xdr_inline_decode(xdr, 4); |
1219 | if (unlikely(!p)) |
1220 | return -EIO; |
1221 | |
1222 | left = res->xattr_len; |
1223 | buf = res->xattr_buf; |
1224 | |
1225 | count = be32_to_cpup(p); |
1226 | copied = 0; |
1227 | |
1228 | /* |
1229 | * We have asked for enough room to encode the maximum number |
1230 | * of possible attribute names, so everything should fit. |
1231 | * |
1232 | * But, don't rely on that assumption. Just decode entries |
1233 | * until they don't fit anymore, just in case the server did |
1234 | * something odd. |
1235 | */ |
1236 | while (count--) { |
1237 | p = xdr_inline_decode(xdr, 4); |
1238 | if (unlikely(!p)) |
1239 | return -EIO; |
1240 | |
1241 | len = be32_to_cpup(p); |
1242 | if (len > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) { |
1243 | status = -ERANGE; |
1244 | goto out; |
1245 | } |
1246 | |
1247 | p = xdr_inline_decode(xdr, len); |
1248 | if (unlikely(!p)) |
1249 | return -EIO; |
1250 | |
1251 | ulen = len + XATTR_USER_PREFIX_LEN + 1; |
1252 | if (buf) { |
1253 | if (ulen > left) { |
1254 | status = -ERANGE; |
1255 | goto out; |
1256 | } |
1257 | |
1258 | memcpy(buf, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); |
1259 | memcpy(buf + XATTR_USER_PREFIX_LEN, p, len); |
1260 | |
1261 | buf[ulen - 1] = 0; |
1262 | buf += ulen; |
1263 | left -= ulen; |
1264 | } |
1265 | copied += ulen; |
1266 | } |
1267 | |
1268 | p = xdr_inline_decode(xdr, 4); |
1269 | if (unlikely(!p)) |
1270 | return -EIO; |
1271 | |
1272 | res->eof = be32_to_cpup(p); |
1273 | res->copied = copied; |
1274 | |
1275 | out: |
1276 | if (status == -ERANGE && res->xattr_len == XATTR_LIST_MAX) |
1277 | status = -E2BIG; |
1278 | |
1279 | return status; |
1280 | } |
1281 | |
1282 | /* |
1283 | * Decode ALLOCATE request |
1284 | */ |
1285 | static int nfs4_xdr_dec_allocate(struct rpc_rqst *rqstp, |
1286 | struct xdr_stream *xdr, |
1287 | void *data) |
1288 | { |
1289 | struct nfs42_falloc_res *res = data; |
1290 | struct compound_hdr hdr; |
1291 | int status; |
1292 | |
1293 | status = decode_compound_hdr(xdr, &hdr); |
1294 | if (status) |
1295 | goto out; |
1296 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1297 | if (status) |
1298 | goto out; |
1299 | status = decode_putfh(xdr); |
1300 | if (status) |
1301 | goto out; |
1302 | status = decode_allocate(xdr, res); |
1303 | if (status) |
1304 | goto out; |
1305 | decode_getfattr(xdr, res->falloc_fattr, res->falloc_server); |
1306 | out: |
1307 | return status; |
1308 | } |
1309 | |
1310 | /* |
1311 | * Decode COPY response |
1312 | */ |
1313 | static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp, |
1314 | struct xdr_stream *xdr, |
1315 | void *data) |
1316 | { |
1317 | struct nfs42_copy_res *res = data; |
1318 | struct compound_hdr hdr; |
1319 | int status; |
1320 | |
1321 | status = decode_compound_hdr(xdr, &hdr); |
1322 | if (status) |
1323 | goto out; |
1324 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1325 | if (status) |
1326 | goto out; |
1327 | status = decode_putfh(xdr); |
1328 | if (status) |
1329 | goto out; |
1330 | status = decode_savefh(xdr); |
1331 | if (status) |
1332 | goto out; |
1333 | status = decode_putfh(xdr); |
1334 | if (status) |
1335 | goto out; |
1336 | status = decode_copy(xdr, res); |
1337 | if (status) |
1338 | goto out; |
1339 | if (res->commit_res.verf) |
1340 | status = decode_commit(xdr, &res->commit_res); |
1341 | out: |
1342 | return status; |
1343 | } |
1344 | |
1345 | /* |
1346 | * Decode OFFLOAD_CANCEL response |
1347 | */ |
1348 | static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp, |
1349 | struct xdr_stream *xdr, |
1350 | void *data) |
1351 | { |
1352 | struct nfs42_offload_status_res *res = data; |
1353 | struct compound_hdr hdr; |
1354 | int status; |
1355 | |
1356 | status = decode_compound_hdr(xdr, &hdr); |
1357 | if (status) |
1358 | goto out; |
1359 | status = decode_sequence(xdr, &res->osr_seq_res, rqstp); |
1360 | if (status) |
1361 | goto out; |
1362 | status = decode_putfh(xdr); |
1363 | if (status) |
1364 | goto out; |
1365 | status = decode_offload_cancel(xdr, res); |
1366 | |
1367 | out: |
1368 | return status; |
1369 | } |
1370 | |
1371 | /* |
1372 | * Decode COPY_NOTIFY response |
1373 | */ |
1374 | static int nfs4_xdr_dec_copy_notify(struct rpc_rqst *rqstp, |
1375 | struct xdr_stream *xdr, |
1376 | void *data) |
1377 | { |
1378 | struct nfs42_copy_notify_res *res = data; |
1379 | struct compound_hdr hdr; |
1380 | int status; |
1381 | |
1382 | status = decode_compound_hdr(xdr, &hdr); |
1383 | if (status) |
1384 | goto out; |
1385 | status = decode_sequence(xdr, &res->cnr_seq_res, rqstp); |
1386 | if (status) |
1387 | goto out; |
1388 | status = decode_putfh(xdr); |
1389 | if (status) |
1390 | goto out; |
1391 | status = decode_copy_notify(xdr, res); |
1392 | |
1393 | out: |
1394 | return status; |
1395 | } |
1396 | |
1397 | /* |
1398 | * Decode DEALLOCATE request |
1399 | */ |
1400 | static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp, |
1401 | struct xdr_stream *xdr, |
1402 | void *data) |
1403 | { |
1404 | struct nfs42_falloc_res *res = data; |
1405 | struct compound_hdr hdr; |
1406 | int status; |
1407 | |
1408 | status = decode_compound_hdr(xdr, &hdr); |
1409 | if (status) |
1410 | goto out; |
1411 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1412 | if (status) |
1413 | goto out; |
1414 | status = decode_putfh(xdr); |
1415 | if (status) |
1416 | goto out; |
1417 | status = decode_deallocate(xdr, res); |
1418 | if (status) |
1419 | goto out; |
1420 | decode_getfattr(xdr, res->falloc_fattr, res->falloc_server); |
1421 | out: |
1422 | return status; |
1423 | } |
1424 | |
1425 | /* |
1426 | * Decode READ_PLUS request |
1427 | */ |
1428 | static int nfs4_xdr_dec_read_plus(struct rpc_rqst *rqstp, |
1429 | struct xdr_stream *xdr, |
1430 | void *data) |
1431 | { |
1432 | struct nfs_pgio_res *res = data; |
1433 | struct compound_hdr hdr; |
1434 | int status; |
1435 | |
1436 | xdr_set_scratch_buffer(xdr, res->scratch, READ_PLUS_SCRATCH_SIZE); |
1437 | |
1438 | status = decode_compound_hdr(xdr, &hdr); |
1439 | if (status) |
1440 | goto out; |
1441 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1442 | if (status) |
1443 | goto out; |
1444 | status = decode_putfh(xdr); |
1445 | if (status) |
1446 | goto out; |
1447 | status = decode_read_plus(xdr, res); |
1448 | if (!status) |
1449 | status = res->count; |
1450 | out: |
1451 | return status; |
1452 | } |
1453 | |
1454 | /* |
1455 | * Decode SEEK request |
1456 | */ |
1457 | static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp, |
1458 | struct xdr_stream *xdr, |
1459 | void *data) |
1460 | { |
1461 | struct nfs42_seek_res *res = data; |
1462 | struct compound_hdr hdr; |
1463 | int status; |
1464 | |
1465 | status = decode_compound_hdr(xdr, &hdr); |
1466 | if (status) |
1467 | goto out; |
1468 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1469 | if (status) |
1470 | goto out; |
1471 | status = decode_putfh(xdr); |
1472 | if (status) |
1473 | goto out; |
1474 | status = decode_seek(xdr, res); |
1475 | out: |
1476 | return status; |
1477 | } |
1478 | |
1479 | /* |
1480 | * Decode LAYOUTSTATS request |
1481 | */ |
1482 | static int nfs4_xdr_dec_layoutstats(struct rpc_rqst *rqstp, |
1483 | struct xdr_stream *xdr, |
1484 | void *data) |
1485 | { |
1486 | struct nfs42_layoutstat_res *res = data; |
1487 | struct compound_hdr hdr; |
1488 | int status, i; |
1489 | |
1490 | status = decode_compound_hdr(xdr, &hdr); |
1491 | if (status) |
1492 | goto out; |
1493 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1494 | if (status) |
1495 | goto out; |
1496 | status = decode_putfh(xdr); |
1497 | if (status) |
1498 | goto out; |
1499 | WARN_ON(res->num_dev > PNFS_LAYOUTSTATS_MAXDEV); |
1500 | for (i = 0; i < res->num_dev; i++) { |
1501 | status = decode_layoutstats(xdr); |
1502 | if (status) |
1503 | goto out; |
1504 | } |
1505 | out: |
1506 | res->rpc_status = status; |
1507 | return status; |
1508 | } |
1509 | |
1510 | /* |
1511 | * Decode CLONE request |
1512 | */ |
1513 | static int nfs4_xdr_dec_clone(struct rpc_rqst *rqstp, |
1514 | struct xdr_stream *xdr, |
1515 | void *data) |
1516 | { |
1517 | struct nfs42_clone_res *res = data; |
1518 | struct compound_hdr hdr; |
1519 | int status; |
1520 | |
1521 | status = decode_compound_hdr(xdr, &hdr); |
1522 | if (status) |
1523 | goto out; |
1524 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1525 | if (status) |
1526 | goto out; |
1527 | status = decode_putfh(xdr); |
1528 | if (status) |
1529 | goto out; |
1530 | status = decode_savefh(xdr); |
1531 | if (status) |
1532 | goto out; |
1533 | status = decode_putfh(xdr); |
1534 | if (status) |
1535 | goto out; |
1536 | status = decode_clone(xdr); |
1537 | if (status) |
1538 | goto out; |
1539 | decode_getfattr(xdr, res->dst_fattr, res->server); |
1540 | out: |
1541 | res->rpc_status = status; |
1542 | return status; |
1543 | } |
1544 | |
1545 | /* |
1546 | * Decode LAYOUTERROR request |
1547 | */ |
1548 | static int nfs4_xdr_dec_layouterror(struct rpc_rqst *rqstp, |
1549 | struct xdr_stream *xdr, |
1550 | void *data) |
1551 | { |
1552 | struct nfs42_layouterror_res *res = data; |
1553 | struct compound_hdr hdr; |
1554 | int status, i; |
1555 | |
1556 | status = decode_compound_hdr(xdr, &hdr); |
1557 | if (status) |
1558 | goto out; |
1559 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1560 | if (status) |
1561 | goto out; |
1562 | status = decode_putfh(xdr); |
1563 | |
1564 | for (i = 0; i < res->num_errors && status == 0; i++) |
1565 | status = decode_layouterror(xdr); |
1566 | out: |
1567 | res->rpc_status = status; |
1568 | return status; |
1569 | } |
1570 | |
1571 | /* |
1572 | * Decode SETXATTR request |
1573 | */ |
1574 | static int nfs4_xdr_dec_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr, |
1575 | void *data) |
1576 | { |
1577 | struct nfs42_setxattrres *res = data; |
1578 | struct compound_hdr hdr; |
1579 | int status; |
1580 | |
1581 | status = decode_compound_hdr(xdr, &hdr); |
1582 | if (status) |
1583 | goto out; |
1584 | status = decode_sequence(xdr, &res->seq_res, req); |
1585 | if (status) |
1586 | goto out; |
1587 | status = decode_putfh(xdr); |
1588 | if (status) |
1589 | goto out; |
1590 | status = decode_setxattr(xdr, cinfo: &res->cinfo); |
1591 | if (status) |
1592 | goto out; |
1593 | status = decode_getfattr(xdr, res->fattr, res->server); |
1594 | out: |
1595 | return status; |
1596 | } |
1597 | |
1598 | /* |
1599 | * Decode GETXATTR request |
1600 | */ |
1601 | static int nfs4_xdr_dec_getxattr(struct rpc_rqst *rqstp, |
1602 | struct xdr_stream *xdr, void *data) |
1603 | { |
1604 | struct nfs42_getxattrres *res = data; |
1605 | struct compound_hdr hdr; |
1606 | int status; |
1607 | |
1608 | status = decode_compound_hdr(xdr, &hdr); |
1609 | if (status) |
1610 | goto out; |
1611 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1612 | if (status) |
1613 | goto out; |
1614 | status = decode_putfh(xdr); |
1615 | if (status) |
1616 | goto out; |
1617 | status = decode_getxattr(xdr, res, req: rqstp); |
1618 | out: |
1619 | return status; |
1620 | } |
1621 | |
1622 | /* |
1623 | * Decode LISTXATTR request |
1624 | */ |
1625 | static int nfs4_xdr_dec_listxattrs(struct rpc_rqst *rqstp, |
1626 | struct xdr_stream *xdr, void *data) |
1627 | { |
1628 | struct nfs42_listxattrsres *res = data; |
1629 | struct compound_hdr hdr; |
1630 | int status; |
1631 | |
1632 | xdr_set_scratch_page(xdr, res->scratch); |
1633 | |
1634 | status = decode_compound_hdr(xdr, &hdr); |
1635 | if (status) |
1636 | goto out; |
1637 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
1638 | if (status) |
1639 | goto out; |
1640 | status = decode_putfh(xdr); |
1641 | if (status) |
1642 | goto out; |
1643 | status = decode_listxattrs(xdr, res); |
1644 | out: |
1645 | return status; |
1646 | } |
1647 | |
1648 | /* |
1649 | * Decode REMOVEXATTR request |
1650 | */ |
1651 | static int nfs4_xdr_dec_removexattr(struct rpc_rqst *req, |
1652 | struct xdr_stream *xdr, void *data) |
1653 | { |
1654 | struct nfs42_removexattrres *res = data; |
1655 | struct compound_hdr hdr; |
1656 | int status; |
1657 | |
1658 | status = decode_compound_hdr(xdr, &hdr); |
1659 | if (status) |
1660 | goto out; |
1661 | status = decode_sequence(xdr, &res->seq_res, req); |
1662 | if (status) |
1663 | goto out; |
1664 | status = decode_putfh(xdr); |
1665 | if (status) |
1666 | goto out; |
1667 | |
1668 | status = decode_removexattr(xdr, cinfo: &res->cinfo); |
1669 | out: |
1670 | return status; |
1671 | } |
1672 | #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */ |
1673 | |