1 /* NFSv4.1 client for Windows 2 * Copyright � 2012 The Regents of the University of Michigan 3 * 4 * Olga Kornievskaia <aglo@umich.edu> 5 * Casey Bodley <cbodley@umich.edu> 6 * 7 * This library is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as published by 9 * the Free Software Foundation; either version 2.1 of the License, or (at 10 * your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, but 13 * without any warranty; without even the implied warranty of merchantability 14 * or fitness for a particular purpose. See the GNU Lesser General Public 15 * License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 */ 21 22 #include <windows.h> 23 #include <strsafe.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <time.h> 27 28 #include "nfs41_ops.h" 29 #include "nfs41_compound.h" 30 #include "nfs41_xdr.h" 31 #include "name_cache.h" 32 #include "delegation.h" 33 #include "daemon_debug.h" 34 #include "util.h" 35 36 int nfs41_exchange_id( 37 IN nfs41_rpc_clnt *rpc, 38 IN client_owner4 *owner, 39 IN uint32_t flags_in, 40 OUT nfs41_exchange_id_res *res_out) 41 { 42 int status = 0; 43 nfs41_compound compound; 44 nfs_argop4 argop; 45 nfs_resop4 resop; 46 nfs41_exchange_id_args ex_id; 47 48 compound_init(&compound, &argop, &resop, "exchange_id"); 49 50 compound_add_op(&compound, OP_EXCHANGE_ID, &ex_id, res_out); 51 ex_id.eia_clientowner = owner; 52 ex_id.eia_flags = flags_in; 53 ex_id.eia_state_protect.spa_how = SP4_NONE; 54 ex_id.eia_client_impl_id = NULL; 55 56 res_out->server_owner.so_major_id_len = NFS4_OPAQUE_LIMIT; 57 res_out->server_scope_len = NFS4_OPAQUE_LIMIT; 58 59 status = nfs41_send_compound(rpc, (char *)&compound.args, 60 (char *)&compound.res); 61 if (status) 62 goto out; 63 64 compound_error(status = compound.res.status); 65 out: 66 return status; 67 } 68 69 // AGLO: 10/07/2009 we might want lookup these values from the registry 70 static int set_fore_channel_attrs( 71 IN nfs41_rpc_clnt *rpc, 72 IN uint32_t max_req, 73 OUT nfs41_channel_attrs *attrs) 74 { 75 attrs->ca_headerpadsize = 0; 76 attrs->ca_maxrequestsize = rpc->wsize; 77 attrs->ca_maxresponsesize = rpc->rsize; 78 attrs->ca_maxresponsesize_cached = NFS41_MAX_SERVER_CACHE; 79 attrs->ca_maxoperations = 0xffffffff; 80 attrs->ca_maxrequests = max_req; 81 attrs->ca_rdma_ird = NULL; 82 return 0; 83 } 84 85 // AGLO: 10/07/2009 we might want lookup these values from the registry 86 static int set_back_channel_attrs( 87 IN nfs41_rpc_clnt *rpc, 88 IN uint32_t max_req, 89 OUT nfs41_channel_attrs *attrs) 90 { 91 attrs->ca_headerpadsize = 0; 92 attrs->ca_maxrequestsize = rpc->wsize; 93 attrs->ca_maxresponsesize = rpc->rsize; 94 attrs->ca_maxresponsesize_cached = NFS41_MAX_SERVER_CACHE; 95 attrs->ca_maxoperations = 0xffffffff; 96 attrs->ca_maxrequests = max_req; 97 attrs->ca_rdma_ird = NULL; 98 return 0; 99 } 100 101 int nfs41_create_session(nfs41_client *clnt, nfs41_session *session, bool_t try_recovery) 102 { 103 int status = 0; 104 nfs41_compound compound; 105 nfs_argop4 argop; 106 nfs_resop4 resop; 107 nfs41_create_session_args req = { 0 }; 108 nfs41_create_session_res reply = { 0 }; 109 110 compound_init(&compound, &argop, &resop, "create_session"); 111 112 compound_add_op(&compound, OP_CREATE_SESSION, &req, &reply); 113 114 AcquireSRWLockShared(&clnt->exid_lock); 115 req.csa_clientid = clnt->clnt_id; 116 req.csa_sequence = clnt->seq_id; 117 ReleaseSRWLockShared(&clnt->exid_lock); 118 req.csa_flags = session->flags; 119 req.csa_cb_program = NFS41_RPC_CBPROGRAM; 120 req.csa_cb_secparams[0].type = 0; /* AUTH_NONE */ 121 req.csa_cb_secparams[1].type = 1; /* AUTH_SYS */ 122 req.csa_cb_secparams[1].u.auth_sys.machinename = clnt->rpc->server_name; 123 req.csa_cb_secparams[1].u.auth_sys.stamp = (uint32_t)time(NULL); 124 125 // ca_maxrequests should be gotten from the rpc layer 126 set_fore_channel_attrs(clnt->rpc, 127 NFS41_MAX_RPC_REQS, &req.csa_fore_chan_attrs); 128 set_back_channel_attrs(clnt->rpc, 129 1, &req.csa_back_chan_attrs); 130 131 reply.csr_sessionid = session->session_id; 132 reply.csr_fore_chan_attrs = &session->fore_chan_attrs; 133 reply.csr_back_chan_attrs = &session->back_chan_attrs; 134 135 status = compound_encode_send_decode(session, &compound, try_recovery); 136 if (status) 137 goto out; 138 139 if (compound_error(status = compound.res.status)) 140 goto out; 141 142 print_hexbuf(1, (unsigned char *)"session id: ", session->session_id, NFS4_SESSIONID_SIZE); 143 // check that csa_sequence is same as csr_sequence 144 if (reply.csr_sequence != clnt->seq_id) { 145 eprintf("ERROR: CREATE_SESSION: csa_sequence %d != " 146 "csr_sequence %d\n", clnt->seq_id, reply.csr_sequence); 147 status = NFS4ERR_SEQ_MISORDERED; 148 goto out; 149 } else clnt->seq_id++; 150 151 if (reply.csr_flags != req.csa_flags) { 152 eprintf("WARNING: requested session flags %x received %x\n", 153 req.csa_flags, reply.csr_flags); 154 if ((session->flags & CREATE_SESSION4_FLAG_CONN_BACK_CHAN) && 155 !(reply.csr_flags & CREATE_SESSION4_FLAG_CONN_BACK_CHAN)) 156 eprintf("WARNING: we asked to use this session for callbacks but " 157 "server refused\n"); 158 if ((session->flags & CREATE_SESSION4_FLAG_PERSIST) && 159 !(reply.csr_flags & CREATE_SESSION4_FLAG_PERSIST)) 160 eprintf("WARNING: we asked for persistent session but " 161 "server refused\n"); 162 session->flags = reply.csr_flags; 163 } 164 else 165 dprintf(1, "session flags %x\n", reply.csr_flags); 166 167 dprintf(1, "session fore_chan_attrs:\n" 168 " %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n", 169 "headerpadsize", session->fore_chan_attrs.ca_headerpadsize, 170 "maxrequestsize", session->fore_chan_attrs.ca_maxrequestsize, 171 "maxresponsesize", session->fore_chan_attrs.ca_maxresponsesize, 172 "maxresponsesize_cached", session->fore_chan_attrs.ca_maxresponsesize_cached, 173 "maxoperations", session->fore_chan_attrs.ca_maxoperations, 174 "maxrequests", session->fore_chan_attrs.ca_maxrequests); 175 dprintf(1, "client supports %d max rpc slots, but server has %d\n", 176 session->table.max_slots, session->fore_chan_attrs.ca_maxrequests); 177 /* use the server's ca_maxrequests unless it's bigger than our array */ 178 session->table.max_slots = min(session->table.max_slots, 179 session->fore_chan_attrs.ca_maxrequests); 180 status = 0; 181 out: 182 return status; 183 } 184 185 enum nfsstat4 nfs41_bind_conn_to_session( 186 IN nfs41_rpc_clnt *rpc, 187 IN const unsigned char *sessionid, 188 IN enum channel_dir_from_client4 dir) 189 { 190 int status; 191 nfs41_compound compound; 192 nfs_argop4 argop; 193 nfs_resop4 resop; 194 nfs41_bind_conn_to_session_args bind_args = { 0 }; 195 nfs41_bind_conn_to_session_res bind_res = { 0 }; 196 197 compound_init(&compound, &argop, &resop, "bind_conn_to_session"); 198 199 compound_add_op(&compound, OP_BIND_CONN_TO_SESSION, &bind_args, &bind_res); 200 bind_args.sessionid = (unsigned char *)sessionid; 201 bind_args.dir = dir; 202 203 status = nfs41_send_compound(rpc, 204 (char*)&compound.args, (char*)&compound.res); 205 if (status) 206 goto out; 207 208 compound_error(status = compound.res.status); 209 210 out: 211 return status; 212 } 213 214 int nfs41_destroy_session( 215 IN nfs41_session *session) 216 { 217 int status; 218 nfs41_compound compound; 219 nfs_argop4 argop; 220 nfs_resop4 resop; 221 nfs41_destroy_session_args ds_args; 222 nfs41_destroy_session_res ds_res; 223 224 compound_init(&compound, &argop, &resop, "destroy_session"); 225 226 compound_add_op(&compound, OP_DESTROY_SESSION, &ds_args, &ds_res); 227 ds_args.dsa_sessionid = session->session_id; 228 229 /* don't attempt to recover from BADSESSION/STALE_CLIENTID */ 230 status = compound_encode_send_decode(session, &compound, FALSE); 231 if (status) 232 goto out; 233 234 status = compound.res.status; 235 if (status) 236 eprintf("%s failed with status %d.\n", 237 nfs_opnum_to_string(OP_DESTROY_SESSION), status); 238 out: 239 return status; 240 } 241 242 int nfs41_destroy_clientid( 243 IN nfs41_rpc_clnt *rpc, 244 IN uint64_t clientid) 245 { 246 int status; 247 nfs41_compound compound; 248 nfs_argop4 argops; 249 nfs_resop4 resops; 250 nfs41_destroy_clientid_args dc_args; 251 nfs41_destroy_clientid_res dc_res; 252 253 compound_init(&compound, &argops, &resops, "destroy_clientid"); 254 255 compound_add_op(&compound, OP_DESTROY_CLIENTID, &dc_args, &dc_res); 256 dc_args.dca_clientid = clientid; 257 258 status = nfs41_send_compound(rpc, (char *)&compound.args, 259 (char *)&compound.res); 260 if (status) 261 goto out; 262 263 compound_error(status = compound.res.status); 264 out: 265 return status; 266 } 267 268 enum nfsstat4 nfs41_reclaim_complete( 269 IN nfs41_session *session) 270 { 271 enum nfsstat4 status = NFS4_OK; 272 nfs41_compound compound; 273 nfs_argop4 argops[2]; 274 nfs_resop4 resops[2]; 275 nfs41_sequence_args sequence_args; 276 nfs41_sequence_res sequence_res; 277 nfs41_reclaim_complete_res reclaim_res; 278 279 compound_init(&compound, argops, resops, "reclaim_complete"); 280 281 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 282 nfs41_session_sequence(&sequence_args, session, 0); 283 284 compound_add_op(&compound, OP_RECLAIM_COMPLETE, NULL, &reclaim_res); 285 286 /* don't attempt to recover from BADSESSION */ 287 status = compound_encode_send_decode(session, &compound, FALSE); 288 if (status) 289 goto out; 290 291 compound_error(status = compound.res.status); 292 out: 293 return status; 294 } 295 296 static void open_delegation_return( 297 IN nfs41_session *session, 298 IN nfs41_path_fh *file, 299 IN open_delegation4 *delegation, 300 IN bool_t try_recovery) 301 { 302 stateid_arg stateid; 303 int status; 304 305 if (delegation->type == OPEN_DELEGATE_NONE || 306 delegation->type == OPEN_DELEGATE_NONE_EXT) 307 return; 308 309 /* return the delegation */ 310 stateid.open = NULL; 311 stateid.delegation = NULL; 312 stateid.type = STATEID_DELEG_FILE; 313 memcpy(&stateid.stateid, &delegation->stateid, sizeof(stateid4)); 314 315 status = nfs41_delegreturn(session, file, &stateid, try_recovery); 316 317 /* clear the delegation type returned by nfs41_open() */ 318 delegation->type = OPEN_DELEGATE_NONE; 319 } 320 321 static void open_update_cache( 322 IN nfs41_session *session, 323 IN nfs41_path_fh *parent, 324 IN nfs41_path_fh *file, 325 IN bool_t try_recovery, 326 IN open_delegation4 *delegation, 327 IN bool_t already_delegated, 328 IN change_info4 *changeinfo, 329 IN nfs41_getattr_res *dir_attrs, 330 IN nfs41_getattr_res *file_attrs) 331 { 332 struct nfs41_name_cache *cache = session_name_cache(session); 333 uint32_t status; 334 335 /* update the attributes of the parent directory */ 336 memcpy(&dir_attrs->info->attrmask, &dir_attrs->obj_attributes.attrmask, 337 sizeof(bitmap4)); 338 nfs41_attr_cache_update(cache, parent->fh.fileid, dir_attrs->info); 339 340 /* add the file handle and attributes to the name cache */ 341 memcpy(&file_attrs->info->attrmask, &file_attrs->obj_attributes.attrmask, 342 sizeof(bitmap4)); 343 retry_cache_insert: 344 AcquireSRWLockShared(&file->path->lock); 345 status = nfs41_name_cache_insert(cache, file->path->path, &file->name, 346 &file->fh, file_attrs->info, changeinfo, 347 already_delegated ? OPEN_DELEGATE_NONE : delegation->type); 348 ReleaseSRWLockShared(&file->path->lock); 349 350 if (status == ERROR_TOO_MANY_OPEN_FILES) { 351 /* the cache won't accept any more delegations; ask the client to 352 * return a delegation to free up a slot in the attribute cache */ 353 status = nfs41_client_delegation_return_lru(session->client); 354 if (status == NFS4_OK) 355 goto retry_cache_insert; 356 } 357 358 if (status && delegation->type != OPEN_DELEGATE_NONE) { 359 /* if we can't make room in the cache, return this 360 * delegation immediately to free resources on the server */ 361 open_delegation_return(session, file, delegation, try_recovery); 362 goto retry_cache_insert; 363 } 364 } 365 366 int nfs41_open( 367 IN nfs41_session *session, 368 IN nfs41_path_fh *parent, 369 IN nfs41_path_fh *file, 370 IN state_owner4 *owner, 371 IN open_claim4 *claim, 372 IN uint32_t allow, 373 IN uint32_t deny, 374 IN uint32_t create, 375 IN uint32_t how_mode, 376 IN OPTIONAL nfs41_file_info *createattrs, 377 IN bool_t try_recovery, 378 OUT stateid4 *stateid, 379 OUT open_delegation4 *delegation, 380 OUT OPTIONAL nfs41_file_info *info) 381 { 382 int status; 383 nfs41_compound compound; 384 nfs_argop4 argops[8]; 385 nfs_resop4 resops[8]; 386 nfs41_sequence_args sequence_args; 387 nfs41_sequence_res sequence_res; 388 nfs41_putfh_args putfh_args[2]; 389 nfs41_putfh_res putfh_res[2]; 390 nfs41_op_open_args open_args; 391 nfs41_op_open_res open_res; 392 nfs41_getfh_res getfh_res; 393 bitmap4 attr_request; 394 nfs41_getattr_args getattr_args; 395 nfs41_getattr_res getattr_res, pgetattr_res; 396 nfs41_savefh_res savefh_res; 397 nfs41_restorefh_res restorefh_res; 398 nfs41_file_info tmp_info, dir_info; 399 bool_t current_fh_is_dir; 400 bool_t already_delegated = delegation->type == OPEN_DELEGATE_READ 401 || delegation->type == OPEN_DELEGATE_WRITE; 402 403 /* depending on the claim type, OPEN expects CURRENT_FH set 404 * to either the parent directory, or to the file itself */ 405 switch (claim->claim) { 406 case CLAIM_NULL: 407 case CLAIM_DELEGATE_CUR: 408 case CLAIM_DELEGATE_PREV: 409 /* CURRENT_FH: directory */ 410 current_fh_is_dir = TRUE; 411 /* SEQUENCE; PUTFH(dir); SAVEFH; OPEN; 412 * GETFH(file); GETATTR(file); RESTOREFH(dir); GETATTR */ 413 nfs41_superblock_getattr_mask(parent->fh.superblock, &attr_request); 414 break; 415 case CLAIM_PREVIOUS: 416 case CLAIM_FH: 417 case CLAIM_DELEG_CUR_FH: 418 case CLAIM_DELEG_PREV_FH: 419 default: 420 /* CURRENT_FH: file being opened */ 421 current_fh_is_dir = FALSE; 422 /* SEQUENCE; PUTFH(file); OPEN; GETATTR(file); PUTFH(dir); GETATTR */ 423 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request); 424 break; 425 } 426 427 if (info == NULL) 428 info = &tmp_info; 429 430 attr_request.arr[0] |= FATTR4_WORD0_FSID; 431 432 compound_init(&compound, argops, resops, "open"); 433 434 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 435 nfs41_session_sequence(&sequence_args, session, 1); 436 437 if (current_fh_is_dir) { 438 /* CURRENT_FH: directory */ 439 compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]); 440 putfh_args[0].file = parent; 441 putfh_args[0].in_recovery = 0; 442 443 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); 444 } else { 445 /* CURRENT_FH: file being opened */ 446 compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]); 447 putfh_args[0].file = file; 448 putfh_args[0].in_recovery = 0; 449 } 450 451 compound_add_op(&compound, OP_OPEN, &open_args, &open_res); 452 open_args.seqid = 0; 453 #ifdef DISABLE_FILE_DELEGATIONS 454 open_args.share_access = allow | OPEN4_SHARE_ACCESS_WANT_NO_DELEG; 455 #else 456 open_args.share_access = allow; 457 #endif 458 open_args.share_deny = deny; 459 open_args.owner = owner; 460 open_args.openhow.opentype = create; 461 open_args.openhow.how.mode = how_mode; 462 open_args.openhow.how.createattrs = createattrs; 463 if (how_mode == EXCLUSIVE4_1) { 464 DWORD tid = GetCurrentThreadId(); 465 time((time_t*)open_args.openhow.how.createverf); 466 memcpy(open_args.openhow.how.createverf+4, &tid, sizeof(tid)); 467 /* mask unsupported attributes */ 468 nfs41_superblock_supported_attrs_exclcreat( 469 parent->fh.superblock, &createattrs->attrmask); 470 } else if (createattrs) { 471 /* mask unsupported attributes */ 472 nfs41_superblock_supported_attrs( 473 parent->fh.superblock, &createattrs->attrmask); 474 } 475 open_args.claim = claim; 476 open_res.resok4.stateid = stateid; 477 open_res.resok4.delegation = delegation; 478 479 if (current_fh_is_dir) { 480 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); 481 getfh_res.fh = &file->fh; 482 } 483 484 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 485 getattr_args.attr_request = &attr_request; 486 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 487 getattr_res.info = info; 488 489 if (current_fh_is_dir) { 490 compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); 491 } else { 492 compound_add_op(&compound, OP_PUTFH, &putfh_args[1], &putfh_res[1]); 493 putfh_args[1].file = parent; 494 putfh_args[1].in_recovery = 0; 495 } 496 497 compound_add_op(&compound, OP_GETATTR, &getattr_args, &pgetattr_res); 498 getattr_args.attr_request = &attr_request; 499 pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 500 pgetattr_res.info = &dir_info; 501 502 status = compound_encode_send_decode(session, &compound, try_recovery); 503 if (status) 504 goto out; 505 506 if (compound_error(status = compound.res.status)) 507 goto out; 508 509 if (dir_info.type == NF4ATTRDIR) { 510 file->fh.superblock = parent->fh.superblock; 511 goto out; 512 } 513 514 /* fill in the file handle's fileid and superblock */ 515 file->fh.fileid = info->fileid; 516 status = nfs41_superblock_for_fh(session, &info->fsid, &parent->fh, file); 517 if (status) 518 goto out; 519 520 if (create == OPEN4_CREATE) 521 nfs41_superblock_space_changed(file->fh.superblock); 522 523 /* update the name/attr cache with the results */ 524 open_update_cache(session, parent, file, try_recovery, delegation, 525 already_delegated, &open_res.resok4.cinfo, &pgetattr_res, &getattr_res); 526 out: 527 return status; 528 } 529 530 int nfs41_create( 531 IN nfs41_session *session, 532 IN uint32_t type, 533 IN nfs41_file_info *createattrs, 534 IN OPTIONAL const char *symlink, 535 IN nfs41_path_fh *parent, 536 OUT nfs41_path_fh *file, 537 OUT nfs41_file_info *info) 538 { 539 int status; 540 nfs41_compound compound; 541 nfs_argop4 argops[8]; 542 nfs_resop4 resops[8]; 543 nfs41_sequence_args sequence_args; 544 nfs41_sequence_res sequence_res; 545 nfs41_putfh_args putfh_args; 546 nfs41_putfh_res putfh_res; 547 nfs41_create_args create_args; 548 nfs41_create_res create_res; 549 nfs41_getfh_res getfh_res; 550 nfs41_getattr_args getattr_args; 551 nfs41_getattr_res getattr_res, pgetattr_res; 552 bitmap4 attr_request; 553 nfs41_file_info dir_info; 554 nfs41_savefh_res savefh_res; 555 nfs41_restorefh_res restorefh_res; 556 557 nfs41_superblock_getattr_mask(parent->fh.superblock, &attr_request); 558 559 compound_init(&compound, argops, resops, "create"); 560 561 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 562 nfs41_session_sequence(&sequence_args, session, 1); 563 564 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 565 putfh_args.file = parent; 566 putfh_args.in_recovery = 0; 567 568 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); 569 570 compound_add_op(&compound, OP_CREATE, &create_args, &create_res); 571 create_args.objtype.type = type; 572 if (type == NF4LNK) { 573 create_args.objtype.u.lnk.linkdata = symlink; 574 create_args.objtype.u.lnk.linkdata_len = (uint32_t)strlen(symlink); 575 } 576 create_args.name = &file->name; 577 create_args.createattrs = createattrs; 578 nfs41_superblock_supported_attrs( 579 parent->fh.superblock, &createattrs->attrmask); 580 581 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); 582 getfh_res.fh = &file->fh; 583 584 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 585 getattr_args.attr_request = &attr_request; 586 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 587 getattr_res.info = info; 588 589 compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); 590 591 compound_add_op(&compound, OP_GETATTR, &getattr_args, &pgetattr_res); 592 getattr_args.attr_request = &attr_request; 593 pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 594 pgetattr_res.info = &dir_info; 595 596 status = compound_encode_send_decode(session, &compound, TRUE); 597 if (status) 598 goto out; 599 600 if (compound_error(status = compound.res.status)) 601 goto out; 602 603 /* fill in the file handle's fileid and superblock */ 604 file->fh.fileid = info->fileid; 605 file->fh.superblock = parent->fh.superblock; 606 607 /* update the attributes of the parent directory */ 608 memcpy(&dir_info.attrmask, &pgetattr_res.obj_attributes.attrmask, 609 sizeof(bitmap4)); 610 nfs41_attr_cache_update(session_name_cache(session), 611 parent->fh.fileid, &dir_info); 612 613 /* add the new file handle and attributes to the name cache */ 614 memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask, 615 sizeof(bitmap4)); 616 AcquireSRWLockShared(&file->path->lock); 617 nfs41_name_cache_insert(session_name_cache(session), 618 file->path->path, &file->name, &file->fh, 619 info, &create_res.cinfo, OPEN_DELEGATE_NONE); 620 ReleaseSRWLockShared(&file->path->lock); 621 622 nfs41_superblock_space_changed(file->fh.superblock); 623 out: 624 return status; 625 } 626 627 int nfs41_close( 628 IN nfs41_session *session, 629 IN nfs41_path_fh *file, 630 IN stateid_arg *stateid) 631 { 632 int status; 633 nfs41_compound compound; 634 nfs_argop4 argops[4]; 635 nfs_resop4 resops[4]; 636 nfs41_sequence_args sequence_args; 637 nfs41_sequence_res sequence_res; 638 nfs41_putfh_args putfh_args; 639 nfs41_putfh_res putfh_res; 640 nfs41_op_close_args close_args; 641 nfs41_op_close_res close_res; 642 nfs41_getattr_args getattr_args; 643 nfs41_getattr_res getattr_res; 644 bitmap4 attr_request; 645 nfs41_file_info info; 646 647 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request); 648 649 compound_init(&compound, argops, resops, "close"); 650 651 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 652 nfs41_session_sequence(&sequence_args, session, 1); 653 654 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 655 putfh_args.file = file; 656 putfh_args.in_recovery = 0; 657 658 compound_add_op(&compound, OP_CLOSE, &close_args, &close_res); 659 close_args.stateid = stateid; 660 661 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 662 getattr_args.attr_request = &attr_request; 663 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 664 getattr_res.info = &info; 665 666 status = compound_encode_send_decode(session, &compound, TRUE); 667 if (status) 668 goto out; 669 670 if (compound_error(status = compound.res.status)) 671 goto out; 672 673 if (info.type == NF4NAMEDATTR) 674 goto out; 675 676 /* update the attributes of the parent directory */ 677 memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, 678 sizeof(bitmap4)); 679 nfs41_attr_cache_update(session_name_cache(session), 680 file->fh.fileid, &info); 681 out: 682 return status; 683 } 684 685 int nfs41_write( 686 IN nfs41_session *session, 687 IN nfs41_path_fh *file, 688 IN stateid_arg *stateid, 689 IN unsigned char *data, 690 IN uint32_t data_len, 691 IN uint64_t offset, 692 IN enum stable_how4 stable, 693 OUT uint32_t *bytes_written, 694 OUT nfs41_write_verf *verf, 695 OUT nfs41_file_info *cinfo) 696 { 697 int status; 698 nfs41_compound compound; 699 nfs_argop4 argops[4]; 700 nfs_resop4 resops[4]; 701 nfs41_sequence_args sequence_args; 702 nfs41_sequence_res sequence_res; 703 nfs41_putfh_args putfh_args; 704 nfs41_putfh_res putfh_res; 705 nfs41_write_args write_args; 706 nfs41_write_res write_res; 707 nfs41_getattr_args getattr_args; 708 nfs41_getattr_res getattr_res = {0}; 709 bitmap4 attr_request; 710 nfs41_file_info info = { 0 }, *pinfo; 711 712 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request); 713 714 compound_init(&compound, argops, resops, 715 stateid->stateid.seqid == 0 ? "ds write" : "write"); 716 717 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 718 nfs41_session_sequence(&sequence_args, session, 0); 719 720 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 721 putfh_args.file = file; 722 putfh_args.in_recovery = 0; 723 724 compound_add_op(&compound, OP_WRITE, &write_args, &write_res); 725 write_args.stateid = stateid; 726 write_args.offset = offset; 727 write_args.stable = stable; 728 write_args.data_len = data_len; 729 write_args.data = data; 730 write_res.resok4.verf = verf; 731 732 if (cinfo) pinfo = cinfo; 733 else pinfo = &info; 734 735 if (stable != UNSTABLE4) { 736 /* if the write is stable, we can't rely on COMMIT to update 737 * the attribute cache, so we do the GETATTR here */ 738 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 739 getattr_args.attr_request = &attr_request; 740 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 741 getattr_res.info = pinfo; 742 } 743 744 status = compound_encode_send_decode(session, &compound, TRUE); 745 if (status) 746 goto out; 747 748 if (compound_error(status = compound.res.status)) 749 goto out; 750 751 if (stable != UNSTABLE4 && pinfo->type != NF4NAMEDATTR) { 752 /* update the attribute cache */ 753 memcpy(&pinfo->attrmask, &getattr_res.obj_attributes.attrmask, 754 sizeof(bitmap4)); 755 nfs41_attr_cache_update(session_name_cache(session), 756 file->fh.fileid, pinfo); 757 } 758 759 *bytes_written = write_res.resok4.count; 760 761 /* we shouldn't ever see this, but a buggy server could 762 * send us into an infinite loop. return NFS4ERR_IO */ 763 if (!write_res.resok4.count) { 764 status = NFS4ERR_IO; 765 eprintf("WRITE succeeded with count=0; returning %s\n", 766 nfs_error_string(status)); 767 } 768 769 nfs41_superblock_space_changed(file->fh.superblock); 770 out: 771 return status; 772 } 773 774 int nfs41_read( 775 IN nfs41_session *session, 776 IN nfs41_path_fh *file, 777 IN stateid_arg *stateid, 778 IN uint64_t offset, 779 IN uint32_t count, 780 OUT unsigned char *data_out, 781 OUT uint32_t *data_len_out, 782 OUT bool_t *eof_out) 783 { 784 int status; 785 nfs41_compound compound; 786 nfs_argop4 argops[4]; 787 nfs_resop4 resops[4]; 788 nfs41_sequence_args sequence_args; 789 nfs41_sequence_res sequence_res; 790 nfs41_putfh_args putfh_args; 791 nfs41_putfh_res putfh_res; 792 nfs41_read_args read_args; 793 nfs41_read_res read_res; 794 795 compound_init(&compound, argops, resops, 796 stateid->stateid.seqid == 0 ? "ds read" : "read"); 797 798 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 799 nfs41_session_sequence(&sequence_args, session, 0); 800 801 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 802 putfh_args.file = file; 803 putfh_args.in_recovery = 0; 804 805 compound_add_op(&compound, OP_READ, &read_args, &read_res); 806 read_args.stateid = stateid; 807 read_args.offset = offset; 808 read_args.count = count; 809 read_res.resok4.data_len = count; 810 read_res.resok4.data = data_out; 811 812 status = compound_encode_send_decode(session, &compound, TRUE); 813 if (status) 814 goto out; 815 816 if (compound_error(status = compound.res.status)) 817 goto out; 818 819 *data_len_out = read_res.resok4.data_len; 820 *eof_out = read_res.resok4.eof; 821 822 /* we shouldn't ever see this, but a buggy server could 823 * send us into an infinite loop. return NFS4ERR_IO */ 824 if (!read_res.resok4.data_len && !read_res.resok4.eof) { 825 status = NFS4ERR_IO; 826 eprintf("READ succeeded with len=0 and eof=0; returning %s\n", 827 nfs_error_string(status)); 828 } 829 out: 830 return status; 831 } 832 833 int nfs41_commit( 834 IN nfs41_session *session, 835 IN nfs41_path_fh *file, 836 IN uint64_t offset, 837 IN uint32_t count, 838 IN bool_t do_getattr, 839 OUT nfs41_write_verf *verf, 840 OUT nfs41_file_info *cinfo) 841 { 842 int status; 843 nfs41_compound compound; 844 nfs_argop4 argops[4]; 845 nfs_resop4 resops[4]; 846 nfs41_sequence_args sequence_args; 847 nfs41_sequence_res sequence_res; 848 nfs41_putfh_args putfh_args; 849 nfs41_putfh_res putfh_res; 850 nfs41_commit_args commit_args; 851 nfs41_commit_res commit_res; 852 nfs41_getattr_args getattr_args; 853 nfs41_getattr_res getattr_res = {0}; 854 bitmap4 attr_request; 855 nfs41_file_info info, *pinfo; 856 857 compound_init(&compound, argops, resops, 858 do_getattr ? "commit" : "ds commit"); 859 860 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 861 nfs41_session_sequence(&sequence_args, session, 1); 862 863 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 864 putfh_args.file = file; 865 putfh_args.in_recovery = 0; 866 867 compound_add_op(&compound, OP_COMMIT, &commit_args, &commit_res); 868 commit_args.offset = offset; 869 commit_args.count = count; 870 commit_res.verf = verf; 871 872 /* send a GETATTR request to update the attribute cache, 873 * but not if we're talking to a data server! */ 874 if (cinfo) pinfo = cinfo; 875 else pinfo = &info; 876 if (do_getattr) { 877 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request); 878 879 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 880 getattr_args.attr_request = &attr_request; 881 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 882 getattr_res.info = pinfo; 883 } 884 885 status = compound_encode_send_decode(session, &compound, TRUE); 886 if (status) 887 goto out; 888 889 if (compound_error(status = compound.res.status)) 890 goto out; 891 892 if (do_getattr) { 893 /* update the attribute cache */ 894 memcpy(&pinfo->attrmask, &getattr_res.obj_attributes.attrmask, 895 sizeof(bitmap4)); 896 nfs41_attr_cache_update(session_name_cache(session), 897 file->fh.fileid, pinfo); 898 } 899 nfs41_superblock_space_changed(file->fh.superblock); 900 out: 901 return status; 902 } 903 904 int nfs41_lock( 905 IN nfs41_session *session, 906 IN nfs41_path_fh *file, 907 IN state_owner4 *owner, 908 IN uint32_t type, 909 IN uint64_t offset, 910 IN uint64_t length, 911 IN bool_t reclaim, 912 IN bool_t try_recovery, 913 IN OUT stateid_arg *stateid) 914 { 915 int status; 916 nfs41_compound compound; 917 nfs_argop4 argops[3]; 918 nfs_resop4 resops[3]; 919 nfs41_sequence_args sequence_args; 920 nfs41_sequence_res sequence_res; 921 nfs41_putfh_args putfh_args; 922 nfs41_putfh_res putfh_res; 923 nfs41_lock_args lock_args; 924 nfs41_lock_res lock_res; 925 926 compound_init(&compound, argops, resops, "lock"); 927 928 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 929 nfs41_session_sequence(&sequence_args, session, 0); 930 931 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 932 putfh_args.file = file; 933 putfh_args.in_recovery = 0; 934 935 compound_add_op(&compound, OP_LOCK, &lock_args, &lock_res); 936 lock_args.locktype = type; 937 lock_args.reclaim = reclaim; 938 lock_args.offset = offset; 939 lock_args.length = length; 940 if (stateid->type == STATEID_LOCK) { 941 lock_args.locker.new_lock_owner = 0; 942 lock_args.locker.u.lock_owner.lock_stateid = stateid; 943 lock_args.locker.u.lock_owner.lock_seqid = 0; /* ignored */ 944 } else { 945 lock_args.locker.new_lock_owner = 1; 946 lock_args.locker.u.open_owner.open_seqid = 0; /* ignored */ 947 lock_args.locker.u.open_owner.open_stateid = stateid; 948 lock_args.locker.u.open_owner.lock_seqid = 0; /* ignored */ 949 lock_args.locker.u.open_owner.lock_owner = owner; 950 } 951 lock_res.u.resok4.lock_stateid = &stateid->stateid; 952 lock_res.u.denied.owner.owner_len = NFS4_OPAQUE_LIMIT; 953 954 status = compound_encode_send_decode(session, &compound, try_recovery); 955 if (status) 956 goto out; 957 958 if (compound_error(status = compound.res.status)) 959 goto out; 960 961 stateid->type = STATEID_LOCK; /* returning a lock stateid */ 962 out: 963 return status; 964 } 965 966 int nfs41_unlock( 967 IN nfs41_session *session, 968 IN nfs41_path_fh *file, 969 IN uint64_t offset, 970 IN uint64_t length, 971 IN OUT stateid_arg *stateid) 972 { 973 int status; 974 nfs41_compound compound; 975 nfs_argop4 argops[3]; 976 nfs_resop4 resops[3]; 977 nfs41_sequence_args sequence_args; 978 nfs41_sequence_res sequence_res; 979 nfs41_putfh_args putfh_args; 980 nfs41_putfh_res putfh_res; 981 nfs41_locku_args locku_args; 982 nfs41_locku_res locku_res; 983 984 compound_init(&compound, argops, resops, "unlock"); 985 986 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 987 nfs41_session_sequence(&sequence_args, session, 0); 988 989 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 990 putfh_args.file = file; 991 putfh_args.in_recovery = 0; 992 993 compound_add_op(&compound, OP_LOCKU, &locku_args, &locku_res); 994 /* 18.12.3: the server MUST accept any legal value for locktype */ 995 locku_args.locktype = READ_LT; 996 locku_args.offset = offset; 997 locku_args.length = length; 998 locku_args.lock_stateid = stateid; 999 locku_res.lock_stateid = &stateid->stateid; 1000 1001 status = compound_encode_send_decode(session, &compound, TRUE); 1002 if (status) 1003 goto out; 1004 1005 compound_error(status = compound.res.status); 1006 out: 1007 return status; 1008 } 1009 1010 int nfs41_readdir( 1011 IN nfs41_session *session, 1012 IN nfs41_path_fh *file, 1013 IN bitmap4 *attr_request, 1014 IN nfs41_readdir_cookie *cookie, 1015 OUT unsigned char *entries, 1016 IN OUT uint32_t *entries_len, 1017 OUT bool_t *eof_out) 1018 { 1019 int status; 1020 nfs41_compound compound; 1021 nfs_argop4 argops[3]; 1022 nfs_resop4 resops[3]; 1023 nfs41_sequence_args sequence_args; 1024 nfs41_sequence_res sequence_res; 1025 nfs41_putfh_args putfh_args; 1026 nfs41_putfh_res putfh_res; 1027 nfs41_readdir_args readdir_args; 1028 nfs41_readdir_res readdir_res; 1029 1030 compound_init(&compound, argops, resops, "readdir"); 1031 1032 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1033 nfs41_session_sequence(&sequence_args, session, 0); 1034 1035 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1036 putfh_args.file = file; 1037 putfh_args.in_recovery = 0; 1038 1039 compound_add_op(&compound, OP_READDIR, &readdir_args, &readdir_res); 1040 readdir_args.cookie.cookie = cookie->cookie; 1041 memcpy(readdir_args.cookie.verf, cookie->verf, NFS4_VERIFIER_SIZE); 1042 readdir_args.dircount = *entries_len; 1043 readdir_args.maxcount = *entries_len + sizeof(nfs41_readdir_res); 1044 readdir_args.attr_request = attr_request; 1045 readdir_res.reply.entries_len = *entries_len; 1046 readdir_res.reply.entries = entries; 1047 ZeroMemory(entries, readdir_args.dircount); 1048 1049 status = compound_encode_send_decode(session, &compound, TRUE); 1050 if (status) 1051 goto out; 1052 1053 if (compound_error(status = compound.res.status)) 1054 goto out; 1055 1056 *entries_len = readdir_res.reply.entries_len; 1057 *eof_out = readdir_res.reply.eof; 1058 memcpy(cookie->verf, readdir_res.cookieverf, NFS4_VERIFIER_SIZE); 1059 out: 1060 return status; 1061 } 1062 1063 int nfs41_getattr( 1064 IN nfs41_session *session, 1065 IN OPTIONAL nfs41_path_fh *file, 1066 IN bitmap4 *attr_request, 1067 OUT nfs41_file_info *info) 1068 { 1069 int status; 1070 nfs41_compound compound; 1071 nfs_argop4 argops[3]; 1072 nfs_resop4 resops[3]; 1073 nfs41_sequence_args sequence_args; 1074 nfs41_sequence_res sequence_res; 1075 nfs41_putfh_args putfh_args; 1076 nfs41_putfh_res putfh_res; 1077 nfs41_getattr_args getattr_args; 1078 nfs41_getattr_res getattr_res; 1079 1080 compound_init(&compound, argops, resops, "getattr"); 1081 1082 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1083 nfs41_session_sequence(&sequence_args, session, 0); 1084 1085 if (file) { 1086 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1087 putfh_args.file = file; 1088 putfh_args.in_recovery = 0; 1089 } else { 1090 compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res); 1091 } 1092 1093 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 1094 getattr_args.attr_request = attr_request; 1095 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1096 getattr_res.info = info; 1097 1098 status = compound_encode_send_decode(session, &compound, TRUE); 1099 if (status) 1100 goto out; 1101 1102 if (compound_error(status = compound.res.status)) 1103 goto out; 1104 1105 if (file) { 1106 /* update the name cache with whatever attributes we got */ 1107 memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask, 1108 sizeof(bitmap4)); 1109 nfs41_attr_cache_update(session_name_cache(session), 1110 file->fh.fileid, info); 1111 } 1112 out: 1113 return status; 1114 } 1115 1116 int nfs41_superblock_getattr( 1117 IN nfs41_session *session, 1118 IN nfs41_path_fh *file, 1119 IN bitmap4 *attr_request, 1120 OUT nfs41_file_info *info, 1121 OUT bool_t *supports_named_attrs) 1122 { 1123 int status; 1124 nfs41_compound compound; 1125 nfs_argop4 argops[4]; 1126 nfs_resop4 resops[4]; 1127 nfs41_sequence_args sequence_args; 1128 nfs41_sequence_res sequence_res; 1129 nfs41_putfh_args putfh_args; 1130 nfs41_putfh_res putfh_res; 1131 nfs41_getattr_args getattr_args; 1132 nfs41_getattr_res getattr_res; 1133 nfs41_openattr_args openattr_args; 1134 nfs41_openattr_res openattr_res; 1135 1136 compound_init(&compound, argops, resops, "getfsattr"); 1137 1138 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1139 nfs41_session_sequence(&sequence_args, session, 0); 1140 1141 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1142 putfh_args.file = file; 1143 putfh_args.in_recovery = 0; 1144 1145 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 1146 getattr_args.attr_request = attr_request; 1147 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1148 getattr_res.info = info; 1149 1150 compound_add_op(&compound, OP_OPENATTR, &openattr_args, &openattr_res); 1151 openattr_args.createdir = 0; 1152 1153 status = compound_encode_send_decode(session, &compound, TRUE); 1154 if (status) 1155 goto out; 1156 1157 status = sequence_res.sr_status; 1158 if (status) goto out; 1159 status = putfh_res.status; 1160 if (status) goto out; 1161 status = getattr_res.status; 1162 if (status) goto out; 1163 1164 switch (status = openattr_res.status) { 1165 case NFS4ERR_NOTSUPP: 1166 *supports_named_attrs = 0; 1167 status = NFS4_OK; 1168 break; 1169 1170 case NFS4ERR_NOENT: 1171 case NFS4_OK: 1172 *supports_named_attrs = 1; 1173 status = NFS4_OK; 1174 break; 1175 } 1176 out: 1177 return status; 1178 } 1179 1180 int nfs41_remove( 1181 IN nfs41_session *session, 1182 IN nfs41_path_fh *parent, 1183 IN const nfs41_component *target, 1184 IN uint64_t fileid) 1185 { 1186 int status; 1187 nfs41_compound compound; 1188 nfs_argop4 argops[4]; 1189 nfs_resop4 resops[4]; 1190 nfs41_sequence_args sequence_args; 1191 nfs41_sequence_res sequence_res; 1192 nfs41_putfh_args putfh_args; 1193 nfs41_putfh_res putfh_res; 1194 nfs41_remove_args remove_args; 1195 nfs41_remove_res remove_res; 1196 nfs41_getattr_args getattr_args; 1197 nfs41_getattr_res getattr_res; 1198 bitmap4 attr_request; 1199 nfs41_file_info info; 1200 1201 nfs41_superblock_getattr_mask(parent->fh.superblock, &attr_request); 1202 1203 compound_init(&compound, argops, resops, "remove"); 1204 1205 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1206 nfs41_session_sequence(&sequence_args, session, 1); 1207 1208 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1209 putfh_args.file = parent; 1210 putfh_args.in_recovery = 0; 1211 1212 compound_add_op(&compound, OP_REMOVE, &remove_args, &remove_res); 1213 remove_args.target = target; 1214 1215 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 1216 getattr_args.attr_request = &attr_request; 1217 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1218 getattr_res.info = &info; 1219 1220 status = compound_encode_send_decode(session, &compound, TRUE); 1221 if (status) 1222 goto out; 1223 1224 if (compound_error(status = compound.res.status)) 1225 goto out; 1226 1227 if (info.type == NF4ATTRDIR) 1228 goto out; 1229 1230 /* update the attributes of the parent directory */ 1231 memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, 1232 sizeof(bitmap4)); 1233 nfs41_attr_cache_update(session_name_cache(session), 1234 parent->fh.fileid, &info); 1235 1236 /* remove the target file from the cache */ 1237 AcquireSRWLockShared(&parent->path->lock); 1238 nfs41_name_cache_remove(session_name_cache(session), 1239 parent->path->path, target, fileid, &remove_res.cinfo); 1240 ReleaseSRWLockShared(&parent->path->lock); 1241 1242 nfs41_superblock_space_changed(parent->fh.superblock); 1243 out: 1244 return status; 1245 } 1246 1247 int nfs41_rename( 1248 IN nfs41_session *session, 1249 IN nfs41_path_fh *src_dir, 1250 IN const nfs41_component *src_name, 1251 IN nfs41_path_fh *dst_dir, 1252 IN const nfs41_component *dst_name) 1253 { 1254 int status; 1255 nfs41_compound compound; 1256 nfs_argop4 argops[8]; 1257 nfs_resop4 resops[8]; 1258 nfs41_sequence_args sequence_args; 1259 nfs41_sequence_res sequence_res; 1260 nfs41_putfh_args src_putfh_args; 1261 nfs41_putfh_res src_putfh_res; 1262 nfs41_savefh_res savefh_res; 1263 nfs41_putfh_args dst_putfh_args; 1264 nfs41_putfh_res dst_putfh_res; 1265 nfs41_rename_args rename_args; 1266 nfs41_rename_res rename_res; 1267 nfs41_getattr_args getattr_args; 1268 nfs41_getattr_res src_getattr_res, dst_getattr_res; 1269 nfs41_file_info src_info, dst_info; 1270 bitmap4 attr_request; 1271 nfs41_restorefh_res restorefh_res; 1272 1273 nfs41_superblock_getattr_mask(src_dir->fh.superblock, &attr_request); 1274 1275 compound_init(&compound, argops, resops, "rename"); 1276 1277 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1278 nfs41_session_sequence(&sequence_args, session, 1); 1279 1280 compound_add_op(&compound, OP_PUTFH, &src_putfh_args, &src_putfh_res); 1281 src_putfh_args.file = src_dir; 1282 src_putfh_args.in_recovery = 0; 1283 1284 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); 1285 1286 compound_add_op(&compound, OP_PUTFH, &dst_putfh_args, &dst_putfh_res); 1287 dst_putfh_args.file = dst_dir; 1288 dst_putfh_args.in_recovery = 0; 1289 1290 compound_add_op(&compound, OP_RENAME, &rename_args, &rename_res); 1291 rename_args.oldname = src_name; 1292 rename_args.newname = dst_name; 1293 1294 compound_add_op(&compound, OP_GETATTR, &getattr_args, &dst_getattr_res); 1295 getattr_args.attr_request = &attr_request; 1296 dst_getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1297 dst_getattr_res.info = &dst_info; 1298 1299 compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); 1300 1301 compound_add_op(&compound, OP_GETATTR, &getattr_args, &src_getattr_res); 1302 src_getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1303 src_getattr_res.info = &src_info; 1304 1305 status = compound_encode_send_decode(session, &compound, TRUE); 1306 if (status) 1307 goto out; 1308 1309 if (compound_error(status = compound.res.status)) 1310 goto out; 1311 1312 /* update the attributes of the source directory */ 1313 memcpy(&src_info.attrmask, &src_getattr_res.obj_attributes.attrmask, 1314 sizeof(bitmap4)); 1315 nfs41_attr_cache_update(session_name_cache(session), 1316 src_dir->fh.fileid, &src_info); 1317 1318 /* update the attributes of the destination directory */ 1319 memcpy(&dst_info.attrmask, &dst_getattr_res.obj_attributes.attrmask, 1320 sizeof(bitmap4)); 1321 nfs41_attr_cache_update(session_name_cache(session), 1322 dst_dir->fh.fileid, &dst_info); 1323 1324 if (src_dir->path == dst_dir->path) { 1325 /* source and destination are the same, only lock it once */ 1326 AcquireSRWLockShared(&src_dir->path->lock); 1327 } else if (src_dir->path < dst_dir->path) { 1328 /* lock the lowest memory address first */ 1329 AcquireSRWLockShared(&src_dir->path->lock); 1330 AcquireSRWLockShared(&dst_dir->path->lock); 1331 } else { 1332 AcquireSRWLockShared(&dst_dir->path->lock); 1333 AcquireSRWLockShared(&src_dir->path->lock); 1334 } 1335 1336 /* move/rename the target file's name cache entry */ 1337 nfs41_name_cache_rename(session_name_cache(session), 1338 src_dir->path->path, src_name, &rename_res.source_cinfo, 1339 dst_dir->path->path, dst_name, &rename_res.target_cinfo); 1340 1341 if (src_dir->path == dst_dir->path) { 1342 ReleaseSRWLockShared(&src_dir->path->lock); 1343 } else { 1344 ReleaseSRWLockShared(&src_dir->path->lock); 1345 ReleaseSRWLockShared(&dst_dir->path->lock); 1346 } 1347 out: 1348 return status; 1349 } 1350 1351 int nfs41_setattr( 1352 IN nfs41_session *session, 1353 IN nfs41_path_fh *file, 1354 IN stateid_arg *stateid, 1355 IN nfs41_file_info *info) 1356 { 1357 int status; 1358 nfs41_compound compound; 1359 nfs_argop4 argops[4]; 1360 nfs_resop4 resops[4]; 1361 nfs41_sequence_args sequence_args; 1362 nfs41_sequence_res sequence_res; 1363 nfs41_putfh_args putfh_args; 1364 nfs41_putfh_res putfh_res; 1365 nfs41_setattr_args setattr_args; 1366 nfs41_setattr_res setattr_res; 1367 nfs41_getattr_args getattr_args; 1368 nfs41_getattr_res getattr_res; 1369 bitmap4 attr_request; 1370 1371 compound_init(&compound, argops, resops, "setattr"); 1372 1373 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1374 nfs41_session_sequence(&sequence_args, session, 0); 1375 1376 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1377 putfh_args.file = file; 1378 putfh_args.in_recovery = 0; 1379 1380 compound_add_op(&compound, OP_SETATTR, &setattr_args, &setattr_res); 1381 setattr_args.stateid = stateid; 1382 setattr_args.info = info; 1383 1384 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request); 1385 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 1386 getattr_args.attr_request = &attr_request; 1387 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1388 getattr_res.info = info; 1389 1390 status = compound_encode_send_decode(session, &compound, TRUE); 1391 if (status) 1392 goto out; 1393 1394 if (compound_error(status = compound.res.status)) 1395 goto out; 1396 1397 memcpy(&info->attrmask, &attr_request, sizeof(bitmap4)); 1398 nfs41_attr_cache_update(session_name_cache(session), 1399 file->fh.fileid, info); 1400 1401 if (setattr_res.attrsset.arr[0] & FATTR4_WORD0_SIZE) 1402 nfs41_superblock_space_changed(file->fh.superblock); 1403 out: 1404 return status; 1405 } 1406 1407 int nfs41_link( 1408 IN nfs41_session *session, 1409 IN nfs41_path_fh *src, 1410 IN nfs41_path_fh *dst_dir, 1411 IN const nfs41_component *target, 1412 OUT nfs41_file_info *cinfo) 1413 { 1414 int status; 1415 nfs41_compound compound; 1416 nfs_argop4 argops[9]; 1417 nfs_resop4 resops[9]; 1418 nfs41_sequence_args sequence_args; 1419 nfs41_sequence_res sequence_res; 1420 nfs41_putfh_args putfh_args[2]; 1421 nfs41_putfh_res putfh_res[2]; 1422 nfs41_savefh_res savefh_res; 1423 nfs41_link_args link_args; 1424 nfs41_link_res link_res; 1425 nfs41_lookup_args lookup_args; 1426 nfs41_lookup_res lookup_res; 1427 nfs41_getfh_res getfh_res; 1428 nfs41_getattr_args getattr_args[2]; 1429 nfs41_getattr_res getattr_res[2]; 1430 nfs41_file_info info = { 0 }; 1431 nfs41_path_fh file; 1432 1433 nfs41_superblock_getattr_mask(src->fh.superblock, &info.attrmask); 1434 nfs41_superblock_getattr_mask(dst_dir->fh.superblock, &cinfo->attrmask); 1435 cinfo->attrmask.arr[0] |= FATTR4_WORD0_FSID; 1436 1437 compound_init(&compound, argops, resops, "link"); 1438 1439 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1440 nfs41_session_sequence(&sequence_args, session, 1); 1441 1442 /* PUTFH(src) */ 1443 compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]); 1444 putfh_args[0].file = src; 1445 putfh_args[0].in_recovery = 0; 1446 1447 compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); 1448 1449 /* PUTFH(dst_dir) */ 1450 compound_add_op(&compound, OP_PUTFH, &putfh_args[1], &putfh_res[1]); 1451 putfh_args[1].file = dst_dir; 1452 putfh_args[1].in_recovery = 0; 1453 1454 compound_add_op(&compound, OP_LINK, &link_args, &link_res); 1455 link_args.newname = target; 1456 1457 /* GETATTR(dst_dir) */ 1458 compound_add_op(&compound, OP_GETATTR, &getattr_args[0], &getattr_res[0]); 1459 getattr_args[0].attr_request = &info.attrmask; 1460 getattr_res[0].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1461 getattr_res[0].info = &info; 1462 1463 /* LOOKUP(target) */ 1464 compound_add_op(&compound, OP_LOOKUP, &lookup_args, &lookup_res); 1465 lookup_args.name = target; 1466 1467 /* GETATTR(target) */ 1468 compound_add_op(&compound, OP_GETATTR, &getattr_args[1], &getattr_res[1]); 1469 getattr_args[1].attr_request = &cinfo->attrmask; 1470 getattr_res[1].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1471 getattr_res[1].info = cinfo; 1472 1473 /* GETFH(target) */ 1474 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); 1475 getfh_res.fh = &file.fh; 1476 1477 status = compound_encode_send_decode(session, &compound, TRUE); 1478 if (status) 1479 goto out; 1480 1481 if (compound_error(status = compound.res.status)) 1482 goto out; 1483 1484 /* fill in the file handle's fileid and superblock */ 1485 file.fh.fileid = cinfo->fileid; 1486 status = nfs41_superblock_for_fh(session, 1487 &cinfo->fsid, &dst_dir->fh, &file); 1488 if (status) 1489 goto out; 1490 1491 /* update the attributes of the destination directory */ 1492 memcpy(&info.attrmask, &getattr_res[0].obj_attributes.attrmask, 1493 sizeof(bitmap4)); 1494 nfs41_attr_cache_update(session_name_cache(session), 1495 info.fileid, &info); 1496 1497 /* add the new file handle and attributes to the name cache */ 1498 memcpy(&cinfo->attrmask, &getattr_res[1].obj_attributes.attrmask, 1499 sizeof(bitmap4)); 1500 AcquireSRWLockShared(&dst_dir->path->lock); 1501 nfs41_name_cache_insert(session_name_cache(session), 1502 dst_dir->path->path, target, &file.fh, 1503 cinfo, &link_res.cinfo, OPEN_DELEGATE_NONE); 1504 ReleaseSRWLockShared(&dst_dir->path->lock); 1505 1506 nfs41_superblock_space_changed(dst_dir->fh.superblock); 1507 out: 1508 return status; 1509 } 1510 1511 int nfs41_readlink( 1512 IN nfs41_session *session, 1513 IN nfs41_path_fh *file, 1514 IN uint32_t max_len, 1515 OUT char *link_out, 1516 OUT uint32_t *len_out) 1517 { 1518 int status; 1519 nfs41_compound compound; 1520 nfs_argop4 argops[3]; 1521 nfs_resop4 resops[3]; 1522 nfs41_sequence_args sequence_args; 1523 nfs41_sequence_res sequence_res; 1524 nfs41_putfh_args putfh_args; 1525 nfs41_putfh_res putfh_res; 1526 nfs41_readlink_res readlink_res; 1527 1528 compound_init(&compound, argops, resops, "readlink"); 1529 1530 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1531 nfs41_session_sequence(&sequence_args, session, 0); 1532 1533 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1534 putfh_args.file = file; 1535 putfh_args.in_recovery = 0; 1536 1537 compound_add_op(&compound, OP_READLINK, NULL, &readlink_res); 1538 readlink_res.link_len = max_len - 1; 1539 readlink_res.link = link_out; 1540 1541 status = compound_encode_send_decode(session, &compound, TRUE); 1542 if (status) 1543 goto out; 1544 1545 if (compound_error(status = compound.res.status)) 1546 goto out; 1547 1548 link_out[readlink_res.link_len] = '\0'; 1549 *len_out = readlink_res.link_len; 1550 out: 1551 return status; 1552 } 1553 1554 int nfs41_access( 1555 IN nfs41_session *session, 1556 IN nfs41_path_fh *file, 1557 IN uint32_t requested, 1558 OUT uint32_t *supported OPTIONAL, 1559 OUT uint32_t *access OPTIONAL) 1560 { 1561 int status; 1562 nfs41_compound compound; 1563 nfs_argop4 argops[3]; 1564 nfs_resop4 resops[3]; 1565 nfs41_sequence_args sequence_args; 1566 nfs41_sequence_res sequence_res; 1567 nfs41_putfh_args putfh_args; 1568 nfs41_putfh_res putfh_res; 1569 nfs41_access_args access_args; 1570 nfs41_access_res access_res; 1571 1572 compound_init(&compound, argops, resops, "access"); 1573 1574 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1575 nfs41_session_sequence(&sequence_args, session, 0); 1576 1577 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1578 putfh_args.file = file; 1579 putfh_args.in_recovery = 0; 1580 1581 compound_add_op(&compound, OP_ACCESS, &access_args, &access_res); 1582 access_args.access = requested; 1583 1584 status = compound_encode_send_decode(session, &compound, TRUE); 1585 if (status) 1586 goto out; 1587 1588 if (compound_error(status = compound.res.status)) 1589 goto out; 1590 1591 if (supported) 1592 *supported = access_res.supported; 1593 if (access) 1594 *access = access_res.access; 1595 out: 1596 return status; 1597 } 1598 1599 int nfs41_send_sequence( 1600 IN nfs41_session *session) 1601 { 1602 int status; 1603 nfs41_compound compound; 1604 nfs_argop4 argops[1]; 1605 nfs_resop4 resops[1]; 1606 nfs41_sequence_args sequence_args; 1607 nfs41_sequence_res sequence_res; 1608 1609 compound_init(&compound, argops, resops, "sequence"); 1610 1611 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1612 nfs41_session_sequence(&sequence_args, session, 0); 1613 1614 status = compound_encode_send_decode(session, &compound, TRUE); 1615 if (status) 1616 goto out; 1617 1618 if (compound_error(status = compound.res.status)) 1619 goto out; 1620 out: 1621 return status; 1622 } 1623 1624 enum nfsstat4 nfs41_want_delegation( 1625 IN nfs41_session *session, 1626 IN nfs41_path_fh *file, 1627 IN deleg_claim4 *claim, 1628 IN uint32_t want, 1629 IN bool_t try_recovery, 1630 OUT open_delegation4 *delegation) 1631 { 1632 enum nfsstat4 status; 1633 nfs41_compound compound; 1634 nfs_argop4 argops[3]; 1635 nfs_resop4 resops[3]; 1636 nfs41_sequence_args sequence_args; 1637 nfs41_sequence_res sequence_res; 1638 nfs41_putfh_args putfh_args; 1639 nfs41_putfh_res putfh_res; 1640 nfs41_want_delegation_args wd_args; 1641 nfs41_want_delegation_res wd_res; 1642 1643 compound_init(&compound, argops, resops, "want_delegation"); 1644 1645 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1646 nfs41_session_sequence(&sequence_args, session, 0); 1647 1648 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1649 putfh_args.file = file; 1650 putfh_args.in_recovery = 0; 1651 1652 compound_add_op(&compound, OP_WANT_DELEGATION, &wd_args, &wd_res); 1653 wd_args.claim = claim; 1654 wd_args.want = want; 1655 wd_res.delegation = delegation; 1656 1657 status = compound_encode_send_decode(session, &compound, try_recovery); 1658 if (status) 1659 goto out; 1660 1661 compound_error(status = compound.res.status); 1662 out: 1663 return status; 1664 } 1665 1666 int nfs41_delegpurge( 1667 IN nfs41_session *session) 1668 { 1669 int status; 1670 nfs41_compound compound; 1671 nfs_argop4 argops[2]; 1672 nfs_resop4 resops[2]; 1673 nfs41_sequence_args sequence_args; 1674 nfs41_sequence_res sequence_res; 1675 nfs41_delegpurge_res dp_res; 1676 1677 compound_init(&compound, argops, resops, "delegpurge"); 1678 1679 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1680 nfs41_session_sequence(&sequence_args, session, 0); 1681 1682 compound_add_op(&compound, OP_DELEGPURGE, NULL, &dp_res); 1683 1684 status = compound_encode_send_decode(session, &compound, TRUE); 1685 if (status) 1686 goto out; 1687 1688 compound_error(status = compound.res.status); 1689 out: 1690 return status; 1691 } 1692 1693 int nfs41_delegreturn( 1694 IN nfs41_session *session, 1695 IN nfs41_path_fh *file, 1696 IN stateid_arg *stateid, 1697 IN bool_t try_recovery) 1698 { 1699 int status; 1700 nfs41_compound compound; 1701 nfs_argop4 argops[3]; 1702 nfs_resop4 resops[3]; 1703 nfs41_sequence_args sequence_args; 1704 nfs41_sequence_res sequence_res; 1705 nfs41_putfh_args putfh_args; 1706 nfs41_putfh_res putfh_res; 1707 nfs41_delegreturn_args dr_args; 1708 nfs41_delegreturn_res dr_res; 1709 1710 compound_init(&compound, argops, resops, "delegreturn"); 1711 1712 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1713 nfs41_session_sequence(&sequence_args, session, 0); 1714 1715 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1716 putfh_args.file = file; 1717 putfh_args.in_recovery = 0; 1718 1719 compound_add_op(&compound, OP_DELEGRETURN, &dr_args, &dr_res); 1720 dr_args.stateid = stateid; 1721 1722 status = compound_encode_send_decode(session, &compound, try_recovery); 1723 if (status) 1724 goto out; 1725 1726 if (compound_error(status = compound.res.status)) 1727 goto out; 1728 1729 AcquireSRWLockShared(&file->path->lock); 1730 nfs41_name_cache_delegreturn(session_name_cache(session), 1731 file->fh.fileid, file->path->path, &file->name); 1732 ReleaseSRWLockShared(&file->path->lock); 1733 out: 1734 return status; 1735 } 1736 1737 enum nfsstat4 nfs41_fs_locations( 1738 IN nfs41_session *session, 1739 IN nfs41_path_fh *parent, 1740 IN const nfs41_component *name, 1741 OUT fs_locations4 *locations) 1742 { 1743 enum nfsstat4 status; 1744 nfs41_compound compound; 1745 nfs_argop4 argops[4]; 1746 nfs_resop4 resops[4]; 1747 nfs41_sequence_args sequence_args; 1748 nfs41_sequence_res sequence_res; 1749 nfs41_putfh_args putfh_args; 1750 nfs41_putfh_res putfh_res; 1751 nfs41_lookup_args lookup_args; 1752 nfs41_lookup_res lookup_res; 1753 nfs41_getattr_args getattr_args; 1754 nfs41_getattr_res getattr_res; 1755 bitmap4 attr_request = { 1, { FATTR4_WORD0_FS_LOCATIONS } }; 1756 nfs41_file_info info; 1757 1758 compound_init(&compound, argops, resops, "fs_locations"); 1759 1760 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1761 nfs41_session_sequence(&sequence_args, session, 0); 1762 1763 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1764 putfh_args.file = parent; 1765 putfh_args.in_recovery = 0; 1766 1767 compound_add_op(&compound, OP_LOOKUP, &lookup_args, &lookup_res); 1768 lookup_args.name = name; 1769 1770 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 1771 getattr_args.attr_request = &attr_request; 1772 info.fs_locations = locations; 1773 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 1774 getattr_res.info = &info; 1775 1776 status = compound_encode_send_decode(session, &compound, TRUE); 1777 if (status) 1778 goto out; 1779 1780 compound_error(status = compound.res.status); 1781 out: 1782 return status; 1783 } 1784 1785 int nfs41_secinfo( 1786 IN nfs41_session *session, 1787 IN nfs41_path_fh *file, 1788 IN const nfs41_component *name, 1789 OUT nfs41_secinfo_info *secinfo) 1790 { 1791 int status; 1792 nfs41_compound compound; 1793 nfs_argop4 argops[3]; 1794 nfs_resop4 resops[3]; 1795 nfs41_sequence_args sequence_args; 1796 nfs41_sequence_res sequence_res; 1797 nfs41_putfh_args putfh_args; 1798 nfs41_putfh_res putfh_res; 1799 nfs41_secinfo_args secinfo_args; 1800 nfs41_secinfo_noname_res secinfo_res; 1801 1802 compound_init(&compound, argops, resops, "secinfo"); 1803 1804 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1805 nfs41_session_sequence(&sequence_args, session, 0); 1806 1807 if (file == NULL) 1808 compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res); 1809 else { 1810 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1811 putfh_args.file = file; 1812 putfh_args.in_recovery = 0; 1813 } 1814 1815 compound_add_op(&compound, OP_SECINFO, &secinfo_args, &secinfo_res); 1816 secinfo_args.name = name; 1817 secinfo_res.secinfo = secinfo; 1818 1819 status = compound_encode_send_decode(session, &compound, FALSE); 1820 if (status) 1821 goto out; 1822 1823 compound_error(status = compound.res.status); 1824 out: 1825 return status; 1826 } 1827 1828 int nfs41_secinfo_noname( 1829 IN nfs41_session *session, 1830 IN nfs41_path_fh *file, 1831 OUT nfs41_secinfo_info *secinfo) 1832 { 1833 int status; 1834 nfs41_compound compound; 1835 nfs_argop4 argops[3]; 1836 nfs_resop4 resops[3]; 1837 nfs41_sequence_args sequence_args; 1838 nfs41_sequence_res sequence_res; 1839 nfs41_putfh_args putfh_args; 1840 nfs41_putfh_res putfh_res; 1841 nfs41_secinfo_noname_args noname_args; 1842 nfs41_secinfo_noname_res noname_res; 1843 1844 compound_init(&compound, argops, resops, "secinfo_no_name"); 1845 1846 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1847 nfs41_session_sequence(&sequence_args, session, 0); 1848 1849 if (file == NULL) 1850 compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res); 1851 else { 1852 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1853 putfh_args.file = file; 1854 putfh_args.in_recovery = 0; 1855 } 1856 1857 compound_add_op(&compound, OP_SECINFO_NO_NAME, &noname_args, &noname_res); 1858 noname_args.type = SECINFO_STYLE4_CURRENT_FH; 1859 noname_res.secinfo = secinfo; 1860 1861 status = compound_encode_send_decode(session, &compound, FALSE); 1862 if (status) 1863 goto out; 1864 1865 compound_error(status = compound.res.status); 1866 out: 1867 return status; 1868 } 1869 1870 enum nfsstat4 nfs41_free_stateid( 1871 IN nfs41_session *session, 1872 IN stateid4 *stateid) 1873 { 1874 enum nfsstat4 status; 1875 nfs41_compound compound; 1876 nfs_argop4 argops[2]; 1877 nfs_resop4 resops[2]; 1878 nfs41_sequence_args sequence_args; 1879 nfs41_sequence_res sequence_res; 1880 nfs41_free_stateid_args freestateid_args; 1881 nfs41_free_stateid_res freestateid_res; 1882 1883 compound_init(&compound, argops, resops, "free_stateid"); 1884 1885 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1886 nfs41_session_sequence(&sequence_args, session, 0); 1887 1888 compound_add_op(&compound, OP_FREE_STATEID, &freestateid_args, &freestateid_res); 1889 freestateid_args.stateid = stateid; 1890 1891 status = compound_encode_send_decode(session, &compound, FALSE); 1892 if (status) 1893 goto out; 1894 1895 compound_error(status = compound.res.status); 1896 out: 1897 return status; 1898 } 1899 1900 enum nfsstat4 nfs41_test_stateid( 1901 IN nfs41_session *session, 1902 IN stateid_arg *stateid_array, 1903 IN uint32_t count, 1904 OUT uint32_t *status_array) 1905 { 1906 enum nfsstat4 status; 1907 nfs41_compound compound; 1908 nfs_argop4 argops[2]; 1909 nfs_resop4 resops[2]; 1910 nfs41_sequence_args sequence_args; 1911 nfs41_sequence_res sequence_res; 1912 nfs41_test_stateid_args teststateid_args; 1913 nfs41_test_stateid_res teststateid_res; 1914 1915 compound_init(&compound, argops, resops, "test_stateid"); 1916 1917 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1918 nfs41_session_sequence(&sequence_args, session, 0); 1919 1920 compound_add_op(&compound, OP_TEST_STATEID, &teststateid_args, &teststateid_res); 1921 teststateid_args.stateids = stateid_array; 1922 teststateid_args.count = count; 1923 teststateid_res.resok.status = status_array; 1924 teststateid_res.resok.count = count; 1925 1926 status = compound_encode_send_decode(session, &compound, FALSE); 1927 if (status) 1928 goto out; 1929 1930 compound_error(status = compound.res.status); 1931 out: 1932 return status; 1933 } 1934 1935 enum nfsstat4 pnfs_rpc_layoutget( 1936 IN nfs41_session *session, 1937 IN nfs41_path_fh *file, 1938 IN stateid_arg *stateid, 1939 IN enum pnfs_iomode iomode, 1940 IN uint64_t offset, 1941 IN uint64_t minlength, 1942 IN uint64_t length, 1943 OUT pnfs_layoutget_res_ok *layoutget_res_ok) 1944 { 1945 enum nfsstat4 status; 1946 nfs41_compound compound; 1947 nfs_argop4 argops[3]; 1948 nfs_resop4 resops[3]; 1949 nfs41_sequence_args sequence_args; 1950 nfs41_sequence_res sequence_res; 1951 nfs41_putfh_args putfh_args; 1952 nfs41_putfh_res putfh_res; 1953 pnfs_layoutget_args layoutget_args; 1954 pnfs_layoutget_res layoutget_res = { 0 }; 1955 uint32_t i; 1956 struct list_entry *entry; 1957 1958 compound_init(&compound, argops, resops, "layoutget"); 1959 1960 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 1961 nfs41_session_sequence(&sequence_args, session, 0); 1962 1963 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 1964 putfh_args.file = file; 1965 putfh_args.in_recovery = 0; 1966 1967 compound_add_op(&compound, OP_LAYOUTGET, &layoutget_args, &layoutget_res); 1968 layoutget_args.signal_layout_avail = 0; 1969 layoutget_args.layout_type = PNFS_LAYOUTTYPE_FILE; 1970 layoutget_args.iomode = iomode; 1971 layoutget_args.offset = offset; 1972 layoutget_args.minlength = minlength; 1973 layoutget_args.length = length; 1974 layoutget_args.stateid = stateid; 1975 layoutget_args.maxcount = session->fore_chan_attrs.ca_maxresponsesize - READ_OVERHEAD; 1976 1977 layoutget_res.u.res_ok = layoutget_res_ok; 1978 1979 status = compound_encode_send_decode(session, &compound, TRUE); 1980 if (status) 1981 goto out; 1982 1983 if (compound_error(status = compound.res.status)) 1984 goto out; 1985 1986 /* point each file handle to the meta server's superblock */ 1987 list_for_each(entry, &layoutget_res_ok->layouts) { 1988 pnfs_layout *base = list_container(entry, pnfs_layout, entry); 1989 if (base->type == PNFS_LAYOUTTYPE_FILE) { 1990 pnfs_file_layout *layout = (pnfs_file_layout*)base; 1991 for (i = 0; i < layout->filehandles.count; i++) 1992 layout->filehandles.arr[i].fh.superblock = file->fh.superblock; 1993 } 1994 } 1995 out: 1996 return status; 1997 } 1998 1999 enum nfsstat4 pnfs_rpc_layoutcommit( 2000 IN nfs41_session *session, 2001 IN nfs41_path_fh *file, 2002 IN stateid4 *stateid, 2003 IN uint64_t offset, 2004 IN uint64_t length, 2005 IN OPTIONAL uint64_t *new_last_offset, 2006 IN OPTIONAL nfstime4 *new_time_modify, 2007 OUT nfs41_file_info *info) 2008 { 2009 enum nfsstat4 status; 2010 nfs41_compound compound; 2011 nfs_argop4 argops[4]; 2012 nfs_resop4 resops[4]; 2013 nfs41_sequence_args sequence_args; 2014 nfs41_sequence_res sequence_res; 2015 nfs41_putfh_args putfh_args; 2016 nfs41_putfh_res putfh_res; 2017 pnfs_layoutcommit_args lc_args; 2018 pnfs_layoutcommit_res lc_res; 2019 nfs41_getattr_args getattr_args; 2020 nfs41_getattr_res getattr_res; 2021 bitmap4 attr_request; 2022 2023 nfs41_superblock_getattr_mask(file->fh.superblock, &attr_request); 2024 2025 compound_init(&compound, argops, resops, "layoutcommit"); 2026 2027 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 2028 nfs41_session_sequence(&sequence_args, session, 0); 2029 2030 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 2031 putfh_args.file = file; 2032 putfh_args.in_recovery = 0; 2033 2034 compound_add_op(&compound, OP_LAYOUTCOMMIT, &lc_args, &lc_res); 2035 lc_args.offset = offset; 2036 lc_args.length = length; 2037 lc_args.stateid = stateid; 2038 lc_args.new_time = new_time_modify; 2039 lc_args.new_offset = new_last_offset; 2040 2041 compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); 2042 getattr_args.attr_request = &attr_request; 2043 getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; 2044 getattr_res.info = info; 2045 2046 status = compound_encode_send_decode(session, &compound, TRUE); 2047 if (status) 2048 goto out; 2049 2050 if (compound_error(status = compound.res.status)) 2051 goto out; 2052 2053 /* update the attribute cache */ 2054 memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask, 2055 sizeof(bitmap4)); 2056 nfs41_attr_cache_update(session_name_cache(session), 2057 file->fh.fileid, info); 2058 out: 2059 return status; 2060 } 2061 2062 enum nfsstat4 pnfs_rpc_layoutreturn( 2063 IN nfs41_session *session, 2064 IN nfs41_path_fh *file, 2065 IN enum pnfs_layout_type type, 2066 IN enum pnfs_iomode iomode, 2067 IN uint64_t offset, 2068 IN uint64_t length, 2069 IN stateid4 *stateid, 2070 OUT pnfs_layoutreturn_res *layoutreturn_res) 2071 { 2072 enum nfsstat4 status; 2073 nfs41_compound compound; 2074 nfs_argop4 argops[3]; 2075 nfs_resop4 resops[3]; 2076 nfs41_sequence_args sequence_args; 2077 nfs41_sequence_res sequence_res; 2078 nfs41_putfh_args putfh_args; 2079 nfs41_putfh_res putfh_res; 2080 pnfs_layoutreturn_args layoutreturn_args; 2081 2082 compound_init(&compound, argops, resops, "layoutreturn"); 2083 2084 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 2085 nfs41_session_sequence(&sequence_args, session, 0); 2086 2087 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 2088 putfh_args.file = file; 2089 putfh_args.in_recovery = 0; 2090 2091 compound_add_op(&compound, OP_LAYOUTRETURN, &layoutreturn_args, layoutreturn_res); 2092 layoutreturn_args.reclaim = 0; 2093 layoutreturn_args.type = type; 2094 layoutreturn_args.iomode = iomode; 2095 layoutreturn_args.return_type = PNFS_RETURN_FILE; 2096 layoutreturn_args.offset = offset; 2097 layoutreturn_args.length = length; 2098 layoutreturn_args.stateid = stateid; 2099 2100 status = compound_encode_send_decode(session, &compound, TRUE); 2101 if (status) 2102 goto out; 2103 2104 compound_error(status = compound.res.status); 2105 out: 2106 return status; 2107 } 2108 2109 enum nfsstat4 pnfs_rpc_getdeviceinfo( 2110 IN nfs41_session *session, 2111 IN unsigned char *deviceid, 2112 OUT pnfs_file_device *device) 2113 { 2114 enum nfsstat4 status; 2115 nfs41_compound compound; 2116 nfs_argop4 argops[2]; 2117 nfs_resop4 resops[2]; 2118 nfs41_sequence_args sequence_args; 2119 nfs41_sequence_res sequence_res; 2120 pnfs_getdeviceinfo_args getdeviceinfo_args; 2121 pnfs_getdeviceinfo_res getdeviceinfo_res; 2122 2123 compound_init(&compound, argops, resops, "get_deviceinfo"); 2124 2125 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 2126 nfs41_session_sequence(&sequence_args, session, 0); 2127 2128 compound_add_op(&compound, OP_GETDEVICEINFO, 2129 &getdeviceinfo_args, &getdeviceinfo_res); 2130 getdeviceinfo_args.deviceid = deviceid; 2131 getdeviceinfo_args.layout_type = PNFS_LAYOUTTYPE_FILE; 2132 getdeviceinfo_args.maxcount = NFS41_MAX_SERVER_CACHE; /* XXX */ 2133 getdeviceinfo_args.notify_types.count = 0; 2134 getdeviceinfo_res.u.res_ok.device = device; 2135 2136 status = compound_encode_send_decode(session, &compound, TRUE); 2137 if (status) 2138 goto out; 2139 2140 compound_error(status = compound.res.status); 2141 out: 2142 return status; 2143 } 2144 2145 enum nfsstat4 nfs41_rpc_openattr( 2146 IN nfs41_session *session, 2147 IN nfs41_path_fh *file, 2148 IN bool_t createdir, 2149 OUT nfs41_fh *fh_out) 2150 { 2151 enum nfsstat4 status; 2152 nfs41_compound compound; 2153 nfs_argop4 argops[4]; 2154 nfs_resop4 resops[4]; 2155 nfs41_sequence_args sequence_args; 2156 nfs41_sequence_res sequence_res; 2157 nfs41_putfh_args putfh_args; 2158 nfs41_putfh_res putfh_res; 2159 nfs41_openattr_args openattr_args; 2160 nfs41_openattr_res openattr_res; 2161 nfs41_getfh_res getfh_res; 2162 2163 compound_init(&compound, argops, resops, "openattr"); 2164 2165 compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); 2166 nfs41_session_sequence(&sequence_args, session, 0); 2167 2168 compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); 2169 putfh_args.file = file; 2170 putfh_args.in_recovery = FALSE; 2171 2172 compound_add_op(&compound, OP_OPENATTR, &openattr_args, &openattr_res); 2173 openattr_args.createdir = createdir; 2174 2175 compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); 2176 getfh_res.fh = fh_out; 2177 2178 status = compound_encode_send_decode(session, &compound, TRUE); 2179 if (status) 2180 goto out; 2181 2182 compound_error(status = compound.res.status); 2183 2184 fh_out->superblock = file->fh.superblock; 2185 out: 2186 return status; 2187 } 2188