1/* 2 * Copyright (c) 2006-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* 30 * vnode op calls for NFS version 4 31 */ 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/systm.h> 35#include <sys/resourcevar.h> 36#include <sys/proc_internal.h> 37#include <sys/kauth.h> 38#include <sys/mount_internal.h> 39#include <sys/malloc.h> 40#include <sys/kpi_mbuf.h> 41#include <sys/conf.h> 42#include <sys/vnode_internal.h> 43#include <sys/dirent.h> 44#include <sys/fcntl.h> 45#include <sys/lockf.h> 46#include <sys/ubc_internal.h> 47#include <sys/attr.h> 48#include <sys/signalvar.h> 49#include <sys/uio_internal.h> 50 51#include <vfs/vfs_support.h> 52 53#include <sys/vm.h> 54 55#include <sys/time.h> 56#include <kern/clock.h> 57#include <libkern/OSAtomic.h> 58 59#include <miscfs/fifofs/fifo.h> 60#include <miscfs/specfs/specdev.h> 61 62#include <nfs/rpcv2.h> 63#include <nfs/nfsproto.h> 64#include <nfs/nfs.h> 65#include <nfs/nfsnode.h> 66#include <nfs/nfs_gss.h> 67#include <nfs/nfsmount.h> 68#include <nfs/nfs_lock.h> 69#include <nfs/xdr_subs.h> 70#include <nfs/nfsm_subs.h> 71 72#include <net/if.h> 73#include <netinet/in.h> 74#include <netinet/in_var.h> 75#include <vm/vm_kern.h> 76 77#include <kern/task.h> 78#include <kern/sched_prim.h> 79 80 81int 82nfs4_access_rpc(nfsnode_t np, u_long *mode, vfs_context_t ctx) 83{ 84 int error = 0, status, numops, slot; 85 u_int64_t xid; 86 struct nfsm_chain nmreq, nmrep; 87 struct timeval now; 88 uint32_t access, supported = 0, missing; 89 struct nfsmount *nmp = NFSTONMP(np); 90 int nfsvers = nmp->nm_vers; 91 uid_t uid; 92 93 nfsm_chain_null(&nmreq); 94 nfsm_chain_null(&nmrep); 95 96 numops = 3; // PUTFH + ACCESS + GETATTR 97 nfsm_chain_build_alloc_init(error, &nmreq, 17 * NFSX_UNSIGNED); 98 nfsm_chain_add_compound_header(error, &nmreq, "access", numops); 99 numops--; 100 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 101 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize); 102 numops--; 103 nfsm_chain_add_32(error, &nmreq, NFS_OP_ACCESS); 104 nfsm_chain_add_32(error, &nmreq, *mode); 105 numops--; 106 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 107 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 108 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 109 nfsm_chain_build_done(error, &nmreq); 110 nfsm_assert(error, (numops == 0), EPROTO); 111 nfsmout_if(error); 112 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 113 114 nfsm_chain_skip_tag(error, &nmrep); 115 nfsm_chain_get_32(error, &nmrep, numops); 116 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 117 nfsm_chain_op_check(error, &nmrep, NFS_OP_ACCESS); 118 nfsm_chain_get_32(error, &nmrep, supported); 119 nfsm_chain_get_32(error, &nmrep, access); 120 nfsmout_if(error); 121 if ((missing = (*mode & ~supported))) { 122 /* missing support for something(s) we wanted */ 123 if (missing & NFS_ACCESS_DELETE) { 124 /* 125 * If the server doesn't report DELETE (possible 126 * on UNIX systems), we'll assume that it is OK 127 * and just let any subsequent delete action fail 128 * if it really isn't deletable. 129 */ 130 access |= NFS_ACCESS_DELETE; 131 } 132 } 133 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 134 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid); 135 nfsmout_if(error); 136 137 uid = kauth_cred_getuid(vfs_context_ucred(ctx)); 138 slot = nfs_node_mode_slot(np, uid, 1); 139 np->n_modeuid[slot] = uid; 140 microuptime(&now); 141 np->n_modestamp[slot] = now.tv_sec; 142 np->n_mode[slot] = access; 143 144 /* pass back the mode returned with this request */ 145 *mode = np->n_mode[slot]; 146nfsmout: 147 nfsm_chain_cleanup(&nmreq); 148 nfsm_chain_cleanup(&nmrep); 149 return (error); 150} 151 152int 153nfs4_getattr_rpc( 154 nfsnode_t np, 155 mount_t mp, 156 u_char *fhp, 157 size_t fhsize, 158 vfs_context_t ctx, 159 struct nfs_vattr *nvap, 160 u_int64_t *xidp) 161{ 162 struct nfsmount *nmp = mp ? VFSTONFS(mp) : NFSTONMP(np); 163 int error = 0, status, nfsvers, numops; 164 struct nfsm_chain nmreq, nmrep; 165 166 if (!nmp) 167 return (ENXIO); 168 nfsvers = nmp->nm_vers; 169 170 nfsm_chain_null(&nmreq); 171 nfsm_chain_null(&nmrep); 172 173 numops = 2; // PUTFH + GETATTR 174 nfsm_chain_build_alloc_init(error, &nmreq, 15 * NFSX_UNSIGNED); 175 nfsm_chain_add_compound_header(error, &nmreq, "getattr", numops); 176 numops--; 177 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 178 nfsm_chain_add_fh(error, &nmreq, nfsvers, fhp, fhsize); 179 numops--; 180 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 181 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 182 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 183 nfsm_chain_build_done(error, &nmreq); 184 nfsm_assert(error, (numops == 0), EPROTO); 185 nfsmout_if(error); 186 error = nfs_request(np, mp, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, xidp, &status); 187 188 nfsm_chain_skip_tag(error, &nmrep); 189 nfsm_chain_get_32(error, &nmrep, numops); 190 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 191 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 192 nfsmout_if(error); 193 NFS_CLEAR_ATTRIBUTES(nvap->nva_bitmap); 194 error = nfs4_parsefattr(&nmrep, NULL, nvap, NULL, NULL); 195nfsmout: 196 nfsm_chain_cleanup(&nmreq); 197 nfsm_chain_cleanup(&nmrep); 198 return (error); 199} 200 201int 202nfs4_readlink_rpc(nfsnode_t np, char *buf, uint32_t *buflenp, vfs_context_t ctx) 203{ 204 struct nfsmount *nmp; 205 int error = 0, lockerror = ENOENT, status, numops; 206 uint32_t len = 0; 207 u_int64_t xid; 208 struct nfsm_chain nmreq, nmrep; 209 210 nmp = NFSTONMP(np); 211 if (!nmp) 212 return (ENXIO); 213 nfsm_chain_null(&nmreq); 214 nfsm_chain_null(&nmrep); 215 216 numops = 3; // PUTFH + GETATTR + READLINK 217 nfsm_chain_build_alloc_init(error, &nmreq, 16 * NFSX_UNSIGNED); 218 nfsm_chain_add_compound_header(error, &nmreq, "readlink", numops); 219 numops--; 220 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 221 nfsm_chain_add_fh(error, &nmreq, NFS_VER4, np->n_fhp, np->n_fhsize); 222 numops--; 223 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 224 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 225 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 226 numops--; 227 nfsm_chain_add_32(error, &nmreq, NFS_OP_READLINK); 228 nfsm_chain_build_done(error, &nmreq); 229 nfsm_assert(error, (numops == 0), EPROTO); 230 nfsmout_if(error); 231 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 232 233 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) 234 error = lockerror; 235 nfsm_chain_skip_tag(error, &nmrep); 236 nfsm_chain_get_32(error, &nmrep, numops); 237 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 238 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 239 nfsm_chain_loadattr(error, &nmrep, np, NFS_VER4, NULL, &xid); 240 nfsm_chain_op_check(error, &nmrep, NFS_OP_READLINK); 241 nfsm_chain_get_32(error, &nmrep, len); 242 nfsmout_if(error); 243 if (len >= *buflenp) { 244 if (np->n_size && (np->n_size < *buflenp)) 245 len = np->n_size; 246 else 247 len = *buflenp - 1; 248 } 249 nfsm_chain_get_opaque(error, &nmrep, len, buf); 250 if (!error) 251 *buflenp = len; 252nfsmout: 253 if (!lockerror) 254 nfs_unlock(np); 255 nfsm_chain_cleanup(&nmreq); 256 nfsm_chain_cleanup(&nmrep); 257 return (error); 258} 259 260int 261nfs4_read_rpc_async( 262 nfsnode_t np, 263 off_t offset, 264 size_t len, 265 thread_t thd, 266 kauth_cred_t cred, 267 struct nfsreq_cbinfo *cb, 268 struct nfsreq **reqp) 269{ 270 struct nfsmount *nmp; 271 int error = 0, nfsvers, numops; 272 struct nfsm_chain nmreq; 273 274 nmp = NFSTONMP(np); 275 if (!nmp) 276 return (ENXIO); 277 nfsvers = nmp->nm_vers; 278 279 nfsm_chain_null(&nmreq); 280 281 // PUTFH + READ + GETATTR 282 numops = 3; 283 nfsm_chain_build_alloc_init(error, &nmreq, 22 * NFSX_UNSIGNED); 284 nfsm_chain_add_compound_header(error, &nmreq, "read", numops); 285 numops--; 286 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 287 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize); 288 numops--; 289 nfsm_chain_add_32(error, &nmreq, NFS_OP_READ); 290 291 /* XXX use special stateid for now */ 292 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 293 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 294 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 295 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 296 297 nfsm_chain_add_64(error, &nmreq, offset); 298 nfsm_chain_add_32(error, &nmreq, len); 299 numops--; 300 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 301 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 302 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 303 nfsm_chain_build_done(error, &nmreq); 304 nfsm_assert(error, (numops == 0), EPROTO); 305 nfsmout_if(error); 306 error = nfs_request_async(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, cb, reqp); 307nfsmout: 308 nfsm_chain_cleanup(&nmreq); 309 return (error); 310} 311 312int 313nfs4_read_rpc_async_finish( 314 nfsnode_t np, 315 struct nfsreq *req, 316 struct uio *uiop, 317 size_t *lenp, 318 int *eofp) 319{ 320 struct nfsmount *nmp; 321 int error = 0, lockerror, nfsvers, numops, status, eof = 0; 322 size_t retlen = 0; 323 u_int64_t xid; 324 struct nfsm_chain nmrep; 325 326 nmp = NFSTONMP(np); 327 if (!nmp) { 328 nfs_request_async_cancel(req); 329 return (ENXIO); 330 } 331 nfsvers = nmp->nm_vers; 332 333 nfsm_chain_null(&nmrep); 334 335 error = nfs_request_async_finish(req, &nmrep, &xid, &status); 336 if (error == EINPROGRESS) /* async request restarted */ 337 return (error); 338 339 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) 340 error = lockerror; 341 nfsm_chain_skip_tag(error, &nmrep); 342 nfsm_chain_get_32(error, &nmrep, numops); 343 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 344 nfsm_chain_op_check(error, &nmrep, NFS_OP_READ); 345 nfsm_chain_get_32(error, &nmrep, eof); 346 nfsm_chain_get_32(error, &nmrep, retlen); 347 if (!error) { 348 *lenp = MIN(retlen, *lenp); 349 error = nfsm_chain_get_uio(&nmrep, *lenp, uiop); 350 } 351 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 352 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid); 353 if (!lockerror) 354 nfs_unlock(np); 355 if (eofp) { 356 if (!eof && !retlen) 357 eof = 1; 358 *eofp = eof; 359 } 360 nfsm_chain_cleanup(&nmrep); 361 return (error); 362} 363 364int 365nfs4_write_rpc_async( 366 nfsnode_t np, 367 struct uio *uiop, 368 size_t len, 369 thread_t thd, 370 kauth_cred_t cred, 371 int iomode, 372 struct nfsreq_cbinfo *cb, 373 struct nfsreq **reqp) 374{ 375 struct nfsmount *nmp; 376 int error = 0, nfsvers, numops; 377 off_t offset; 378 struct nfsm_chain nmreq; 379 380 nmp = NFSTONMP(np); 381 if (!nmp) 382 return (ENXIO); 383 nfsvers = nmp->nm_vers; 384 385 offset = uiop->uio_offset; 386 387 nfsm_chain_null(&nmreq); 388 389 // PUTFH + WRITE + GETATTR 390 numops = 3; 391 nfsm_chain_build_alloc_init(error, &nmreq, 25 * NFSX_UNSIGNED + len); 392 nfsm_chain_add_compound_header(error, &nmreq, "write", numops); 393 numops--; 394 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 395 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize); 396 numops--; 397 nfsm_chain_add_32(error, &nmreq, NFS_OP_WRITE); 398 399 /* XXX use special stateid for now */ 400 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 401 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 402 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 403 nfsm_chain_add_32(error, &nmreq, 0xffffffff); 404 405 nfsm_chain_add_64(error, &nmreq, uiop->uio_offset); 406 nfsm_chain_add_32(error, &nmreq, iomode); 407 nfsm_chain_add_32(error, &nmreq, len); 408 if (!error) 409 error = nfsm_chain_add_uio(&nmreq, uiop, len); 410 numops--; 411 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 412 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 413 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 414 nfsm_chain_build_done(error, &nmreq); 415 nfsm_assert(error, (numops == 0), EPROTO); 416 nfsmout_if(error); 417 418 error = nfs_request_async(np, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, cb, reqp); 419nfsmout: 420 nfsm_chain_cleanup(&nmreq); 421 return (error); 422} 423 424int 425nfs4_write_rpc_async_finish( 426 nfsnode_t np, 427 struct nfsreq *req, 428 int *iomodep, 429 size_t *rlenp, 430 uint64_t *wverfp) 431{ 432 struct nfsmount *nmp; 433 int error = 0, lockerror = ENOENT, nfsvers, numops, status; 434 int committed = NFS_WRITE_FILESYNC; 435 size_t rlen = 0; 436 u_int64_t xid, wverf; 437 mount_t mp; 438 struct nfsm_chain nmrep; 439 440 nmp = NFSTONMP(np); 441 if (!nmp) { 442 nfs_request_async_cancel(req); 443 return (ENXIO); 444 } 445 nfsvers = nmp->nm_vers; 446 447 nfsm_chain_null(&nmrep); 448 449 error = nfs_request_async_finish(req, &nmrep, &xid, &status); 450 if (error == EINPROGRESS) /* async request restarted */ 451 return (error); 452 nmp = NFSTONMP(np); 453 if (!nmp) 454 error = ENXIO; 455 if (!error && (lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) 456 error = lockerror; 457 nfsm_chain_skip_tag(error, &nmrep); 458 nfsm_chain_get_32(error, &nmrep, numops); 459 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 460 nfsm_chain_op_check(error, &nmrep, NFS_OP_WRITE); 461 nfsm_chain_get_32(error, &nmrep, rlen); 462 nfsmout_if(error); 463 *rlenp = rlen; 464 if (rlen <= 0) 465 error = NFSERR_IO; 466 nfsm_chain_get_32(error, &nmrep, committed); 467 nfsm_chain_get_64(error, &nmrep, wverf); 468 nfsmout_if(error); 469 if (wverfp) 470 *wverfp = wverf; 471 lck_mtx_lock(&nmp->nm_lock); 472 if (!(nmp->nm_state & NFSSTA_HASWRITEVERF)) { 473 nmp->nm_verf = wverf; 474 nmp->nm_state |= NFSSTA_HASWRITEVERF; 475 } else if (nmp->nm_verf != wverf) { 476 nmp->nm_verf = wverf; 477 } 478 lck_mtx_unlock(&nmp->nm_lock); 479 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 480 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid); 481nfsmout: 482 if (!lockerror) 483 nfs_unlock(np); 484 nfsm_chain_cleanup(&nmrep); 485 if ((committed != NFS_WRITE_FILESYNC) && nfs_allow_async && 486 ((mp = NFSTOMP(np))) && (vfs_flags(mp) & MNT_ASYNC)) 487 committed = NFS_WRITE_FILESYNC; 488 *iomodep = committed; 489 return (error); 490} 491 492int 493nfs4_remove_rpc( 494 nfsnode_t dnp, 495 char *name, 496 int namelen, 497 thread_t thd, 498 kauth_cred_t cred) 499{ 500 int error = 0, remove_error = 0, status; 501 struct nfsmount *nmp; 502 int nfsvers, numops; 503 u_int64_t xid; 504 struct nfsm_chain nmreq, nmrep; 505 506 nmp = NFSTONMP(dnp); 507 if (!nmp) 508 return (ENXIO); 509 nfsvers = nmp->nm_vers; 510 511 nfsm_chain_null(&nmreq); 512 nfsm_chain_null(&nmrep); 513 514 // PUTFH, REMOVE, GETATTR 515 numops = 3; 516 nfsm_chain_build_alloc_init(error, &nmreq, 17 * NFSX_UNSIGNED + namelen); 517 nfsm_chain_add_compound_header(error, &nmreq, "remove", numops); 518 numops--; 519 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 520 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize); 521 numops--; 522 nfsm_chain_add_32(error, &nmreq, NFS_OP_REMOVE); 523 nfsm_chain_add_string(error, &nmreq, name, namelen); 524 numops--; 525 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 526 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 527 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 528 nfsm_chain_build_done(error, &nmreq); 529 nfsm_assert(error, (numops == 0), EPROTO); 530 nfsmout_if(error); 531 532 error = nfs_request2(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, thd, cred, 0, &nmrep, &xid, &status); 533 534 nfsm_chain_skip_tag(error, &nmrep); 535 nfsm_chain_get_32(error, &nmrep, numops); 536 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 537 nfsm_chain_op_check(error, &nmrep, NFS_OP_REMOVE); 538 remove_error = error; 539 nfsm_chain_check_change_info(error, &nmrep, dnp); 540 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 541 nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, NULL, &xid); 542 if (error) 543 NATTRINVALIDATE(dnp); 544nfsmout: 545 nfsm_chain_cleanup(&nmreq); 546 nfsm_chain_cleanup(&nmrep); 547 548 dnp->n_flag |= NMODIFIED; 549 550 return (remove_error); 551} 552 553int 554nfs4_rename_rpc( 555 nfsnode_t fdnp, 556 char *fnameptr, 557 int fnamelen, 558 nfsnode_t tdnp, 559 char *tnameptr, 560 int tnamelen, 561 vfs_context_t ctx) 562{ 563 int error = 0, status, nfsvers, numops; 564 struct nfsmount *nmp; 565 u_int64_t xid, savedxid; 566 struct nfsm_chain nmreq, nmrep; 567 568 nmp = NFSTONMP(fdnp); 569 if (!nmp) 570 return (ENXIO); 571 nfsvers = nmp->nm_vers; 572 573 nfsm_chain_null(&nmreq); 574 nfsm_chain_null(&nmrep); 575 576 // PUTFH(FROM), SAVEFH, PUTFH(TO), RENAME, GETATTR(TO), RESTOREFH, GETATTR(FROM) 577 numops = 7; 578 nfsm_chain_build_alloc_init(error, &nmreq, 30 * NFSX_UNSIGNED + fnamelen + tnamelen); 579 nfsm_chain_add_compound_header(error, &nmreq, "rename", numops); 580 numops--; 581 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 582 nfsm_chain_add_fh(error, &nmreq, nfsvers, fdnp->n_fhp, fdnp->n_fhsize); 583 numops--; 584 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH); 585 numops--; 586 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 587 nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize); 588 numops--; 589 nfsm_chain_add_32(error, &nmreq, NFS_OP_RENAME); 590 nfsm_chain_add_string(error, &nmreq, fnameptr, fnamelen); 591 nfsm_chain_add_string(error, &nmreq, tnameptr, tnamelen); 592 numops--; 593 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 594 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 595 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 596 numops--; 597 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH); 598 numops--; 599 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 600 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 601 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 602 nfsm_chain_build_done(error, &nmreq); 603 nfsm_assert(error, (numops == 0), EPROTO); 604 nfsmout_if(error); 605 606 error = nfs_request(fdnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 607 608 nfsm_chain_skip_tag(error, &nmrep); 609 nfsm_chain_get_32(error, &nmrep, numops); 610 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 611 nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH); 612 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 613 nfsm_chain_op_check(error, &nmrep, NFS_OP_RENAME); 614 nfsm_chain_check_change_info(error, &nmrep, fdnp); 615 nfsm_chain_check_change_info(error, &nmrep, tdnp); 616 /* directory attributes: if we don't get them, make sure to invalidate */ 617 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 618 savedxid = xid; 619 nfsm_chain_loadattr(error, &nmrep, tdnp, nfsvers, NULL, &xid); 620 if (error) 621 NATTRINVALIDATE(tdnp); 622 nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH); 623 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 624 xid = savedxid; 625 nfsm_chain_loadattr(error, &nmrep, fdnp, nfsvers, NULL, &xid); 626 if (error) 627 NATTRINVALIDATE(fdnp); 628nfsmout: 629 nfsm_chain_cleanup(&nmreq); 630 nfsm_chain_cleanup(&nmrep); 631 fdnp->n_flag |= NMODIFIED; 632 tdnp->n_flag |= NMODIFIED; 633 /* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. */ 634 if (error == EEXIST) 635 error = 0; 636 return (error); 637} 638 639/* 640 * NFS V4 readdir RPC. 641 */ 642#define DIRHDSIZ ((int)(sizeof(struct dirent) - (MAXNAMLEN + 1))) 643int 644nfs4_readdir_rpc(nfsnode_t dnp, struct uio *uiop, vfs_context_t ctx) 645{ 646 size_t len, tlen, skiplen, left; 647 struct dirent *dp = NULL; 648 vnode_t newvp; 649 nfsuint64 *cookiep; 650 struct componentname cn, *cnp = &cn; 651 nfsuint64 cookie; 652 struct nfsmount *nmp; 653 nfsnode_t np; 654 int error = 0, lockerror, status, more_entries = 1, blksiz = 0, bigenough = 1; 655 int nfsvers, rdirplus, nmreaddirsize, nmrsize, eof, i, numops; 656 u_int64_t xid, savexid; 657 struct nfs_vattr nvattr; 658 struct nfsm_chain nmreq, nmrep; 659 char *cp; 660 const char *tag; 661 uint32_t entry_attrs[NFS_ATTR_BITMAP_LEN]; 662 fhandle_t fh; 663 664#if DIAGNOSTIC 665 /* XXX limitation based on need to adjust uio */ 666 if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) || 667 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1))) 668 panic("nfs4_readdir_rpc: bad uio"); 669#endif 670 nmp = NFSTONMP(dnp); 671 if (!nmp) 672 return (ENXIO); 673 nfsvers = nmp->nm_vers; 674 nmreaddirsize = nmp->nm_readdirsize; 675 nmrsize = nmp->nm_rsize; 676 rdirplus = (nmp->nm_flag & NFSMNT_RDIRPLUS) ? 1 : 0; 677 678 bzero(cnp, sizeof(*cnp)); 679 newvp = NULLVP; 680 681 /* 682 * Set up attribute request for entries. 683 * For READDIRPLUS functionality, get everything. 684 * Otherwise, just get what we need for struct dirent. 685 */ 686 if (rdirplus) { 687 tag = "READDIRPLUS"; 688 for (i=0; i < NFS_ATTR_BITMAP_LEN; i++) 689 entry_attrs[i] = 690 nfs_getattr_bitmap[i] & 691 nmp->nm_fsattr.nfsa_supp_attr[i]; 692 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_FILEHANDLE); 693 } else { 694 tag = "READDIR"; 695 NFS_CLEAR_ATTRIBUTES(entry_attrs); 696 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_TYPE); 697 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_FILEID); 698 } 699 /* XXX NFS_BITMAP_SET(entry_attrs, NFS_FATTR_MOUNTED_ON_FILEID); */ 700 NFS_BITMAP_SET(entry_attrs, NFS_FATTR_RDATTR_ERROR); 701 702 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_SHARED))) 703 return (lockerror); 704 705 /* 706 * If there is no cookie, assume directory was stale. 707 */ 708 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0); 709 if (cookiep) 710 cookie = *cookiep; 711 else { 712 nfs_unlock(dnp); 713 return (NFSERR_BAD_COOKIE); 714 } 715 716 /* 717 * The NFS client is responsible for the "." and ".." 718 * entries in the directory. So, we put them at the top. 719 */ 720 if ((uiop->uio_offset == 0) && 721 ((2*(4 + DIRHDSIZ)) <= uio_uio_resid(uiop))) { 722 /* add "." entry */ 723 len = 2; 724 tlen = nfsm_rndup(len); 725 // LP64todo - fix this! 726 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 727 dp->d_fileno = dnp->n_vattr.nva_fileid; 728 dp->d_namlen = len; 729 dp->d_reclen = tlen + DIRHDSIZ; 730 dp->d_type = DT_DIR; 731 strlcpy(dp->d_name, ".", len); 732 blksiz += dp->d_reclen; 733 if (blksiz == DIRBLKSIZ) 734 blksiz = 0; 735 uiop->uio_offset += DIRHDSIZ + tlen; 736 uio_iov_base_add(uiop, DIRHDSIZ + tlen); 737 uio_uio_resid_add(uiop, -(DIRHDSIZ + tlen)); 738 uio_iov_len_add(uiop, -(DIRHDSIZ + tlen)); 739 /* add ".." entry */ 740 len = 3; 741 tlen = nfsm_rndup(len); 742 // LP64todo - fix this! 743 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 744 if (dnp->n_parent) 745 dp->d_fileno = VTONFS(dnp->n_parent)->n_vattr.nva_fileid; 746 else 747 dp->d_fileno = dnp->n_vattr.nva_fileid; 748 dp->d_namlen = len; 749 dp->d_reclen = tlen + DIRHDSIZ; 750 dp->d_type = DT_DIR; 751 strlcpy(dp->d_name, "..", len); 752 blksiz += dp->d_reclen; 753 if (blksiz == DIRBLKSIZ) 754 blksiz = 0; 755 uiop->uio_offset += DIRHDSIZ + tlen; 756 uio_iov_base_add(uiop, DIRHDSIZ + tlen); 757 uio_uio_resid_add(uiop, -(DIRHDSIZ + tlen)); 758 uio_iov_len_add(uiop, -(DIRHDSIZ + tlen)); 759 cookie.nfsuquad[0] = 0; 760 cookie.nfsuquad[1] = 2; 761 } 762 763 /* 764 * Loop around doing readdir rpc's of size nm_readdirsize 765 * truncated to a multiple of DIRBLKSIZ. 766 * The stopping criteria is EOF or buffer full. 767 */ 768 while (more_entries && bigenough) { 769 nfsm_chain_null(&nmreq); 770 nfsm_chain_null(&nmrep); 771 nfsm_assert(error, NFSTONMP(dnp), ENXIO); 772 773 numops = 3; // PUTFH + GETATTR + READDIR 774 nfsm_chain_build_alloc_init(error, &nmreq, 26 * NFSX_UNSIGNED); 775 nfsm_chain_add_compound_header(error, &nmreq, tag, numops); 776 numops--; 777 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 778 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize); 779 numops--; 780 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 781 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 782 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 783 numops--; 784 nfsm_chain_add_32(error, &nmreq, NFS_OP_READDIR); 785 /* opaque values don't need swapping, but as long */ 786 /* as we are consistent about it, it should be ok */ 787 nfsm_chain_add_32(error, &nmreq, cookie.nfsuquad[0]); 788 if ((cookie.nfsuquad[0] == 0) && (cookie.nfsuquad[1] <= 2)) 789 nfsm_chain_add_32(error, &nmreq, 0); 790 else 791 nfsm_chain_add_32(error, &nmreq, cookie.nfsuquad[1]); 792 nfsm_chain_add_32(error, &nmreq, dnp->n_cookieverf.nfsuquad[0]); 793 nfsm_chain_add_32(error, &nmreq, dnp->n_cookieverf.nfsuquad[1]); 794 nfsm_chain_add_32(error, &nmreq, nmreaddirsize); 795 nfsm_chain_add_32(error, &nmreq, nmrsize); 796 nfsm_chain_add_bitmap(error, &nmreq, entry_attrs, NFS_ATTR_BITMAP_LEN); 797 nfsm_chain_build_done(error, &nmreq); 798 nfsm_assert(error, (numops == 0), EPROTO); 799 nfs_unlock(dnp); 800 nfsmout_if(error); 801 error = nfs_request(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 802 803 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE))) 804 error = lockerror; 805 savexid = xid; 806 nfsm_chain_skip_tag(error, &nmrep); 807 nfsm_chain_get_32(error, &nmrep, numops); 808 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 809 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 810 nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, NULL, &xid); 811 nfsm_chain_op_check(error, &nmrep, NFS_OP_READDIR); 812 nfsm_chain_get_32(error, &nmrep, dnp->n_cookieverf.nfsuquad[0]); 813 nfsm_chain_get_32(error, &nmrep, dnp->n_cookieverf.nfsuquad[1]); 814 nfsm_chain_get_32(error, &nmrep, more_entries); 815 nfs_unlock(dnp); 816 nfsmout_if(error); 817 818 /* Loop through the entries, massaging them into "dirent" form. */ 819 /* If READDIRPLUS, also create the vnodes. */ 820 while (more_entries && bigenough) { 821 /* Entry: COOKIE, NAME, FATTR */ 822 nfsm_chain_get_32(error, &nmrep, cookie.nfsuquad[0]); 823 nfsm_chain_get_32(error, &nmrep, cookie.nfsuquad[1]); 824 nfsm_chain_get_32(error, &nmrep, len); 825 nfsmout_if(error); 826 /* Note: NFS supports longer names, but struct dirent doesn't */ 827 /* so we just truncate the names to fit */ 828 if (len <= 0) { 829 error = EBADRPC; 830 goto nfsmout; 831 } 832 if (len > MAXNAMLEN) { 833 skiplen = len - MAXNAMLEN; 834 len = MAXNAMLEN; 835 } else { 836 skiplen = 0; 837 } 838 tlen = nfsm_rndup(len); 839 if (tlen == len) 840 tlen += 4; /* To ensure null termination */ 841 left = DIRBLKSIZ - blksiz; 842 if ((tlen + DIRHDSIZ) > left) { 843 dp->d_reclen += left; 844 uio_iov_base_add(uiop, left); 845 uio_iov_len_add(uiop, -left); 846 uiop->uio_offset += left; 847 uio_uio_resid_add(uiop, -left); 848 blksiz = 0; 849 } 850 if ((tlen + DIRHDSIZ) > uio_uio_resid(uiop)) { 851 bigenough = 0; 852 break; 853 } 854 // LP64todo - fix this! 855 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 856 dp->d_fileno = 0; 857 dp->d_namlen = len; 858 dp->d_reclen = tlen + DIRHDSIZ; 859 dp->d_type = DT_UNKNOWN; 860 blksiz += dp->d_reclen; 861 if (blksiz == DIRBLKSIZ) 862 blksiz = 0; 863 uiop->uio_offset += DIRHDSIZ; 864#if LP64KERN 865 uio_uio_resid_add(uiop, -((int64_t)DIRHDSIZ)); 866 uio_iov_len_add(uiop, -((int64_t)DIRHDSIZ)); 867#else 868 uio_uio_resid_add(uiop, -((int)DIRHDSIZ)); 869 uio_iov_len_add(uiop, -((int)DIRHDSIZ)); 870#endif 871 uio_iov_base_add(uiop, DIRHDSIZ); 872 // LP64todo - fix this! 873 cnp->cn_nameptr = CAST_DOWN(caddr_t, uio_iov_base(uiop)); 874 cnp->cn_namelen = len; 875 error = nfsm_chain_get_uio(&nmrep, len, uiop); 876 if (skiplen) 877 nfsm_chain_adv(error, &nmrep, 878 nfsm_rndup(len + skiplen) - nfsm_rndup(len)); 879 nfsmout_if(error); 880 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap); 881 error = nfs4_parsefattr(&nmrep, NULL, &nvattr, &fh, NULL); 882 if (error && NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_RDATTR_ERROR)) { 883 /* OK, we didn't get attributes, whatever... */ 884 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap); 885 error = 0; 886 } 887 nfsm_chain_get_32(error, &nmrep, more_entries); 888 nfsmout_if(error); 889 890 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop)); 891 tlen -= len; 892 *cp = '\0'; 893 uio_iov_base_add(uiop, tlen); 894 uio_iov_len_add(uiop, -tlen); 895 uiop->uio_offset += tlen; 896 uio_uio_resid_add(uiop, -tlen); 897 898 /* 899 * Skip any "." and ".." entries returned from server. 900 * (Actually, just leave it in place with d_fileno == 0.) 901 */ 902 if ((cnp->cn_nameptr[0] == '.') && 903 ((len == 1) || ((len == 2) && (cnp->cn_nameptr[1] == '.')))) { 904 /* clear the name too */ 905 dp->d_namlen = 0; 906 dp->d_name[0] = '\0'; 907 continue; 908 } 909 910 if (NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_TYPE)) 911 dp->d_type = IFTODT(VTTOIF(nvattr.nva_type)); 912 if (NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_FILEID)) 913 dp->d_fileno = (int)nvattr.nva_fileid; 914 if (rdirplus && NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_FILEHANDLE) && 915 !NFS_CMPFH(dnp, fh.fh_data, fh.fh_len)) { 916 cnp->cn_hash = 0; 917 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, 918 fh.fh_data, fh.fh_len, &nvattr, &xid, NG_MAKEENTRY, &np); 919 if (!error) { 920 nfs_unlock(np); 921 vnode_put(NFSTOV(np)); 922 } 923 } 924 nfsmout_if(error); 925 } 926 /* If at end of rpc data, get the eof boolean */ 927 if (!more_entries) { 928 nfsm_chain_get_32(error, &nmrep, eof); 929 if (!error) 930 more_entries = (eof == 0); 931 } 932 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_SHARED))) 933 error = lockerror; 934 nfsmout_if(error); 935 nfsm_chain_cleanup(&nmrep); 936 } 937 nfs_unlock(dnp); 938 /* 939 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 940 * by increasing d_reclen for the last record. 941 */ 942 if (blksiz > 0) { 943 left = DIRBLKSIZ - blksiz; 944 dp->d_reclen += left; 945 uio_iov_base_add(uiop, left); 946 uio_iov_len_add(uiop, -left); 947 uiop->uio_offset += left; 948 uio_uio_resid_add(uiop, -left); 949 } 950 951 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE))) 952 error = lockerror; 953 nfsmout_if(error); 954 955 /* 956 * We are now either at the end of the directory or have filled the 957 * block. 958 */ 959 if (bigenough) 960 dnp->n_direofoffset = uiop->uio_offset; 961 else { 962 if (uio_uio_resid(uiop) > 0) 963 printf("EEK! nfs4_readdir_rpc resid > 0\n"); 964 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1); 965 if (cookiep) 966 *cookiep = cookie; 967 } 968 969 nfs_unlock(dnp); 970nfsmout: 971 nfsm_chain_cleanup(&nmreq); 972 nfsm_chain_cleanup(&nmrep); 973 return (error); 974} 975 976int 977nfs4_lookup_rpc_async( 978 nfsnode_t dnp, 979 char *name, 980 int namelen, 981 vfs_context_t ctx, 982 struct nfsreq **reqp) 983{ 984 int error = 0, isdotdot = 0, getattrs = 1, nfsvers, numops; 985 struct nfsm_chain nmreq; 986 uint32_t bitmap[NFS_ATTR_BITMAP_LEN]; 987 struct nfsmount *nmp; 988 989 nmp = NFSTONMP(dnp); 990 if (!nmp) 991 return (ENXIO); 992 nfsvers = nmp->nm_vers; 993 994 if ((name[0] == '.') && (name[1] == '.') && (namelen == 2)) 995 isdotdot = 1; 996 997 nfsm_chain_null(&nmreq); 998 999 // PUTFH, GETATTR, LOOKUP(P), GETATTR (FH) 1000 numops = getattrs ? 4 : 3; 1001 nfsm_chain_build_alloc_init(error, &nmreq, 20 * NFSX_UNSIGNED + namelen); 1002 nfsm_chain_add_compound_header(error, &nmreq, "lookup", numops); 1003 numops--; 1004 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1005 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize); 1006 numops--; 1007 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1008 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 1009 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1010 numops--; 1011 if (isdotdot) { 1012 nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUPP); 1013 } else { 1014 nfsm_chain_add_32(error, &nmreq, NFS_OP_LOOKUP); 1015 nfsm_chain_add_string(error, &nmreq, name, namelen); 1016 } 1017 if (getattrs) { 1018 numops--; 1019 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1020 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap); 1021 NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE); 1022 nfsm_chain_add_bitmap_masked(error, &nmreq, bitmap, 1023 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1024 } 1025 nfsm_chain_build_done(error, &nmreq); 1026 nfsm_assert(error, (numops == 0), EPROTO); 1027 nfsmout_if(error); 1028 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, 1029 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, reqp); 1030nfsmout: 1031 nfsm_chain_cleanup(&nmreq); 1032 return (error); 1033} 1034 1035int 1036nfs4_lookup_rpc_async_finish( 1037 nfsnode_t dnp, 1038 __unused vfs_context_t ctx, 1039 struct nfsreq *req, 1040 u_int64_t *xidp, 1041 fhandle_t *fhp, 1042 struct nfs_vattr *nvap) 1043{ 1044 int error = 0, status, nfsvers, numops; 1045 uint32_t val = 0; 1046 u_int64_t xid; 1047 struct nfsmount *nmp; 1048 struct nfsm_chain nmrep; 1049 1050 nmp = NFSTONMP(dnp); 1051 nfsvers = nmp->nm_vers; 1052 1053 nfsm_chain_null(&nmrep); 1054 1055 error = nfs_request_async_finish(req, &nmrep, &xid, &status); 1056 1057 nfsm_chain_skip_tag(error, &nmrep); 1058 nfsm_chain_get_32(error, &nmrep, numops); 1059 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1060 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1061 if (xidp) 1062 *xidp = xid; 1063 nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, NULL, &xid); 1064 1065 // nfsm_chain_op_check(error, &nmrep, (isdotdot ? NFS_OP_LOOKUPP : NFS_OP_LOOKUP)); 1066 nfsm_chain_get_32(error, &nmrep, val); 1067 nfsm_assert(error, (val == NFS_OP_LOOKUPP) || (val == NFS_OP_LOOKUP), EBADRPC); 1068 nfsm_chain_get_32(error, &nmrep, val); 1069 nfsm_assert(error, (val == NFS_OK), val); 1070 1071 nfsmout_if(error || !fhp || !nvap); 1072 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1073 nfsmout_if(error); 1074 NFS_CLEAR_ATTRIBUTES(nvap->nva_bitmap); 1075 error = nfs4_parsefattr(&nmrep, NULL, nvap, fhp, NULL); 1076 if (!NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FILEHANDLE)) { 1077 error = EBADRPC; 1078 goto nfsmout; 1079 } 1080nfsmout: 1081 nfsm_chain_cleanup(&nmrep); 1082 return (error); 1083} 1084 1085int 1086nfs4_commit_rpc( 1087 nfsnode_t np, 1088 u_int64_t offset, 1089 u_int64_t count, 1090 kauth_cred_t cred) 1091{ 1092 struct nfsmount *nmp; 1093 int error = 0, lockerror, status, nfsvers, numops; 1094 u_int64_t xid, wverf; 1095 uint32_t count32; 1096 struct nfsm_chain nmreq, nmrep; 1097 1098 nmp = NFSTONMP(np); 1099 FSDBG(521, np, offset, count, nmp ? nmp->nm_state : 0); 1100 if (!nmp) 1101 return (ENXIO); 1102 if (!(nmp->nm_state & NFSSTA_HASWRITEVERF)) 1103 return (0); 1104 nfsvers = nmp->nm_vers; 1105 1106 if (count > UINT32_MAX) 1107 count32 = 0; 1108 else 1109 count32 = count; 1110 1111 nfsm_chain_null(&nmreq); 1112 nfsm_chain_null(&nmrep); 1113 1114 // PUTFH, COMMIT, GETATTR 1115 numops = 3; 1116 nfsm_chain_build_alloc_init(error, &nmreq, 19 * NFSX_UNSIGNED); 1117 nfsm_chain_add_compound_header(error, &nmreq, "commit", numops); 1118 numops--; 1119 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1120 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize); 1121 numops--; 1122 nfsm_chain_add_32(error, &nmreq, NFS_OP_COMMIT); 1123 nfsm_chain_add_64(error, &nmreq, offset); 1124 nfsm_chain_add_32(error, &nmreq, count32); 1125 numops--; 1126 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1127 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 1128 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1129 nfsm_chain_build_done(error, &nmreq); 1130 nfsm_assert(error, (numops == 0), EPROTO); 1131 nfsmout_if(error); 1132 error = nfs_request2(np, NULL, &nmreq, NFSPROC4_COMPOUND, 1133 current_thread(), cred, 0, &nmrep, &xid, &status); 1134 1135 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) 1136 error = lockerror; 1137 nfsm_chain_skip_tag(error, &nmrep); 1138 nfsm_chain_get_32(error, &nmrep, numops); 1139 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1140 nfsm_chain_op_check(error, &nmrep, NFS_OP_COMMIT); 1141 nfsm_chain_get_64(error, &nmrep, wverf); 1142 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1143 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid); 1144 if (!lockerror) 1145 nfs_unlock(np); 1146 nfsmout_if(error); 1147 lck_mtx_lock(&nmp->nm_lock); 1148 if (nmp->nm_verf != wverf) { 1149 nmp->nm_verf = wverf; 1150 error = NFSERR_STALEWRITEVERF; 1151 } 1152 lck_mtx_unlock(&nmp->nm_lock); 1153nfsmout: 1154 nfsm_chain_cleanup(&nmreq); 1155 nfsm_chain_cleanup(&nmrep); 1156 return (error); 1157} 1158 1159int 1160nfs4_pathconf_rpc( 1161 nfsnode_t np, 1162 struct nfs_fsattr *nfsap, 1163 vfs_context_t ctx) 1164{ 1165 u_int64_t xid; 1166 int error = 0, lockerror, status, nfsvers, numops; 1167 struct nfsm_chain nmreq, nmrep; 1168 struct nfsmount *nmp = NFSTONMP(np); 1169 uint32_t bitmap[NFS_ATTR_BITMAP_LEN]; 1170 struct nfs_vattr nvattr; 1171 1172 if (!nmp) 1173 return (ENXIO); 1174 nfsvers = nmp->nm_vers; 1175 1176 nfsm_chain_null(&nmreq); 1177 nfsm_chain_null(&nmrep); 1178 1179 /* NFSv4: fetch "pathconf" info for this node */ 1180 numops = 2; // PUTFH + GETATTR 1181 nfsm_chain_build_alloc_init(error, &nmreq, 16 * NFSX_UNSIGNED); 1182 nfsm_chain_add_compound_header(error, &nmreq, "pathconf", numops); 1183 numops--; 1184 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1185 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize); 1186 numops--; 1187 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1188 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap); 1189 NFS_BITMAP_SET(bitmap, NFS_FATTR_MAXLINK); 1190 NFS_BITMAP_SET(bitmap, NFS_FATTR_MAXNAME); 1191 NFS_BITMAP_SET(bitmap, NFS_FATTR_NO_TRUNC); 1192 NFS_BITMAP_SET(bitmap, NFS_FATTR_CHOWN_RESTRICTED); 1193 NFS_BITMAP_SET(bitmap, NFS_FATTR_CASE_INSENSITIVE); 1194 NFS_BITMAP_SET(bitmap, NFS_FATTR_CASE_PRESERVING); 1195 nfsm_chain_add_bitmap_masked(error, &nmreq, bitmap, 1196 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1197 nfsm_chain_build_done(error, &nmreq); 1198 nfsm_assert(error, (numops == 0), EPROTO); 1199 nfsmout_if(error); 1200 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 1201 1202 nfsm_chain_skip_tag(error, &nmrep); 1203 nfsm_chain_get_32(error, &nmrep, numops); 1204 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1205 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1206 nfsmout_if(error); 1207 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap); 1208 error = nfs4_parsefattr(&nmrep, nfsap, &nvattr, NULL, NULL); 1209 nfsmout_if(error); 1210 if ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE))) 1211 error = lockerror; 1212 nfs_loadattrcache(np, &nvattr, &xid, 0); 1213 if (!lockerror) 1214 nfs_unlock(np); 1215nfsmout: 1216 nfsm_chain_cleanup(&nmreq); 1217 nfsm_chain_cleanup(&nmrep); 1218 return (error); 1219} 1220 1221int 1222nfs4_vnop_getattr( 1223 struct vnop_getattr_args /* { 1224 struct vnodeop_desc *a_desc; 1225 vnode_t a_vp; 1226 struct vnode_attr *a_vap; 1227 vfs_context_t a_context; 1228 } */ *ap) 1229{ 1230 struct vnode_attr *vap = ap->a_vap; 1231 struct nfs_vattr nva; 1232 int error; 1233 1234 error = nfs_getattr(VTONFS(ap->a_vp), &nva, ap->a_context, 0); 1235 if (error) 1236 return (error); 1237 1238 /* copy what we have in nva to *a_vap */ 1239 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_RAWDEV)) { 1240 dev_t rdev = makedev(nva.nva_rawdev.specdata1, nva.nva_rawdev.specdata2); 1241 VATTR_RETURN(vap, va_rdev, rdev); 1242 } 1243 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_NUMLINKS)) 1244 VATTR_RETURN(vap, va_nlink, nva.nva_nlink); 1245 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_SIZE)) 1246 VATTR_RETURN(vap, va_data_size, nva.nva_size); 1247 // VATTR_RETURN(vap, va_data_alloc, ???); 1248 // VATTR_RETURN(vap, va_total_size, ???); 1249 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_SPACE_USED)) 1250 VATTR_RETURN(vap, va_total_alloc, nva.nva_bytes); 1251 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_OWNER)) 1252 VATTR_RETURN(vap, va_uid, nva.nva_uid); 1253 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_OWNER_GROUP)) 1254 VATTR_RETURN(vap, va_gid, nva.nva_gid); 1255 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_MODE)) 1256 VATTR_RETURN(vap, va_mode, nva.nva_mode); 1257 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_ARCHIVE) || 1258 NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_HIDDEN)) { 1259 uint32_t flags = 0; 1260 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_ARCHIVE)) 1261 flags |= SF_ARCHIVED; 1262 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_HIDDEN)) 1263 flags |= UF_HIDDEN; 1264 VATTR_RETURN(vap, va_flags, flags); 1265 } 1266 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_TIME_CREATE)) { 1267 vap->va_create_time.tv_sec = nva.nva_timesec[NFSTIME_CREATE]; 1268 vap->va_create_time.tv_nsec = nva.nva_timensec[NFSTIME_CREATE]; 1269 VATTR_SET_SUPPORTED(vap, va_create_time); 1270 } 1271 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_TIME_ACCESS)) { 1272 vap->va_access_time.tv_sec = nva.nva_timesec[NFSTIME_ACCESS]; 1273 vap->va_access_time.tv_nsec = nva.nva_timensec[NFSTIME_ACCESS]; 1274 VATTR_SET_SUPPORTED(vap, va_access_time); 1275 } 1276 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_TIME_MODIFY)) { 1277 vap->va_modify_time.tv_sec = nva.nva_timesec[NFSTIME_MODIFY]; 1278 vap->va_modify_time.tv_nsec = nva.nva_timensec[NFSTIME_MODIFY]; 1279 VATTR_SET_SUPPORTED(vap, va_modify_time); 1280 } 1281 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_TIME_METADATA)) { 1282 vap->va_change_time.tv_sec = nva.nva_timesec[NFSTIME_CHANGE]; 1283 vap->va_change_time.tv_nsec = nva.nva_timensec[NFSTIME_CHANGE]; 1284 VATTR_SET_SUPPORTED(vap, va_change_time); 1285 } 1286 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_TIME_BACKUP)) { 1287 vap->va_backup_time.tv_sec = nva.nva_timesec[NFSTIME_BACKUP]; 1288 vap->va_backup_time.tv_nsec = nva.nva_timensec[NFSTIME_BACKUP]; 1289 VATTR_SET_SUPPORTED(vap, va_backup_time); 1290 } 1291 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_FILEID)) 1292 VATTR_RETURN(vap, va_fileid, nva.nva_fileid); 1293 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_TYPE)) 1294 VATTR_RETURN(vap, va_type, nva.nva_type); 1295 if (NFS_BITMAP_ISSET(nva.nva_bitmap, NFS_FATTR_CHANGE)) 1296 VATTR_RETURN(vap, va_filerev, nva.nva_change); 1297 1298 // other attrs we might support someday: 1299 // VATTR_RETURN(vap, va_encoding, ??? /* potentially unnormalized UTF-8? */); 1300 // struct kauth_acl *va_acl; /* access control list */ 1301 // guid_t va_uuuid; /* file owner UUID */ 1302 // guid_t va_guuid; /* file group UUID */ 1303 1304 return (error); 1305} 1306 1307int 1308nfs4_setattr_rpc( 1309 nfsnode_t np, 1310 struct vnode_attr *vap, 1311 vfs_context_t ctx, 1312 int alreadylocked) 1313{ 1314 struct nfsmount *nmp = NFSTONMP(np); 1315 int error = 0, lockerror = ENOENT, status, nfsvers, numops; 1316 u_int64_t xid; 1317 struct nfsm_chain nmreq, nmrep; 1318 uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen, stateid; 1319 1320 if (!nmp) 1321 return (ENXIO); 1322 nfsvers = nmp->nm_vers; 1323 1324 if (VATTR_IS_ACTIVE(vap, va_flags) && (vap->va_flags & ~(SF_ARCHIVED|UF_HIDDEN))) { 1325 /* we don't support setting unsupported flags (duh!) */ 1326 if (vap->va_active & ~VNODE_ATTR_va_flags) 1327 return (EINVAL); /* return EINVAL if other attributes also set */ 1328 else 1329 return (ENOTSUP); /* return ENOTSUP for chflags(2) */ 1330 } 1331 1332 nfsm_chain_null(&nmreq); 1333 nfsm_chain_null(&nmrep); 1334 1335 // PUTFH, SETATTR, GETATTR 1336 numops = 3; 1337 nfsm_chain_build_alloc_init(error, &nmreq, 40 * NFSX_UNSIGNED); 1338 nfsm_chain_add_compound_header(error, &nmreq, "setattr", numops); 1339 numops--; 1340 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1341 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize); 1342 numops--; 1343 nfsm_chain_add_32(error, &nmreq, NFS_OP_SETATTR); 1344 if (VATTR_IS_ACTIVE(vap, va_data_size)) 1345 stateid = 0xffffffff; /* XXX use the special stateid for now */ 1346 else 1347 stateid = 0; 1348 nfsm_chain_add_32(error, &nmreq, stateid); 1349 nfsm_chain_add_32(error, &nmreq, stateid); 1350 nfsm_chain_add_32(error, &nmreq, stateid); 1351 nfsm_chain_add_32(error, &nmreq, stateid); 1352 nfsm_chain_add_fattr4(error, &nmreq, vap, nmp); 1353 numops--; 1354 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1355 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 1356 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1357 nfsm_chain_build_done(error, &nmreq); 1358 nfsm_assert(error, (numops == 0), EPROTO); 1359 nfsmout_if(error); 1360 error = nfs_request(np, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 1361 1362 if (!alreadylocked && ((lockerror = nfs_lock(np, NFS_NODE_LOCK_EXCLUSIVE)))) 1363 error = lockerror; 1364 nfsm_chain_skip_tag(error, &nmrep); 1365 nfsm_chain_get_32(error, &nmrep, numops); 1366 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1367 nfsm_chain_op_check(error, &nmrep, NFS_OP_SETATTR); 1368 bmlen = NFS_ATTR_BITMAP_LEN; 1369 nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen); 1370 nfsmout_if(error); 1371 nfs_vattr_set_supported(bitmap, vap); 1372 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1373 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid); 1374 if (error) 1375 NATTRINVALIDATE(np); 1376nfsmout: 1377 if (!alreadylocked && !lockerror) 1378 nfs_unlock(np); 1379 nfsm_chain_cleanup(&nmreq); 1380 nfsm_chain_cleanup(&nmrep); 1381 return (error); 1382} 1383 1384int 1385nfs4_vnop_open(struct vnop_open_args *ap) 1386{ 1387 return nfs3_vnop_open(ap); 1388} 1389 1390int 1391nfs4_vnop_close(struct vnop_close_args *ap) 1392{ 1393 return nfs3_vnop_close(ap); 1394} 1395 1396int 1397nfs4_vnop_advlock(__unused struct vnop_advlock_args *ap) 1398{ 1399 return (ENOSYS); 1400} 1401 1402/* 1403 * Note: the NFSv4 CREATE RPC is for everything EXCEPT regular files. 1404 * Files are created using the NFSv4 OPEN RPC. So we must open the 1405 * file to create it and then close it immediately. 1406 */ 1407int 1408nfs4_vnop_create( 1409 struct vnop_create_args /* { 1410 struct vnodeop_desc *a_desc; 1411 vnode_t a_dvp; 1412 vnode_t *a_vpp; 1413 struct componentname *a_cnp; 1414 struct vnode_attr *a_vap; 1415 vfs_context_t a_context; 1416 } */ *ap) 1417{ 1418 vfs_context_t ctx = ap->a_context; 1419 struct componentname *cnp = ap->a_cnp; 1420 struct vnode_attr *vap = ap->a_vap; 1421 vnode_t dvp = ap->a_dvp; 1422 vnode_t *vpp = ap->a_vpp; 1423 struct nfsmount *nmp; 1424 struct nfs_vattr nvattr, dnvattr; 1425 int error = 0, create_error = EIO, lockerror = ENOENT, status; 1426 int nfsvers, numops; 1427 u_int64_t xid, savedxid = 0; 1428 nfsnode_t dnp = VTONFS(dvp); 1429 nfsnode_t np = NULL; 1430 vnode_t newvp = NULL; 1431 struct nfsm_chain nmreq, nmrep; 1432 uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen; 1433 uint32_t seqid, stateid[4], rflags, delegation, val; 1434 fhandle_t fh; 1435 struct nfsreq *req = NULL; 1436 struct nfs_dulookup dul; 1437 1438 static uint32_t nfs4_open_owner_hack = 0; 1439 1440 nmp = VTONMP(dvp); 1441 if (!nmp) 1442 return (ENXIO); 1443 nfsvers = nmp->nm_vers; 1444 1445 seqid = stateid[0] = stateid[1] = stateid[2] = stateid[3] = 0; 1446 rflags = 0; 1447 1448 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen); 1449 1450 nfsm_chain_null(&nmreq); 1451 nfsm_chain_null(&nmrep); 1452 1453 // PUTFH, SAVEFH, OPEN(CREATE), GETATTR(FH), RESTOREFH, GETATTR 1454 numops = 6; 1455 nfsm_chain_build_alloc_init(error, &nmreq, 53 * NFSX_UNSIGNED + cnp->cn_namelen); 1456 nfsm_chain_add_compound_header(error, &nmreq, "create", numops); 1457 numops--; 1458 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1459 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize); 1460 numops--; 1461 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH); 1462 numops--; 1463 nfsm_chain_add_32(error, &nmreq, NFS_OP_OPEN); 1464 nfsm_chain_add_32(error, &nmreq, seqid); 1465 seqid++; 1466 nfsm_chain_add_32(error, &nmreq, NFS_OPEN_SHARE_ACCESS_BOTH); 1467 nfsm_chain_add_32(error, &nmreq, NFS_OPEN_SHARE_DENY_NONE); 1468 nfsm_chain_add_64(error, &nmreq, nmp->nm_clientid); // open_owner4.clientid 1469 OSAddAtomic(1, (SInt32*)&nfs4_open_owner_hack); 1470 nfsm_chain_add_32(error, &nmreq, sizeof(nfs4_open_owner_hack)); 1471 nfsm_chain_add_opaque(error, &nmreq, &nfs4_open_owner_hack, sizeof(nfs4_open_owner_hack)); // open_owner4.owner 1472 // openflag4 1473 nfsm_chain_add_32(error, &nmreq, NFS_OPEN_CREATE); 1474 nfsm_chain_add_32(error, &nmreq, NFS_CREATE_UNCHECKED); // XXX exclusive/guarded 1475 nfsm_chain_add_fattr4(error, &nmreq, vap, nmp); 1476 // open_claim4 1477 nfsm_chain_add_32(error, &nmreq, NFS_CLAIM_NULL); 1478 nfsm_chain_add_string(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen); 1479 numops--; 1480 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1481 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap); 1482 NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE); 1483 nfsm_chain_add_bitmap_masked(error, &nmreq, bitmap, 1484 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1485 numops--; 1486 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH); 1487 numops--; 1488 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1489 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 1490 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1491 nfsm_chain_build_done(error, &nmreq); 1492 nfsm_assert(error, (numops == 0), EPROTO); 1493 nfsmout_if(error); 1494 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE))) 1495 error = lockerror; 1496 nfsmout_if(error); 1497 1498 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, 1499 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, &req); 1500 if (!error) { 1501 nfs_dulookup_start(&dul, dnp, ctx); 1502 error = nfs_request_async_finish(req, &nmrep, &xid, &status); 1503 } 1504 savedxid = xid; 1505 1506 nfsm_chain_skip_tag(error, &nmrep); 1507 nfsm_chain_get_32(error, &nmrep, numops); 1508 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1509 nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH); 1510 nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN); 1511 nfsm_chain_get_32(error, &nmrep, stateid[0]); 1512 nfsm_chain_get_32(error, &nmrep, stateid[1]); 1513 nfsm_chain_get_32(error, &nmrep, stateid[2]); 1514 nfsm_chain_get_32(error, &nmrep, stateid[3]); 1515 nfsm_chain_check_change_info(error, &nmrep, dnp); 1516 nfsm_chain_get_32(error, &nmrep, rflags); 1517 bmlen = NFS_ATTR_BITMAP_LEN; 1518 nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen); 1519 nfsm_chain_get_32(error, &nmrep, delegation); 1520 if (!error) 1521 switch (delegation) { 1522 case NFS_OPEN_DELEGATE_NONE: 1523 break; 1524 case NFS_OPEN_DELEGATE_READ: 1525 printf("nfs4_vnop_create: read delegation?\n"); 1526 nfsm_chain_adv(error, &nmrep, 5*NFSX_UNSIGNED); 1527 // ACE: 1528 nfsm_chain_adv(error, &nmrep, 3 * NFSX_UNSIGNED); 1529 nfsm_chain_get_32(error, &nmrep, val); /* string length */ 1530 nfsm_chain_adv(error, &nmrep, nfsm_rndup(val)); 1531 break; 1532 case NFS_OPEN_DELEGATE_WRITE: 1533 printf("nfs4_vnop_create: write delegation?\n"); 1534 nfsm_chain_adv(error, &nmrep, 5*NFSX_UNSIGNED); 1535 nfsm_chain_adv(error, &nmrep, 3*NFSX_UNSIGNED); 1536 // ACE: 1537 nfsm_chain_adv(error, &nmrep, 3 * NFSX_UNSIGNED); 1538 nfsm_chain_get_32(error, &nmrep, val); /* string length */ 1539 nfsm_chain_adv(error, &nmrep, nfsm_rndup(val)); 1540 break; 1541 default: 1542 error = EBADRPC; 1543 break; 1544 } 1545 /* At this point if we have no error, the object was created. */ 1546 /* if we don't get attributes, then we should lookitup. */ 1547 create_error = error; 1548 nfsmout_if(error); 1549 nfs_vattr_set_supported(bitmap, vap); 1550 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1551 nfsmout_if(error); 1552 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap); 1553 error = nfs4_parsefattr(&nmrep, NULL, &nvattr, &fh, NULL); 1554 nfsmout_if(error); 1555 if (!NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_FILEHANDLE)) { 1556 printf("nfs: open/create didn't return filehandle?\n"); 1557 error = EBADRPC; 1558 goto nfsmout; 1559 } 1560 /* directory attributes: if we don't get them, make sure to invalidate */ 1561 nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH); 1562 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1563 nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, NULL, &xid); 1564 if (error) 1565 NATTRINVALIDATE(dnp); 1566 1567 if (rflags & NFS_OPEN_RESULT_CONFIRM) { 1568 nfsm_chain_cleanup(&nmreq); 1569 nfsm_chain_cleanup(&nmrep); 1570 // PUTFH, OPEN_CONFIRM, GETATTR 1571 numops = 3; 1572 nfsm_chain_build_alloc_init(error, &nmreq, 23 * NFSX_UNSIGNED); 1573 nfsm_chain_add_compound_header(error, &nmreq, "create_confirm", numops); 1574 numops--; 1575 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1576 nfsm_chain_add_fh(error, &nmreq, nfsvers, fh.fh_data, fh.fh_len); 1577 numops--; 1578 nfsm_chain_add_32(error, &nmreq, NFS_OP_OPEN_CONFIRM); 1579 nfsm_chain_add_32(error, &nmreq, stateid[0]); 1580 nfsm_chain_add_32(error, &nmreq, stateid[1]); 1581 nfsm_chain_add_32(error, &nmreq, stateid[2]); 1582 nfsm_chain_add_32(error, &nmreq, stateid[3]); 1583 nfsm_chain_add_32(error, &nmreq, seqid); 1584 seqid++; 1585 numops--; 1586 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1587 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 1588 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1589 nfsm_chain_build_done(error, &nmreq); 1590 nfsm_assert(error, (numops == 0), EPROTO); 1591 nfsmout_if(error); 1592 error = nfs_request(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 1593 1594 nfsm_chain_skip_tag(error, &nmrep); 1595 nfsm_chain_get_32(error, &nmrep, numops); 1596 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1597 nfsm_chain_op_check(error, &nmrep, NFS_OP_OPEN_CONFIRM); 1598 nfsm_chain_get_32(error, &nmrep, stateid[0]); 1599 nfsm_chain_get_32(error, &nmrep, stateid[1]); 1600 nfsm_chain_get_32(error, &nmrep, stateid[2]); 1601 nfsm_chain_get_32(error, &nmrep, stateid[3]); 1602 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1603 nfsmout_if(error); 1604 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap); 1605 error = nfs4_parsefattr(&nmrep, NULL, &nvattr, NULL, NULL); 1606 nfsmout_if(error); 1607 savedxid = xid; 1608 } 1609 nfsmout_if(error); 1610 nfsm_chain_cleanup(&nmreq); 1611 nfsm_chain_cleanup(&nmrep); 1612 1613 // PUTFH, CLOSE 1614 numops = 2; 1615 nfsm_chain_build_alloc_init(error, &nmreq, 19 * NFSX_UNSIGNED); 1616 nfsm_chain_add_compound_header(error, &nmreq, "create_close", numops); 1617 numops--; 1618 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1619 nfsm_chain_add_fh(error, &nmreq, nfsvers, fh.fh_data, fh.fh_len); 1620 numops--; 1621 nfsm_chain_add_32(error, &nmreq, NFS_OP_CLOSE); 1622 nfsm_chain_add_32(error, &nmreq, seqid); 1623 seqid++; 1624 nfsm_chain_add_32(error, &nmreq, stateid[0]); 1625 nfsm_chain_add_32(error, &nmreq, stateid[1]); 1626 nfsm_chain_add_32(error, &nmreq, stateid[2]); 1627 nfsm_chain_add_32(error, &nmreq, stateid[3]); 1628 nfsm_chain_build_done(error, &nmreq); 1629 nfsm_assert(error, (numops == 0), EPROTO); 1630 nfsmout_if(error); 1631 error = nfs_request(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 1632 1633 nfsm_chain_skip_tag(error, &nmrep); 1634 nfsm_chain_get_32(error, &nmrep, numops); 1635 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1636 nfsm_chain_op_check(error, &nmrep, NFS_OP_CLOSE); 1637 nfsm_chain_get_32(error, &nmrep, stateid[0]); 1638 nfsm_chain_get_32(error, &nmrep, stateid[1]); 1639 nfsm_chain_get_32(error, &nmrep, stateid[2]); 1640 nfsm_chain_get_32(error, &nmrep, stateid[3]); 1641 if (error) 1642 printf("nfs4_vnop_create: close error %d\n", error); 1643 1644nfsmout: 1645 nfsm_chain_cleanup(&nmreq); 1646 nfsm_chain_cleanup(&nmrep); 1647 1648 if (!lockerror) { 1649 if (!create_error && (dnp->n_flag & NNEGNCENTRIES)) { 1650 dnp->n_flag &= ~NNEGNCENTRIES; 1651 cache_purge_negatives(dvp); 1652 } 1653 dnp->n_flag |= NMODIFIED; 1654 if (!nfs_getattr(dnp, &dnvattr, ctx, 1)) { 1655 if (NFS_CHANGED_NC(nfsvers, dnp, &dnvattr)) { 1656 dnp->n_flag &= ~NNEGNCENTRIES; 1657 cache_purge(dvp); 1658 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnvattr); 1659 } 1660 } 1661 } 1662 1663 if (!error && fh.fh_len) { 1664 /* create the vnode with the filehandle and attributes */ 1665 xid = savedxid; 1666 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, NG_MAKEENTRY, &np); 1667 if (!error) 1668 newvp = NFSTOV(np); 1669 } 1670 1671 nfs_dulookup_finish(&dul, dnp, ctx); 1672 1673 /* 1674 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 1675 * if we can succeed in looking up the object. 1676 */ 1677 if ((create_error == EEXIST) || (!create_error && !newvp)) { 1678 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np); 1679 if (!error) { 1680 newvp = NFSTOV(np); 1681 if (vnode_vtype(newvp) != VLNK) 1682 error = EEXIST; 1683 } 1684 } 1685 if (!lockerror) 1686 nfs_unlock(dnp); 1687 if (error) { 1688 if (newvp) { 1689 nfs_unlock(np); 1690 vnode_put(newvp); 1691 } 1692 } else { 1693 nfs_unlock(np); 1694 *vpp = newvp; 1695 } 1696 return (error); 1697} 1698 1699/* 1700 * Note: the NFSv4 CREATE RPC is for everything EXCEPT regular files. 1701 */ 1702static int 1703nfs4_create_rpc( 1704 vfs_context_t ctx, 1705 nfsnode_t dnp, 1706 struct componentname *cnp, 1707 struct vnode_attr *vap, 1708 int type, 1709 char *link, 1710 nfsnode_t *npp) 1711{ 1712 struct nfsmount *nmp; 1713 struct nfs_vattr nvattr, dnvattr; 1714 int error = 0, create_error = EIO, lockerror = ENOENT, status; 1715 int nfsvers, numops; 1716 u_int64_t xid, savedxid = 0; 1717 nfsnode_t np = NULL; 1718 vnode_t newvp = NULL; 1719 struct nfsm_chain nmreq, nmrep; 1720 uint32_t bitmap[NFS_ATTR_BITMAP_LEN], bmlen; 1721 const char *tag; 1722 nfs_specdata sd; 1723 fhandle_t fh; 1724 struct nfsreq *req = NULL; 1725 struct nfs_dulookup dul; 1726 1727 nmp = NFSTONMP(dnp); 1728 if (!nmp) 1729 return (ENXIO); 1730 nfsvers = nmp->nm_vers; 1731 1732 sd.specdata1 = sd.specdata2 = 0; 1733 1734 switch (type) { 1735 case NFLNK: 1736 tag = "symlink"; 1737 break; 1738 case NFBLK: 1739 case NFCHR: 1740 tag = "mknod"; 1741 if (!VATTR_IS_ACTIVE(vap, va_rdev)) 1742 return (EINVAL); 1743 sd.specdata1 = major(vap->va_rdev); 1744 sd.specdata2 = minor(vap->va_rdev); 1745 break; 1746 case NFSOCK: 1747 case NFFIFO: 1748 tag = "mknod"; 1749 break; 1750 case NFDIR: 1751 tag = "mkdir"; 1752 break; 1753 default: 1754 return (EINVAL); 1755 } 1756 1757 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen); 1758 1759 nfsm_chain_null(&nmreq); 1760 nfsm_chain_null(&nmrep); 1761 1762 // PUTFH, SAVEFH, CREATE, GETATTR(FH), RESTOREFH, GETATTR 1763 numops = 6; 1764 nfsm_chain_build_alloc_init(error, &nmreq, 66 * NFSX_UNSIGNED); 1765 nfsm_chain_add_compound_header(error, &nmreq, tag, numops); 1766 numops--; 1767 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 1768 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize); 1769 numops--; 1770 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH); 1771 numops--; 1772 nfsm_chain_add_32(error, &nmreq, NFS_OP_CREATE); 1773 nfsm_chain_add_32(error, &nmreq, type); 1774 if (type == NFLNK) { 1775 nfsm_chain_add_string(error, &nmreq, link, strlen(link)); 1776 } else if ((type == NFBLK) || (type == NFCHR)) { 1777 nfsm_chain_add_32(error, &nmreq, sd.specdata1); 1778 nfsm_chain_add_32(error, &nmreq, sd.specdata2); 1779 } 1780 nfsm_chain_add_string(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen); 1781 nfsm_chain_add_fattr4(error, &nmreq, vap, nmp); 1782 numops--; 1783 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1784 NFS_COPY_ATTRIBUTES(nfs_getattr_bitmap, bitmap); 1785 NFS_BITMAP_SET(bitmap, NFS_FATTR_FILEHANDLE); 1786 nfsm_chain_add_bitmap_masked(error, &nmreq, bitmap, 1787 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1788 numops--; 1789 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH); 1790 numops--; 1791 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 1792 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 1793 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 1794 nfsm_chain_build_done(error, &nmreq); 1795 nfsm_assert(error, (numops == 0), EPROTO); 1796 nfsmout_if(error); 1797 if ((lockerror = nfs_lock(dnp, NFS_NODE_LOCK_EXCLUSIVE))) 1798 error = lockerror; 1799 nfsmout_if(error); 1800 1801 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC4_COMPOUND, 1802 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, &req); 1803 if (!error) { 1804 nfs_dulookup_start(&dul, dnp, ctx); 1805 error = nfs_request_async_finish(req, &nmrep, &xid, &status); 1806 } 1807 1808 nfsm_chain_skip_tag(error, &nmrep); 1809 nfsm_chain_get_32(error, &nmrep, numops); 1810 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 1811 nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH); 1812 nfsmout_if(error); 1813 nfsm_chain_op_check(error, &nmrep, NFS_OP_CREATE); 1814 nfsm_chain_check_change_info(error, &nmrep, dnp); 1815 bmlen = NFS_ATTR_BITMAP_LEN; 1816 nfsm_chain_get_bitmap(error, &nmrep, bitmap, bmlen); 1817 /* At this point if we have no error, the object was created. */ 1818 /* if we don't get attributes, then we should lookitup. */ 1819 create_error = error; 1820 nfsmout_if(error); 1821 nfs_vattr_set_supported(bitmap, vap); 1822 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1823 nfsmout_if(error); 1824 NFS_CLEAR_ATTRIBUTES(nvattr.nva_bitmap); 1825 error = nfs4_parsefattr(&nmrep, NULL, &nvattr, &fh, NULL); 1826 nfsmout_if(error); 1827 if (!NFS_BITMAP_ISSET(nvattr.nva_bitmap, NFS_FATTR_FILEHANDLE)) { 1828 printf("nfs: create/%s didn't return filehandle?\n", tag); 1829 error = EBADRPC; 1830 goto nfsmout; 1831 } 1832 /* directory attributes: if we don't get them, make sure to invalidate */ 1833 nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH); 1834 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 1835 savedxid = xid; 1836 nfsm_chain_loadattr(error, &nmrep, dnp, nfsvers, NULL, &xid); 1837 if (error) 1838 NATTRINVALIDATE(dnp); 1839 1840nfsmout: 1841 nfsm_chain_cleanup(&nmreq); 1842 nfsm_chain_cleanup(&nmrep); 1843 1844 if (!lockerror) { 1845 if (!create_error && (dnp->n_flag & NNEGNCENTRIES)) { 1846 dnp->n_flag &= ~NNEGNCENTRIES; 1847 cache_purge_negatives(NFSTOV(dnp)); 1848 } 1849 dnp->n_flag |= NMODIFIED; 1850 if (!nfs_getattr(dnp, &dnvattr, ctx, 1)) { 1851 if (NFS_CHANGED_NC(nfsvers, dnp, &dnvattr)) { 1852 dnp->n_flag &= ~NNEGNCENTRIES; 1853 cache_purge(NFSTOV(dnp)); 1854 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnvattr); 1855 } 1856 } 1857 } 1858 1859 if (!error && fh.fh_len) { 1860 /* create the vnode with the filehandle and attributes */ 1861 xid = savedxid; 1862 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, NG_MAKEENTRY, &np); 1863 if (!error) 1864 newvp = NFSTOV(np); 1865 } 1866 1867 nfs_dulookup_finish(&dul, dnp, ctx); 1868 1869 /* 1870 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 1871 * if we can succeed in looking up the object. 1872 */ 1873 if ((create_error == EEXIST) || (!create_error && !newvp)) { 1874 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np); 1875 if (!error) { 1876 newvp = NFSTOV(np); 1877 if (vnode_vtype(newvp) != VLNK) 1878 error = EEXIST; 1879 } 1880 } 1881 if (!lockerror) 1882 nfs_unlock(dnp); 1883 if (error) { 1884 if (newvp) { 1885 nfs_unlock(np); 1886 vnode_put(newvp); 1887 } 1888 } else { 1889 nfs_unlock(np); 1890 *npp = np; 1891 } 1892 return (error); 1893} 1894 1895int 1896nfs4_vnop_mknod( 1897 struct vnop_mknod_args /* { 1898 struct vnodeop_desc *a_desc; 1899 vnode_t a_dvp; 1900 vnode_t *a_vpp; 1901 struct componentname *a_cnp; 1902 struct vnode_attr *a_vap; 1903 vfs_context_t a_context; 1904 } */ *ap) 1905{ 1906 nfsnode_t np = NULL; 1907 struct nfsmount *nmp; 1908 int error; 1909 1910 nmp = VTONMP(ap->a_dvp); 1911 if (!nmp) 1912 return (ENXIO); 1913 1914 if (!VATTR_IS_ACTIVE(ap->a_vap, va_type)) 1915 return (EINVAL); 1916 switch (ap->a_vap->va_type) { 1917 case VBLK: 1918 case VCHR: 1919 case VFIFO: 1920 case VSOCK: 1921 break; 1922 default: 1923 return (ENOTSUP); 1924 } 1925 1926 error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap, 1927 vtonfs_type(ap->a_vap->va_type, nmp->nm_vers), NULL, &np); 1928 if (!error) 1929 *ap->a_vpp = NFSTOV(np); 1930 return (error); 1931} 1932 1933int 1934nfs4_vnop_mkdir( 1935 struct vnop_mkdir_args /* { 1936 struct vnodeop_desc *a_desc; 1937 vnode_t a_dvp; 1938 vnode_t *a_vpp; 1939 struct componentname *a_cnp; 1940 struct vnode_attr *a_vap; 1941 vfs_context_t a_context; 1942 } */ *ap) 1943{ 1944 nfsnode_t np = NULL; 1945 int error; 1946 1947 error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap, 1948 NFDIR, NULL, &np); 1949 if (!error) 1950 *ap->a_vpp = NFSTOV(np); 1951 return (error); 1952} 1953 1954int 1955nfs4_vnop_symlink( 1956 struct vnop_symlink_args /* { 1957 struct vnodeop_desc *a_desc; 1958 vnode_t a_dvp; 1959 vnode_t *a_vpp; 1960 struct componentname *a_cnp; 1961 struct vnode_attr *a_vap; 1962 char *a_target; 1963 vfs_context_t a_context; 1964 } */ *ap) 1965{ 1966 nfsnode_t np = NULL; 1967 int error; 1968 1969 error = nfs4_create_rpc(ap->a_context, VTONFS(ap->a_dvp), ap->a_cnp, ap->a_vap, 1970 NFLNK, ap->a_target, &np); 1971 if (!error) 1972 *ap->a_vpp = NFSTOV(np); 1973 return (error); 1974} 1975 1976int 1977nfs4_vnop_link( 1978 struct vnop_link_args /* { 1979 struct vnodeop_desc *a_desc; 1980 vnode_t a_vp; 1981 vnode_t a_tdvp; 1982 struct componentname *a_cnp; 1983 vfs_context_t a_context; 1984 } */ *ap) 1985{ 1986 vfs_context_t ctx = ap->a_context; 1987 vnode_t vp = ap->a_vp; 1988 vnode_t tdvp = ap->a_tdvp; 1989 struct componentname *cnp = ap->a_cnp; 1990 int error = 0, status; 1991 struct nfsmount *nmp; 1992 nfsnode_t np = VTONFS(vp); 1993 nfsnode_t tdnp = VTONFS(tdvp); 1994 int nfsvers, numops; 1995 u_int64_t xid, savedxid; 1996 struct nfsm_chain nmreq, nmrep; 1997 1998 if (vnode_mount(vp) != vnode_mount(tdvp)) 1999 return (EXDEV); 2000 2001 nmp = VTONMP(vp); 2002 if (!nmp) 2003 return (ENXIO); 2004 nfsvers = nmp->nm_vers; 2005 2006 /* 2007 * Push all writes to the server, so that the attribute cache 2008 * doesn't get "out of sync" with the server. 2009 * XXX There should be a better way! 2010 */ 2011 nfs_flush(np, MNT_WAIT, vfs_context_thread(ctx), V_IGNORE_WRITEERR); 2012 2013 error = nfs_lock2(tdnp, np, NFS_NODE_LOCK_EXCLUSIVE); 2014 if (error) 2015 return (error); 2016 2017 nfsm_chain_null(&nmreq); 2018 nfsm_chain_null(&nmrep); 2019 2020 // PUTFH(SOURCE), SAVEFH, PUTFH(DIR), LINK, GETATTR(DIR), RESTOREFH, GETATTR 2021 numops = 7; 2022 nfsm_chain_build_alloc_init(error, &nmreq, 29 * NFSX_UNSIGNED + cnp->cn_namelen); 2023 nfsm_chain_add_compound_header(error, &nmreq, "link", numops); 2024 numops--; 2025 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 2026 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize); 2027 numops--; 2028 nfsm_chain_add_32(error, &nmreq, NFS_OP_SAVEFH); 2029 numops--; 2030 nfsm_chain_add_32(error, &nmreq, NFS_OP_PUTFH); 2031 nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize); 2032 numops--; 2033 nfsm_chain_add_32(error, &nmreq, NFS_OP_LINK); 2034 nfsm_chain_add_string(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen); 2035 numops--; 2036 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 2037 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 2038 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 2039 numops--; 2040 nfsm_chain_add_32(error, &nmreq, NFS_OP_RESTOREFH); 2041 numops--; 2042 nfsm_chain_add_32(error, &nmreq, NFS_OP_GETATTR); 2043 nfsm_chain_add_bitmap_masked(error, &nmreq, nfs_getattr_bitmap, 2044 NFS_ATTR_BITMAP_LEN, nmp->nm_fsattr.nfsa_supp_attr); 2045 nfsm_chain_build_done(error, &nmreq); 2046 nfsm_assert(error, (numops == 0), EPROTO); 2047 nfsmout_if(error); 2048 error = nfs_request(tdnp, NULL, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); 2049 2050 nfsm_chain_skip_tag(error, &nmrep); 2051 nfsm_chain_get_32(error, &nmrep, numops); 2052 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 2053 nfsm_chain_op_check(error, &nmrep, NFS_OP_SAVEFH); 2054 nfsm_chain_op_check(error, &nmrep, NFS_OP_PUTFH); 2055 nfsm_chain_op_check(error, &nmrep, NFS_OP_LINK); 2056 nfsm_chain_check_change_info(error, &nmrep, tdnp); 2057 /* directory attributes: if we don't get them, make sure to invalidate */ 2058 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 2059 savedxid = xid; 2060 nfsm_chain_loadattr(error, &nmrep, tdnp, nfsvers, NULL, &xid); 2061 if (error) 2062 NATTRINVALIDATE(tdnp); 2063 /* link attributes: if we don't get them, make sure to invalidate */ 2064 nfsm_chain_op_check(error, &nmrep, NFS_OP_RESTOREFH); 2065 nfsm_chain_op_check(error, &nmrep, NFS_OP_GETATTR); 2066 xid = savedxid; 2067 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, NULL, &xid); 2068 if (error) 2069 NATTRINVALIDATE(np); 2070nfsmout: 2071 nfsm_chain_cleanup(&nmreq); 2072 nfsm_chain_cleanup(&nmrep); 2073 tdnp->n_flag |= NMODIFIED; 2074 /* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. */ 2075 if (error == EEXIST) 2076 error = 0; 2077 if (!error && (tdnp->n_flag & NNEGNCENTRIES)) { 2078 tdnp->n_flag &= ~NNEGNCENTRIES; 2079 cache_purge_negatives(tdvp); 2080 } 2081 nfs_unlock2(tdnp, np); 2082 return (error); 2083} 2084 2085int 2086nfs4_vnop_rmdir( 2087 struct vnop_rmdir_args /* { 2088 struct vnodeop_desc *a_desc; 2089 vnode_t a_dvp; 2090 vnode_t a_vp; 2091 struct componentname *a_cnp; 2092 vfs_context_t a_context; 2093 } */ *ap) 2094{ 2095 vfs_context_t ctx = ap->a_context; 2096 vnode_t vp = ap->a_vp; 2097 vnode_t dvp = ap->a_dvp; 2098 struct componentname *cnp = ap->a_cnp; 2099 int error = 0; 2100 nfsnode_t np = VTONFS(vp); 2101 nfsnode_t dnp = VTONFS(dvp); 2102 struct nfs_vattr dnvattr; 2103 struct nfs_dulookup dul; 2104 2105 if (vnode_vtype(vp) != VDIR) 2106 return (EINVAL); 2107 2108 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen); 2109 2110 if ((error = nfs_lock2(dnp, np, NFS_NODE_LOCK_EXCLUSIVE))) 2111 return (error); 2112 2113 nfs_dulookup_start(&dul, dnp, ctx); 2114 2115 error = nfs4_remove_rpc(dnp, cnp->cn_nameptr, cnp->cn_namelen, 2116 vfs_context_thread(ctx), vfs_context_ucred(ctx)); 2117 2118 cache_purge(vp); 2119 if (!nfs_getattr(dnp, &dnvattr, ctx, 1)) { 2120 if (NFS_CHANGED_NC(NFS_VER4, dnp, &dnvattr)) { 2121 dnp->n_flag &= ~NNEGNCENTRIES; 2122 cache_purge(dvp); 2123 NFS_CHANGED_UPDATE_NC(NFS_VER4, dnp, &dnvattr); 2124 } 2125 } 2126 2127 nfs_dulookup_finish(&dul, dnp, ctx); 2128 nfs_unlock2(dnp, np); 2129 2130 /* 2131 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2132 */ 2133 if (error == ENOENT) 2134 error = 0; 2135 if (!error) { 2136 /* 2137 * remove nfsnode from hash now so we can't accidentally find it 2138 * again if another object gets created with the same filehandle 2139 * before this vnode gets reclaimed 2140 */ 2141 lck_mtx_lock(nfs_node_hash_mutex); 2142 if (np->n_hflag & NHHASHED) { 2143 LIST_REMOVE(np, n_hash); 2144 np->n_hflag &= ~NHHASHED; 2145 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e); 2146 } 2147 lck_mtx_unlock(nfs_node_hash_mutex); 2148 } 2149 return (error); 2150} 2151 2152