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 */ 604