1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2018 Nexenta Systems, Inc. 29 * Copyright 2020 RackTop Systems, Inc. 30 */ 31 32 #include <sys/systm.h> 33 #include <sys/cmn_err.h> 34 #include <nfs/nfs.h> 35 #include <nfs/export.h> 36 #include <nfs/nfs4.h> 37 #include <sys/ddi.h> 38 #include <sys/door.h> 39 #include <sys/sdt.h> 40 #include <nfs/nfssys.h> 41 42 void rfs4_init_compound_state(struct compound_state *); 43 44 bitmap4 rfs4_supported_attrs; 45 int MSG_PRT_DEBUG = FALSE; 46 47 /* If building with DEBUG enabled, enable mandattr tunable by default */ 48 #ifdef DEBUG 49 #ifndef RFS4_SUPPORT_MANDATTR_ONLY 50 #define RFS4_SUPPORT_MANDATTR_ONLY 51 #endif 52 #endif 53 54 /* 55 * If building with mandattr only code, disable it by default. 56 * To enable, set rfs4_mandattr_only in /etc/system and reboot. 57 * When building without mandattr ifdef, the compiler should 58 * optimize away the the comparisons because RFS4_MANDATTR_ONLY 59 * is defined to be 0. 60 */ 61 #ifdef RFS4_SUPPORT_MANDATTR_ONLY 62 #define NFS4_LAST_MANDATTR FATTR4_RDATTR_ERROR 63 #define RFS4_MANDATTR_ONLY rfs4_mandattr_only 64 int rfs4_mandattr_only = 0; 65 #else 66 #define RFS4_MANDATTR_ONLY 0 67 #endif 68 69 70 static void rfs4_ntov_init(void); 71 static int rfs4_fattr4_supported_attrs(); 72 static int rfs4_fattr4_type(); 73 static int rfs4_fattr4_fh_expire_type(); 74 static int rfs4_fattr4_change(); 75 static int rfs4_fattr4_size(); 76 static int rfs4_fattr4_link_support(); 77 static int rfs4_fattr4_symlink_support(); 78 static int rfs4_fattr4_named_attr(); 79 static int rfs4_fattr4_fsid(); 80 static int rfs4_fattr4_unique_handles(); 81 static int rfs4_fattr4_lease_time(); 82 static int rfs4_fattr4_rdattr_error(); 83 static int rfs4_fattr4_acl(); 84 static int rfs4_fattr4_aclsupport(); 85 static int rfs4_fattr4_archive(); 86 static int rfs4_fattr4_cansettime(); 87 static int rfs4_fattr4_case_insensitive(); 88 static int rfs4_fattr4_case_preserving(); 89 static int rfs4_fattr4_chown_restricted(); 90 static int rfs4_fattr4_filehandle(); 91 static int rfs4_fattr4_fileid(); 92 static int rfs4_fattr4_files_avail(); 93 static int rfs4_fattr4_files_free(); 94 static int rfs4_fattr4_files_total(); 95 static int rfs4_fattr4_fs_locations(); 96 static int rfs4_fattr4_hidden(); 97 static int rfs4_fattr4_homogeneous(); 98 static int rfs4_fattr4_maxfilesize(); 99 static int rfs4_fattr4_maxlink(); 100 static int rfs4_fattr4_maxname(); 101 static int rfs4_fattr4_maxread(); 102 static int rfs4_fattr4_maxwrite(); 103 static int rfs4_fattr4_mimetype(); 104 static int rfs4_fattr4_mode(); 105 static int rfs4_fattr4_no_trunc(); 106 static int rfs4_fattr4_numlinks(); 107 static int rfs4_fattr4_owner(); 108 static int rfs4_fattr4_owner_group(); 109 static int rfs4_fattr4_quota_avail_hard(); 110 static int rfs4_fattr4_quota_avail_soft(); 111 static int rfs4_fattr4_quota_used(); 112 static int rfs4_fattr4_rawdev(); 113 static int rfs4_fattr4_space_avail(); 114 static int rfs4_fattr4_space_free(); 115 static int rfs4_fattr4_space_total(); 116 static int rfs4_fattr4_space_used(); 117 static int rfs4_fattr4_system(); 118 static int rfs4_fattr4_time_access(); 119 static int rfs4_fattr4_time_access_set(); 120 static int rfs4_fattr4_time_backup(); 121 static int rfs4_fattr4_time_create(); 122 static int rfs4_fattr4_time_delta(); 123 static int rfs4_fattr4_time_metadata(); 124 static int rfs4_fattr4_time_modify(); 125 static int rfs4_fattr4_time_modify_set(); 126 127 /* 128 * Initialize the supported attributes 129 */ 130 bitmap4 supported_attrs[3]; 131 132 static void 133 init_supported_attrs(void) 134 { 135 supported_attrs[0] = supported_attrs[1] = supported_attrs[2] = 136 rfs4_supported_attrs; 137 138 /* restrict to nfsv4.0 */ 139 supported_attrs[0] &= ~(FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL | 140 FATTR4_SEC_LABEL_MASK_LOCAL); 141 142 /* restrict to nfsv4.1 */ 143 supported_attrs[1] &= ~FATTR4_SEC_LABEL_MASK_LOCAL; 144 } 145 146 void 147 rfs4_attr_init(void) 148 { 149 int i; 150 struct nfs4_svgetit_arg sarg; 151 struct compound_state cs; 152 struct statvfs64 sb; 153 154 rfs4_init_compound_state(&cs); 155 /* 156 * This is global state checking, called once. We might be in 157 * non-global-zone context here (say a modload happens from a zone 158 * process) so in this case, we want the global-zone root vnode. 159 */ 160 cs.vp = rootvp; 161 cs.fh.nfs_fh4_val = NULL; 162 cs.cr = kcred; 163 cs.minorversion = NFS_PROT_V4_MINORVERSION(NFS_VERS_4_2); 164 165 /* 166 * Get all the supported attributes 167 */ 168 sarg.op = NFS4ATTR_SUPPORTED; 169 sarg.cs = &cs; 170 sarg.vap->va_mask = AT_ALL; 171 sarg.sbp = &sb; 172 sarg.flag = 0; 173 sarg.rdattr_error = NFS4_OK; 174 sarg.rdattr_error_req = FALSE; 175 sarg.is_referral = B_FALSE; 176 177 rfs4_ntov_init(); 178 179 rfs4_supported_attrs = 0; 180 for (i = 0; i < NFS4_MAXNUM_ATTRS; i++) { 181 #ifdef RFS4_SUPPORT_MANDATTR_ONLY 182 if (rfs4_mandattr_only == TRUE && i > NFS4_LAST_MANDATTR) 183 continue; 184 #endif 185 if ((*nfs4_ntov_map[i].sv_getit)(NFS4ATTR_SUPPORTED, 186 &sarg, NULL) == 0) { 187 rfs4_supported_attrs |= nfs4_ntov_map[i].fbit; 188 } 189 } 190 191 init_supported_attrs(); 192 } 193 194 /* 195 * The following rfs4_fattr4_* functions convert between the fattr4 196 * arguments/attributes and the system (e.g. vattr) values. The following 197 * commands are currently in use: 198 * 199 * NFS4ATTR_SUPPORTED: checks if the attribute in question is supported: 200 * sarg.op = SUPPORTED - all supported attrs 201 * sarg.op = GETIT - only supported readable attrs 202 * sarg.op = SETIT - only supported writable attrs 203 * 204 * NFS4ATTR_GETIT: getattr type conversion - convert system values 205 * (e.g. vattr struct) to fattr4 type values to be returned to the 206 * user - usually in response to nfsv4 getattr request. 207 * 208 * NFS4ATTR_SETIT: convert fattr4 type values to system values to use by 209 * setattr. Allows only read/write and write attributes, 210 * even if not supported by the filesystem. Note that ufs only allows setattr 211 * of owner/group, mode, size, atime/mtime. 212 * 213 * NFS4ATTR_VERIT: convert fattr4 type values to system values to use by 214 * verify/nverify. Implemented to allow 215 * almost everything that can be returned by getattr into known structs 216 * (like vfsstat64 or vattr_t), that is, both read only and read/write attrs. 217 * The function will return -1 if it found that the arguments don't match. 218 * This applies to system-wide values that don't require a VOP_GETATTR 219 * or other further checks to verify. It will return no error if they 220 * either match or were retrieved successfully for later checking. 221 * 222 * NFS4ATTR_FREEIT: free up any space allocated by either of the above. 223 * The sargp->op should be either NFS4ATTR_GETIT or NFS4ATTR_SETIT 224 * to indicate which op was used to allocate the space. 225 * 226 * XXX Note: these functions are currently used by the server only. A 227 * XXX different method of conversion is used on the client side. 228 * XXX Eventually combining the two (possibly by adding NFS4ATTR_CLNT_GETIT 229 * XXX and SETIT) may be a cleaner approach. 230 */ 231 232 /* 233 * Mandatory attributes 234 */ 235 236 /* ARGSUSED */ 237 static int 238 rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 239 union nfs4_attr_u *na) 240 { 241 int error = 0; 242 bitmap4 supported = supported_attrs[sarg->cs->minorversion]; 243 244 switch (cmd) { 245 case NFS4ATTR_SUPPORTED: 246 if (sarg->op == NFS4ATTR_SETIT) 247 error = EINVAL; 248 break; /* this attr is supported */ 249 case NFS4ATTR_GETIT: 250 na->supported_attrs = supported; 251 break; 252 case NFS4ATTR_SETIT: 253 /* 254 * read-only attr 255 */ 256 error = EINVAL; 257 break; 258 case NFS4ATTR_VERIT: 259 /* 260 * Compare the input bitmap to the server's bitmap 261 */ 262 if (na->supported_attrs != supported) { 263 error = -1; /* no match */ 264 } 265 break; 266 case NFS4ATTR_FREEIT: 267 break; 268 } 269 return (error); 270 } 271 272 /* 273 * Translate vnode vtype to nfsv4_ftype. 274 */ 275 static nfs_ftype4 vt_to_nf4[] = { 276 0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0 277 }; 278 279 /* ARGSUSED */ 280 static int 281 rfs4_fattr4_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 282 union nfs4_attr_u *na) 283 { 284 int error = 0; 285 286 switch (cmd) { 287 case NFS4ATTR_SUPPORTED: 288 if (sarg->op == NFS4ATTR_SETIT) 289 error = EINVAL; 290 break; /* this attr is supported */ 291 case NFS4ATTR_GETIT: 292 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_TYPE)) { 293 error = -1; /* may be okay if rdattr_error */ 294 break; 295 } 296 ASSERT(sarg->vap->va_mask & AT_TYPE); 297 298 /* 299 * if xattr flag not set, use v4_to_nf4 mapping; 300 * otherwise verify xattr flag is in sync with va_type 301 * and set xattr types. 302 */ 303 if (! (sarg->xattr & (FH4_NAMEDATTR | FH4_ATTRDIR))) 304 na->type = vt_to_nf4[sarg->vap->va_type]; 305 else { 306 /* 307 * FH4 flag was set. Dir type maps to attrdir, 308 * and all other types map to namedattr. 309 */ 310 if (sarg->vap->va_type == VDIR) 311 na->type = NF4ATTRDIR; 312 else 313 na->type = NF4NAMEDATTR; 314 } 315 break; 316 case NFS4ATTR_SETIT: 317 /* 318 * read-only attr 319 */ 320 error = EINVAL; 321 break; 322 case NFS4ATTR_VERIT: 323 /* 324 * Compare the input type to the object type on server 325 */ 326 ASSERT(sarg->vap->va_mask & AT_TYPE); 327 if (sarg->vap->va_type != nf4_to_vt[na->type]) 328 error = -1; /* no match */ 329 break; 330 case NFS4ATTR_FREEIT: 331 break; 332 } 333 return (error); 334 } 335 336 /* ARGSUSED */ 337 static int 338 fattr4_get_fh_expire_type(struct exportinfo *exi, uint32_t *fh_expire_typep) 339 { 340 #ifdef VOLATILE_FH_TEST 341 int ex_flags; 342 343 if (exi == NULL) 344 return (ESTALE); 345 ex_flags = exi->exi_export.ex_flags; 346 if ((ex_flags & (EX_VOLFH | EX_VOLRNM | EX_VOLMIG | EX_NOEXPOPEN)) 347 == 0) { 348 *fh_expire_typep = FH4_PERSISTENT; 349 return (0); 350 } 351 *fh_expire_typep = 0; 352 353 if (ex_flags & EX_NOEXPOPEN) { 354 /* file handles should not expire with open - not used */ 355 *fh_expire_typep = FH4_NOEXPIRE_WITH_OPEN; 356 } 357 if (ex_flags & EX_VOLFH) { 358 /* 359 * file handles may expire any time - on share here. 360 * If volatile any, no need to check other flags. 361 */ 362 *fh_expire_typep |= FH4_VOLATILE_ANY; 363 return (0); 364 } 365 if (ex_flags & EX_VOLRNM) { 366 /* file handles may expire on rename */ 367 *fh_expire_typep |= FH4_VOL_RENAME; 368 } 369 if (ex_flags & EX_VOLMIG) { 370 /* file handles may expire on migration - not used */ 371 *fh_expire_typep |= FH4_VOL_MIGRATION; 372 } 373 #else /* not VOLATILE_FH_TEST */ 374 *fh_expire_typep = FH4_PERSISTENT; 375 #endif /* VOLATILE_FH_TEST */ 376 377 return (0); 378 } 379 380 /* 381 * At this point the only volatile filehandles we allow (for test purposes 382 * only) are either fh's that expire when the filesystem is shared (reshared), 383 * fh's that expire on a rename and persistent ones. 384 */ 385 /* ARGSUSED */ 386 static int 387 rfs4_fattr4_fh_expire_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 388 union nfs4_attr_u *na) 389 { 390 uint32_t fh_expire_type; 391 int error = 0; 392 393 switch (cmd) { 394 case NFS4ATTR_SUPPORTED: 395 if (sarg->op == NFS4ATTR_SETIT) 396 error = EINVAL; 397 break; /* this attr is supported */ 398 case NFS4ATTR_GETIT: 399 error = fattr4_get_fh_expire_type(sarg->cs->exi, 400 &na->fh_expire_type); 401 break; 402 case NFS4ATTR_SETIT: 403 /* 404 * read-only attr 405 */ 406 error = EINVAL; 407 break; 408 case NFS4ATTR_VERIT: 409 error = fattr4_get_fh_expire_type(sarg->cs->exi, 410 &fh_expire_type); 411 if (!error && (na->fh_expire_type != fh_expire_type)) 412 error = -1; /* no match */ 413 break; 414 case NFS4ATTR_FREEIT: 415 break; 416 } 417 return (error); 418 } 419 420 static int 421 fattr4_get_change(struct nfs4_svgetit_arg *sarg, fattr4_change *changep) 422 { 423 vattr_t vap2[1], *vap = sarg->vap; 424 struct compound_state *cs = sarg->cs; 425 vnode_t *vp = cs->vp; 426 nfsstat4 status; 427 timespec_t vis_change; 428 429 if ((vap->va_mask & AT_CTIME) == 0) { 430 if (sarg->rdattr_error && (vp == NULL)) { 431 return (-1); /* may be okay if rdattr_error */ 432 } 433 ASSERT(vp != NULL); 434 vap = vap2; 435 vap->va_mask = AT_CTIME; 436 status = rfs4_vop_getattr(vp, vap, 0, cs->cr); 437 if (status != NFS4_OK) 438 return (geterrno4(status)); 439 } 440 NFS4_SET_FATTR4_CHANGE(*changep, vap->va_ctime); 441 442 if (nfs_visible_change(cs->exi, vp, &vis_change)) { 443 fattr4_change visch; 444 NFS4_SET_FATTR4_CHANGE(visch, vis_change); 445 if (visch > *changep) 446 *changep = visch; 447 } 448 449 return (0); 450 } 451 452 /* ARGSUSED */ 453 static int 454 rfs4_fattr4_change(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 455 union nfs4_attr_u *na) 456 { 457 int error = 0; 458 fattr4_change change; 459 uint_t mask; 460 vattr_t *vap = sarg->vap; 461 462 switch (cmd) { 463 case NFS4ATTR_SUPPORTED: 464 if (sarg->op == NFS4ATTR_SETIT) 465 error = EINVAL; 466 break; /* this attr is supported */ 467 case NFS4ATTR_GETIT: 468 error = fattr4_get_change(sarg, &na->change); 469 break; 470 case NFS4ATTR_SETIT: 471 /* 472 * read-only attr 473 */ 474 error = EINVAL; 475 break; 476 case NFS4ATTR_VERIT: 477 mask = vap->va_mask; 478 vap->va_mask &= ~AT_CTIME; /* force a VOP_GETATTR */ 479 error = fattr4_get_change(sarg, &change); 480 vap->va_mask = mask; 481 if (!error && (na->change != change)) 482 error = -1; 483 break; 484 case NFS4ATTR_FREEIT: 485 break; 486 } 487 return (error); 488 } 489 490 /* ARGSUSED */ 491 static int 492 rfs4_fattr4_size(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 493 union nfs4_attr_u *na) 494 { 495 int error = 0; 496 497 switch (cmd) { 498 case NFS4ATTR_SUPPORTED: 499 break; /* this attr is supported */ 500 case NFS4ATTR_GETIT: 501 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_SIZE)) { 502 error = -1; /* may be okay if rdattr_error */ 503 break; 504 } 505 ASSERT(sarg->vap->va_mask & AT_SIZE); 506 na->size = sarg->vap->va_size; 507 break; 508 case NFS4ATTR_SETIT: 509 ASSERT(sarg->vap->va_mask & AT_SIZE); 510 sarg->vap->va_size = na->size; 511 break; 512 case NFS4ATTR_VERIT: 513 ASSERT(sarg->vap->va_mask & AT_SIZE); 514 if (sarg->vap->va_size != na->size) 515 error = -1; /* no match */ 516 break; 517 case NFS4ATTR_FREEIT: 518 break; 519 } 520 return (error); 521 } 522 523 /* 524 * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports 525 * hard links. 526 */ 527 /* ARGSUSED */ 528 static int 529 rfs4_fattr4_link_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 530 union nfs4_attr_u *na) 531 { 532 int error = 0; 533 534 switch (cmd) { 535 case NFS4ATTR_SUPPORTED: 536 if (sarg->op == NFS4ATTR_SETIT) 537 error = EINVAL; 538 break; /* this attr is supported */ 539 case NFS4ATTR_GETIT: 540 na->link_support = TRUE; 541 break; 542 case NFS4ATTR_SETIT: 543 /* 544 * read-only attr 545 */ 546 error = EINVAL; 547 break; 548 case NFS4ATTR_VERIT: 549 if (!na->link_support) 550 error = -1; /* no match */ 551 break; 552 case NFS4ATTR_FREEIT: 553 break; 554 } 555 return (error); 556 } 557 558 /* 559 * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports 560 * sym links. 561 */ 562 /* ARGSUSED */ 563 static int 564 rfs4_fattr4_symlink_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 565 union nfs4_attr_u *na) 566 { 567 int error = 0; 568 569 switch (cmd) { 570 case NFS4ATTR_SUPPORTED: 571 if (sarg->op == NFS4ATTR_SETIT) 572 error = EINVAL; 573 break; /* this attr is supported */ 574 case NFS4ATTR_GETIT: 575 na->symlink_support = TRUE; 576 break; 577 case NFS4ATTR_SETIT: 578 /* 579 * read-only attr 580 */ 581 error = EINVAL; 582 break; 583 case NFS4ATTR_VERIT: 584 if (!na->symlink_support) 585 error = -1; /* no match */ 586 break; 587 case NFS4ATTR_FREEIT: 588 break; 589 } 590 return (error); 591 } 592 593 /* ARGSUSED */ 594 static int 595 rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 596 union nfs4_attr_u *na) 597 { 598 int error = 0; 599 ulong_t val; 600 601 switch (cmd) { 602 case NFS4ATTR_SUPPORTED: 603 if (sarg->op == NFS4ATTR_SETIT) 604 error = EINVAL; 605 break; /* this attr is supported */ 606 case NFS4ATTR_GETIT: 607 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) { 608 error = -1; /* may be okay if rdattr_error */ 609 break; 610 } 611 ASSERT(sarg->cs->vp != NULL); 612 613 /* 614 * Solaris xattr model requires that VFS_XATTR is set 615 * in file systems enabled for generic xattr. If VFS_XATTR 616 * not set, no need to call pathconf for _PC_XATTR_EXISTS.. 617 * 618 * However the VFS_XATTR flag doesn't indicate sysattr support 619 * so always check for sysattrs and then only do the 620 * _PC_XATTR_EXISTS pathconf if needed. 621 */ 622 623 val = 0; 624 error = VOP_PATHCONF(sarg->cs->vp, _PC_SATTR_EXISTS, 625 &val, sarg->cs->cr, NULL); 626 if ((error || val == 0) && 627 sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) { 628 error = VOP_PATHCONF(sarg->cs->vp, 629 _PC_XATTR_EXISTS, &val, sarg->cs->cr, NULL); 630 if (error) 631 break; 632 } 633 na->named_attr = (val ? TRUE : FALSE); 634 break; 635 case NFS4ATTR_SETIT: 636 /* 637 * read-only attr 638 */ 639 error = EINVAL; 640 break; 641 case NFS4ATTR_VERIT: 642 ASSERT(sarg->cs->vp != NULL); 643 if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) { 644 error = VOP_PATHCONF(sarg->cs->vp, _PC_SATTR_EXISTS, 645 &val, sarg->cs->cr, NULL); 646 if (error || val == 0) 647 error = VOP_PATHCONF(sarg->cs->vp, 648 _PC_XATTR_EXISTS, &val, 649 sarg->cs->cr, NULL); 650 if (error) 651 break; 652 } else 653 val = 0; 654 if (na->named_attr != (val ? TRUE : FALSE)) 655 error = -1; /* no match */ 656 break; 657 case NFS4ATTR_FREEIT: 658 break; 659 } 660 return (error); 661 } 662 663 /* ARGSUSED */ 664 static int 665 rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 666 union nfs4_attr_u *na) 667 { 668 int error = 0; 669 int *pmaj = (int *)&na->fsid.major; 670 671 /* 672 * fsid_t is 64bits so it fits completely in fattr4_fsid.major. 673 * fattr4_fsid.minor is always set to 0 since it isn't needed (yet). 674 */ 675 switch (cmd) { 676 case NFS4ATTR_SUPPORTED: 677 if (sarg->op == NFS4ATTR_SETIT) 678 error = EINVAL; 679 break; /* this attr is supported */ 680 case NFS4ATTR_GETIT: 681 if (sarg->is_referral) { 682 na->fsid.major = 1; 683 na->fsid.minor = 0; 684 } else if (sarg->cs->exi->exi_volatile_dev) { 685 pmaj[0] = sarg->cs->exi->exi_fsid.val[0]; 686 pmaj[1] = sarg->cs->exi->exi_fsid.val[1]; 687 na->fsid.minor = 0; 688 } else { 689 na->fsid.major = getmajor(sarg->vap->va_fsid); 690 na->fsid.minor = getminor(sarg->vap->va_fsid); 691 } 692 break; 693 case NFS4ATTR_SETIT: 694 error = EINVAL; 695 break; 696 case NFS4ATTR_VERIT: 697 if (sarg->is_referral) { 698 if (na->fsid.major != 1 || 699 na->fsid.minor != 0) 700 error = -1; 701 } else if (sarg->cs->exi->exi_volatile_dev) { 702 if (pmaj[0] != sarg->cs->exi->exi_fsid.val[0] || 703 pmaj[1] != sarg->cs->exi->exi_fsid.val[1] || 704 na->fsid.minor != 0) 705 error = -1; 706 } else { 707 if (na->fsid.major != getmajor(sarg->vap->va_fsid) || 708 na->fsid.minor != getminor(sarg->vap->va_fsid)) 709 error = -1; 710 } 711 break; 712 case NFS4ATTR_FREEIT: 713 break; 714 } 715 return (error); 716 } 717 718 /* ARGSUSED */ 719 static int 720 rfs4_fattr4_unique_handles(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 721 union nfs4_attr_u *na) 722 { 723 /* 724 * XXX 725 * For now, we can't support this. Problem of /export, beinging 726 * a file system, /export/a and /export/b shared separately, 727 * and /export/a/l and /export/b/l are ahrd links of each other. 728 */ 729 int error = 0; 730 731 switch (cmd) { 732 case NFS4ATTR_SUPPORTED: 733 if (sarg->op == NFS4ATTR_SETIT) 734 error = EINVAL; 735 break; /* this attr is supported */ 736 case NFS4ATTR_GETIT: 737 na->unique_handles = FALSE; 738 break; 739 case NFS4ATTR_SETIT: 740 /* 741 * read-only attr 742 */ 743 error = EINVAL; 744 break; 745 case NFS4ATTR_VERIT: 746 if (na->unique_handles) 747 error = -1; /* no match */ 748 break; 749 case NFS4ATTR_FREEIT: 750 break; 751 } 752 return (error); 753 } 754 755 /* ARGSUSED */ 756 static int 757 rfs4_fattr4_lease_time(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 758 union nfs4_attr_u *na) 759 { 760 int error = 0; 761 762 switch (cmd) { 763 case NFS4ATTR_SUPPORTED: 764 if (sarg->op == NFS4ATTR_SETIT) 765 error = EINVAL; 766 break; /* this attr is supported */ 767 case NFS4ATTR_GETIT: 768 na->lease_time = rfs4_lease_time; 769 break; 770 case NFS4ATTR_SETIT: 771 /* 772 * read-only attr 773 */ 774 error = EINVAL; 775 break; 776 case NFS4ATTR_VERIT: 777 if (na->lease_time != rfs4_lease_time) 778 error = -1; /* no match */ 779 break; 780 case NFS4ATTR_FREEIT: 781 break; 782 } 783 return (error); 784 } 785 786 /* ARGSUSED */ 787 static int 788 rfs4_fattr4_rdattr_error(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 789 union nfs4_attr_u *na) 790 { 791 int error = 0; 792 793 switch (cmd) { 794 case NFS4ATTR_SUPPORTED: 795 if ((sarg->op == NFS4ATTR_SETIT) || 796 (sarg->op == NFS4ATTR_VERIT)) 797 error = EINVAL; 798 break; /* this attr is supported */ 799 case NFS4ATTR_GETIT: 800 ASSERT(sarg->rdattr_error_req); 801 na->rdattr_error = sarg->rdattr_error; 802 break; 803 case NFS4ATTR_SETIT: 804 case NFS4ATTR_VERIT: 805 /* 806 * read-only attr 807 */ 808 error = EINVAL; 809 break; 810 case NFS4ATTR_FREEIT: 811 break; 812 } 813 return (error); 814 } 815 816 /* 817 * Server side compare of a filehandle from the wire to a native 818 * server filehandle. 819 */ 820 static int 821 rfs4fhcmp(nfs_fh4 *wirefh, nfs_fh4 *srvfh) 822 { 823 nfs_fh4_fmt_t fh; 824 825 ASSERT(IS_P2ALIGNED(wirefh->nfs_fh4_val, sizeof (uint32_t))); 826 827 bzero(&fh, sizeof (nfs_fh4_fmt_t)); 828 if (!xdr_inline_decode_nfs_fh4((uint32_t *)wirefh->nfs_fh4_val, &fh, 829 wirefh->nfs_fh4_len)) 830 return (1); 831 832 return (bcmp(srvfh->nfs_fh4_val, &fh, srvfh->nfs_fh4_len)); 833 } 834 835 /* ARGSUSED */ 836 static int 837 rfs4_fattr4_filehandle(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 838 union nfs4_attr_u *na) 839 { 840 nfs_fh4 *fh; 841 842 switch (cmd) { 843 case NFS4ATTR_SUPPORTED: 844 if (sarg->op == NFS4ATTR_SETIT) 845 return (EINVAL); 846 return (0); /* this attr is supported */ 847 case NFS4ATTR_GETIT: 848 /* 849 * If sarg->cs->fh is all zeros then should makefh a new 850 * one, otherwise, copy that one over. 851 */ 852 fh = &sarg->cs->fh; 853 if (sarg->cs->fh.nfs_fh4_len == 0) { 854 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) 855 return (-1); /* okay if rdattr_error */ 856 ASSERT(sarg->cs->vp != NULL); 857 na->filehandle.nfs_fh4_val = 858 kmem_alloc(NFS_FH4_LEN, KM_SLEEP); 859 return (makefh4(&na->filehandle, sarg->cs->vp, 860 sarg->cs->exi)); 861 } 862 na->filehandle.nfs_fh4_val = 863 kmem_alloc(fh->nfs_fh4_len, KM_SLEEP); 864 nfs_fh4_copy(fh, &na->filehandle); 865 return (0); 866 case NFS4ATTR_SETIT: 867 /* 868 * read-only attr 869 */ 870 return (EINVAL); 871 case NFS4ATTR_VERIT: 872 /* 873 * A verify of a filehandle will have the client sending 874 * the raw format which needs to be compared to the 875 * native format. 876 */ 877 if (rfs4fhcmp(&na->filehandle, &sarg->cs->fh) == 1) 878 return (-1); /* no match */ 879 return (0); 880 case NFS4ATTR_FREEIT: 881 if (sarg->op != NFS4ATTR_GETIT) 882 return (0); 883 if (na->filehandle.nfs_fh4_val == NULL) 884 return (0); 885 kmem_free(na->filehandle.nfs_fh4_val, 886 na->filehandle.nfs_fh4_len); 887 na->filehandle.nfs_fh4_val = NULL; 888 na->filehandle.nfs_fh4_len = 0; 889 return (0); 890 } 891 return (0); 892 } 893 894 /* 895 * Recommended attributes 896 */ 897 898 /* ARGSUSED */ 899 static int 900 rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 901 union nfs4_attr_u *na) 902 { 903 int error = 0; 904 vsecattr_t vs_native, vs_ace4; 905 ulong_t whichacl; 906 nfsstat4 status; 907 vattr_t va, *vap = sarg->vap; 908 vnode_t *vp = sarg->cs->vp; 909 910 if (RFS4_MANDATTR_ONLY) 911 return (ENOTSUP); 912 913 switch (cmd) { 914 case NFS4ATTR_SUPPORTED: 915 break; 916 917 case NFS4ATTR_VERIT: 918 case NFS4ATTR_GETIT: 919 if (sarg->rdattr_error && (vp == NULL)) { 920 return (-1); 921 } 922 ASSERT(vp != NULL); 923 bzero(&vs_native, sizeof (vs_native)); 924 925 /* see which ACLs fs supports */ 926 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, 927 sarg->cs->cr, NULL); 928 if (error != 0) { 929 /* 930 * If we got an error, then the filesystem 931 * likely does not understand the _PC_ACL_ENABLED 932 * pathconf. In this case, we fall back to trying 933 * POSIX-draft (aka UFS-style) ACLs, since that's 934 * the behavior used by earlier version of NFS. 935 */ 936 error = 0; 937 whichacl = _ACL_ACLENT_ENABLED; 938 } 939 940 if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 941 /* 942 * If the file system supports neither ACE nor 943 * ACLENT ACLs we will fall back to UFS-style ACLs 944 * like we did above if there was an error upon 945 * calling VOP_PATHCONF. 946 * 947 * ACE and ACLENT type ACLs are the only interfaces 948 * supported thus far. If any other bits are set on 949 * 'whichacl' upon return from VOP_PATHCONF, we will 950 * ignore them. 951 */ 952 whichacl = _ACL_ACLENT_ENABLED; 953 } 954 955 if (whichacl & _ACL_ACE_ENABLED) 956 vs_native.vsa_mask = VSA_ACE | VSA_ACECNT; 957 else if (whichacl & _ACL_ACLENT_ENABLED) 958 vs_native.vsa_mask = VSA_ACL | VSA_ACLCNT | 959 VSA_DFACL | VSA_DFACLCNT; 960 961 if (error != 0) 962 break; 963 964 /* get the ACL, and translate it into nfsace4 style */ 965 error = VOP_GETSECATTR(vp, &vs_native, 966 0, sarg->cs->cr, NULL); 967 if (error != 0) 968 break; 969 if (whichacl & _ACL_ACE_ENABLED) { 970 error = vs_acet_to_ace4(&vs_native, &vs_ace4, TRUE); 971 vs_acet_destroy(&vs_native); 972 } else { 973 error = vs_aent_to_ace4(&vs_native, &vs_ace4, 974 vp->v_type == VDIR, TRUE); 975 vs_aent_destroy(&vs_native); 976 } 977 if (error != 0) 978 break; 979 980 if (cmd == NFS4ATTR_GETIT) { 981 na->acl.fattr4_acl_len = vs_ace4.vsa_aclcnt; 982 /* see case NFS4ATTR_FREEIT for this being freed */ 983 na->acl.fattr4_acl_val = vs_ace4.vsa_aclentp; 984 } else { 985 if (na->acl.fattr4_acl_len != vs_ace4.vsa_aclcnt) 986 error = -1; /* no match */ 987 else if (ln_ace4_cmp(na->acl.fattr4_acl_val, 988 vs_ace4.vsa_aclentp, 989 vs_ace4.vsa_aclcnt) != 0) 990 error = -1; /* no match */ 991 } 992 993 break; 994 995 case NFS4ATTR_SETIT: 996 if (sarg->rdattr_error && (vp == NULL)) { 997 return (-1); 998 } 999 ASSERT(vp != NULL); 1000 1001 /* prepare vs_ace4 from fattr4 data */ 1002 bzero(&vs_ace4, sizeof (vs_ace4)); 1003 vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT; 1004 vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len; 1005 vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val; 1006 vs_ace4.vsa_aclentsz = vs_ace4.vsa_aclcnt * sizeof (ace_t); 1007 /* make sure we have correct owner/group */ 1008 if ((vap->va_mask & (AT_UID | AT_GID)) != 1009 (AT_UID | AT_GID)) { 1010 vap = &va; 1011 vap->va_mask = AT_UID | AT_GID; 1012 status = rfs4_vop_getattr(vp, 1013 vap, 0, sarg->cs->cr); 1014 if (status != NFS4_OK) 1015 return (geterrno4(status)); 1016 } 1017 1018 /* see which ACLs the fs supports */ 1019 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, 1020 sarg->cs->cr, NULL); 1021 if (error != 0) { 1022 /* 1023 * If we got an error, then the filesystem 1024 * likely does not understand the _PC_ACL_ENABLED 1025 * pathconf. In this case, we fall back to trying 1026 * POSIX-draft (aka UFS-style) ACLs, since that's 1027 * the behavior used by earlier version of NFS. 1028 */ 1029 error = 0; 1030 whichacl = _ACL_ACLENT_ENABLED; 1031 } 1032 1033 if (!(whichacl & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED))) { 1034 /* 1035 * If the file system supports neither ACE nor 1036 * ACLENT ACLs we will fall back to UFS-style ACLs 1037 * like we did above if there was an error upon 1038 * calling VOP_PATHCONF. 1039 * 1040 * ACE and ACLENT type ACLs are the only interfaces 1041 * supported thus far. If any other bits are set on 1042 * 'whichacl' upon return from VOP_PATHCONF, we will 1043 * ignore them. 1044 */ 1045 whichacl = _ACL_ACLENT_ENABLED; 1046 } 1047 1048 if (whichacl & _ACL_ACE_ENABLED) { 1049 error = vs_ace4_to_acet(&vs_ace4, &vs_native, 1050 vap->va_uid, vap->va_gid, TRUE); 1051 if (error != 0) 1052 break; 1053 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1054 error = VOP_SETSECATTR(vp, &vs_native, 1055 0, sarg->cs->cr, NULL); 1056 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1057 vs_acet_destroy(&vs_native); 1058 } else if (whichacl & _ACL_ACLENT_ENABLED) { 1059 error = vs_ace4_to_aent(&vs_ace4, &vs_native, 1060 vap->va_uid, vap->va_gid, vp->v_type == VDIR, TRUE); 1061 if (error != 0) 1062 break; 1063 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1064 error = VOP_SETSECATTR(vp, &vs_native, 1065 0, sarg->cs->cr, NULL); 1066 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1067 vs_aent_destroy(&vs_native); 1068 } 1069 break; 1070 1071 case NFS4ATTR_FREEIT: 1072 if (sarg->op == NFS4ATTR_GETIT) { 1073 vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT; 1074 vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len; 1075 vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val; 1076 vs_ace4_destroy(&vs_ace4); 1077 } 1078 break; 1079 } 1080 1081 return (error); 1082 } 1083 1084 /* ARGSUSED */ 1085 static int 1086 rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1087 union nfs4_attr_u *na) 1088 { 1089 int error = 0; 1090 1091 if (RFS4_MANDATTR_ONLY) 1092 return (ENOTSUP); 1093 1094 switch (cmd) { 1095 case NFS4ATTR_SUPPORTED: 1096 if (sarg->op == NFS4ATTR_SETIT) 1097 error = EINVAL; 1098 break; /* supported */ 1099 case NFS4ATTR_GETIT: 1100 na->aclsupport = ACL4_SUPPORT_ALLOW_ACL | 1101 ACL4_SUPPORT_DENY_ACL; 1102 break; 1103 case NFS4ATTR_SETIT: 1104 error = EINVAL; 1105 break; 1106 case NFS4ATTR_VERIT: 1107 if (na->aclsupport != (ACL4_SUPPORT_ALLOW_ACL | 1108 ACL4_SUPPORT_DENY_ACL)) 1109 error = -1; /* no match */ 1110 break; 1111 } 1112 1113 return (error); 1114 } 1115 1116 /* ARGSUSED */ 1117 static int 1118 rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1119 union nfs4_attr_u *na) 1120 { 1121 return (ENOTSUP); 1122 } 1123 1124 /* ARGSUSED */ 1125 static int 1126 rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1127 union nfs4_attr_u *na) 1128 { 1129 int error = 0; 1130 1131 if (RFS4_MANDATTR_ONLY) 1132 return (ENOTSUP); 1133 1134 switch (cmd) { 1135 case NFS4ATTR_SUPPORTED: 1136 if (sarg->op == NFS4ATTR_SETIT) 1137 error = EINVAL; 1138 break; /* this attr is supported */ 1139 case NFS4ATTR_GETIT: 1140 na->cansettime = TRUE; 1141 break; 1142 case NFS4ATTR_SETIT: 1143 /* 1144 * read-only attr 1145 */ 1146 error = EINVAL; 1147 break; 1148 case NFS4ATTR_VERIT: 1149 if (!na->cansettime) 1150 error = -1; /* no match */ 1151 break; 1152 case NFS4ATTR_FREEIT: 1153 break; 1154 } 1155 return (error); 1156 } 1157 1158 /* 1159 * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports 1160 * case insensitive. 1161 */ 1162 /* ARGSUSED */ 1163 static int 1164 rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1165 union nfs4_attr_u *na) 1166 { 1167 int error = 0; 1168 1169 if (RFS4_MANDATTR_ONLY) 1170 return (ENOTSUP); 1171 1172 switch (cmd) { 1173 case NFS4ATTR_SUPPORTED: 1174 if (sarg->op == NFS4ATTR_SETIT) 1175 error = EINVAL; 1176 break; /* this attr is supported */ 1177 case NFS4ATTR_GETIT: 1178 na->case_insensitive = FALSE; 1179 break; 1180 case NFS4ATTR_SETIT: 1181 /* 1182 * read-only attr 1183 */ 1184 error = EINVAL; 1185 break; 1186 case NFS4ATTR_VERIT: 1187 if (!na->case_insensitive) 1188 error = -1; /* no match */ 1189 break; 1190 case NFS4ATTR_FREEIT: 1191 break; 1192 } 1193 return (error); 1194 } 1195 1196 /* ARGSUSED */ 1197 static int 1198 rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1199 union nfs4_attr_u *na) 1200 { 1201 int error = 0; 1202 1203 if (RFS4_MANDATTR_ONLY) 1204 return (ENOTSUP); 1205 1206 switch (cmd) { 1207 case NFS4ATTR_SUPPORTED: 1208 if (sarg->op == NFS4ATTR_SETIT) 1209 error = EINVAL; 1210 break; /* this attr is supported */ 1211 case NFS4ATTR_GETIT: 1212 na->case_preserving = TRUE; 1213 break; 1214 case NFS4ATTR_SETIT: 1215 /* 1216 * read-only attr 1217 */ 1218 error = EINVAL; 1219 break; 1220 case NFS4ATTR_VERIT: 1221 if (!na->case_preserving) 1222 error = -1; /* no match */ 1223 break; 1224 case NFS4ATTR_FREEIT: 1225 break; 1226 } 1227 return (error); 1228 } 1229 1230 /* fattr4_chown_restricted should reall be fattr4_chown_allowed */ 1231 /* ARGSUSED */ 1232 static int 1233 rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1234 union nfs4_attr_u *na) 1235 { 1236 int error = 0; 1237 ulong_t val; 1238 1239 if (RFS4_MANDATTR_ONLY) 1240 return (ENOTSUP); 1241 1242 switch (cmd) { 1243 case NFS4ATTR_SUPPORTED: 1244 if (sarg->op == NFS4ATTR_SETIT) 1245 error = EINVAL; 1246 break; /* this attr is supported */ 1247 case NFS4ATTR_GETIT: 1248 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) { 1249 error = -1; /* may be okay if rdattr_error */ 1250 break; 1251 } 1252 ASSERT(sarg->cs->vp != NULL); 1253 error = VOP_PATHCONF(sarg->cs->vp, 1254 _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL); 1255 if (error) 1256 break; 1257 1258 na->chown_restricted = (val == 1); 1259 break; 1260 case NFS4ATTR_SETIT: 1261 /* 1262 * read-only attr 1263 */ 1264 error = EINVAL; 1265 break; 1266 case NFS4ATTR_VERIT: 1267 ASSERT(sarg->cs->vp != NULL); 1268 error = VOP_PATHCONF(sarg->cs->vp, 1269 _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL); 1270 if (error) 1271 break; 1272 if (na->chown_restricted != (val == 1)) 1273 error = -1; /* no match */ 1274 break; 1275 case NFS4ATTR_FREEIT: 1276 break; 1277 } 1278 return (error); 1279 } 1280 1281 /* ARGSUSED */ 1282 static int 1283 rfs4_fattr4_fileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1284 union nfs4_attr_u *na) 1285 { 1286 int error = 0; 1287 1288 if (RFS4_MANDATTR_ONLY) 1289 return (ENOTSUP); 1290 1291 switch (cmd) { 1292 case NFS4ATTR_SUPPORTED: 1293 if (sarg->op == NFS4ATTR_SETIT) 1294 error = EINVAL; 1295 break; /* this attr is supported */ 1296 case NFS4ATTR_GETIT: 1297 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NODEID)) { 1298 error = -1; /* may be okay if rdattr_error */ 1299 break; 1300 } 1301 ASSERT(sarg->vap->va_mask & AT_NODEID); 1302 na->fileid = sarg->vap->va_nodeid; 1303 break; 1304 case NFS4ATTR_SETIT: 1305 /* 1306 * read-only attr 1307 */ 1308 error = EINVAL; 1309 break; 1310 case NFS4ATTR_VERIT: 1311 ASSERT(sarg->vap->va_mask & AT_NODEID); 1312 if (sarg->vap->va_nodeid != na->fileid) 1313 error = -1; /* no match */ 1314 break; 1315 case NFS4ATTR_FREEIT: 1316 break; 1317 } 1318 return (error); 1319 } 1320 1321 /* ARGSUSED */ 1322 static int 1323 rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg) 1324 { 1325 int error = 0; 1326 vattr_t *vap, va; 1327 vnode_t *stubvp = NULL, *vp; 1328 1329 vp = sarg->cs->vp; 1330 sarg->mntdfid_set = FALSE; 1331 1332 /* 1333 * VROOT object or zone's root, must untraverse. 1334 * 1335 * NOTE: Not doing reality checks on curzone vs. compound 1336 * state vnode because it will mismatch once at initialization 1337 * if a non-global-zone triggers the module load, BUT in that case 1338 * the vp is literally "/" which has VROOT set. 1339 */ 1340 if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) { 1341 1342 /* extra hold for vp since untraverse might rele */ 1343 VN_HOLD(vp); 1344 stubvp = untraverse(vp, ZONE_ROOTVP()); 1345 1346 /* 1347 * If vp/stubvp are same, we must be at system-or-zone 1348 * root because untraverse returned same vp 1349 * for a VROOT object. sarg->vap was setup 1350 * before we got here, so there's no need to do 1351 * another getattr -- just use the one in sarg. 1352 */ 1353 if (VN_CMP(vp, stubvp)) { 1354 ASSERT(VN_IS_CURZONEROOT(vp)); 1355 vap = sarg->vap; 1356 } else { 1357 va.va_mask = AT_NODEID; 1358 vap = &va; 1359 error = rfs4_vop_getattr(stubvp, vap, 0, sarg->cs->cr); 1360 } 1361 1362 /* 1363 * Done with stub, time to rele. If vp and stubvp 1364 * were the same, then we need to rele either vp or 1365 * stubvp. If they weren't the same, then untraverse() 1366 * already took case of the extra hold on vp, and only 1367 * the stub needs to be rele'd. Both cases are handled 1368 * by unconditionally rele'ing the stub. 1369 */ 1370 VN_RELE(stubvp); 1371 } else 1372 vap = sarg->vap; 1373 1374 /* 1375 * At this point, vap should contain "correct" AT_NODEID -- 1376 * (for V_ROOT case, nodeid of stub, for non-VROOT case, 1377 * nodeid of vp). If error or AT_NODEID not available, then 1378 * make the obligatory (yet mysterious) rdattr_error 1379 * check that is so common in the attr code. 1380 */ 1381 if (!error && (vap->va_mask & AT_NODEID)) { 1382 sarg->mounted_on_fileid = vap->va_nodeid; 1383 sarg->mntdfid_set = TRUE; 1384 } else if (sarg->rdattr_error) 1385 error = -1; 1386 1387 /* 1388 * error describes these cases: 1389 * 0 : success 1390 * -1: failure due to previous attr processing error (rddir only). 1391 * * : new attr failure (if rddir, caller will set rdattr_error) 1392 */ 1393 return (error); 1394 } 1395 1396 /* ARGSUSED */ 1397 static int 1398 rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd, 1399 struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na) 1400 { 1401 int error = 0; 1402 1403 if (RFS4_MANDATTR_ONLY) 1404 return (ENOTSUP); 1405 1406 switch (cmd) { 1407 case NFS4ATTR_SUPPORTED: 1408 if (sarg->op == NFS4ATTR_SETIT) 1409 error = EINVAL; 1410 break; /* this attr is supported */ 1411 case NFS4ATTR_GETIT: 1412 case NFS4ATTR_VERIT: 1413 if (!sarg->mntdfid_set) 1414 error = rfs4_get_mntdfileid(cmd, sarg); 1415 1416 if (!error && sarg->mntdfid_set) { 1417 if (cmd == NFS4ATTR_GETIT) 1418 na->mounted_on_fileid = sarg->mounted_on_fileid; 1419 else 1420 if (na->mounted_on_fileid != 1421 sarg->mounted_on_fileid) 1422 error = -1; 1423 } 1424 break; 1425 case NFS4ATTR_SETIT: 1426 /* read-only attr */ 1427 error = EINVAL; 1428 break; 1429 case NFS4ATTR_FREEIT: 1430 break; 1431 } 1432 return (error); 1433 } 1434 1435 /* ARGSUSED */ 1436 static int 1437 rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1438 union nfs4_attr_u *na) 1439 { 1440 int error = 0; 1441 1442 if (RFS4_MANDATTR_ONLY) 1443 return (ENOTSUP); 1444 1445 switch (cmd) { 1446 case NFS4ATTR_SUPPORTED: 1447 if (sarg->op == NFS4ATTR_SETIT) 1448 error = EINVAL; 1449 break; /* this attr is supported */ 1450 case NFS4ATTR_GETIT: 1451 if (sarg->rdattr_error && (sarg->sbp == NULL)) { 1452 error = -1; /* may be okay if rdattr_error */ 1453 break; 1454 } 1455 ASSERT(sarg->sbp != NULL); 1456 na->files_avail = sarg->sbp->f_favail; 1457 break; 1458 case NFS4ATTR_SETIT: 1459 /* 1460 * read-only attr 1461 */ 1462 error = EINVAL; 1463 break; 1464 case NFS4ATTR_VERIT: 1465 ASSERT(sarg->sbp != NULL); 1466 if (sarg->sbp->f_favail != na->files_avail) 1467 error = -1; /* no match */ 1468 break; 1469 case NFS4ATTR_FREEIT: 1470 break; 1471 } 1472 return (error); 1473 } 1474 1475 /* ARGSUSED */ 1476 static int 1477 rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1478 union nfs4_attr_u *na) 1479 { 1480 int error = 0; 1481 1482 if (RFS4_MANDATTR_ONLY) 1483 return (ENOTSUP); 1484 1485 switch (cmd) { 1486 case NFS4ATTR_SUPPORTED: 1487 if (sarg->op == NFS4ATTR_SETIT) 1488 error = EINVAL; 1489 break; /* this attr is supported */ 1490 case NFS4ATTR_GETIT: 1491 if (sarg->rdattr_error && (sarg->sbp == NULL)) { 1492 error = -1; /* may be okay if rdattr_error */ 1493 break; 1494 } 1495 ASSERT(sarg->sbp != NULL); 1496 na->files_free = sarg->sbp->f_ffree; 1497 break; 1498 case NFS4ATTR_SETIT: 1499 /* 1500 * read-only attr 1501 */ 1502 error = EINVAL; 1503 break; 1504 case NFS4ATTR_VERIT: 1505 ASSERT(sarg->sbp != NULL); 1506 if (sarg->sbp->f_ffree != na->files_free) 1507 error = -1; /* no match */ 1508 break; 1509 case NFS4ATTR_FREEIT: 1510 break; 1511 } 1512 return (error); 1513 } 1514 1515 /* ARGSUSED */ 1516 static int 1517 rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1518 union nfs4_attr_u *na) 1519 { 1520 int error = 0; 1521 1522 if (RFS4_MANDATTR_ONLY) 1523 return (ENOTSUP); 1524 1525 switch (cmd) { 1526 case NFS4ATTR_SUPPORTED: 1527 if (sarg->op == NFS4ATTR_SETIT) 1528 error = EINVAL; 1529 break; /* this attr is supported */ 1530 case NFS4ATTR_GETIT: 1531 if (sarg->rdattr_error && (sarg->sbp == NULL)) { 1532 error = -1; /* may be okay if rdattr_error */ 1533 break; 1534 } 1535 ASSERT(sarg->sbp != NULL); 1536 na->files_total = sarg->sbp->f_files; 1537 break; 1538 case NFS4ATTR_SETIT: 1539 /* 1540 * read-only attr 1541 */ 1542 error = EINVAL; 1543 break; 1544 case NFS4ATTR_VERIT: 1545 ASSERT(sarg->sbp != NULL); 1546 if (sarg->sbp->f_files != na->files_total) 1547 error = -1; /* no match */ 1548 break; 1549 case NFS4ATTR_FREEIT: 1550 break; 1551 } 1552 return (error); 1553 } 1554 1555 static void 1556 rfs4_free_pathname4(pathname4 *pn4) 1557 { 1558 int i, len; 1559 utf8string *utf8s; 1560 1561 if (pn4 == NULL || (len = pn4->pathname4_len) == 0 || 1562 (utf8s = pn4->pathname4_val) == NULL) 1563 return; 1564 1565 for (i = 0; i < len; i++, utf8s++) { 1566 if (utf8s->utf8string_val == NULL || 1567 utf8s->utf8string_len == 0) 1568 continue; 1569 1570 kmem_free(utf8s->utf8string_val, utf8s->utf8string_len); 1571 utf8s->utf8string_val = NULL; 1572 } 1573 1574 kmem_free(pn4->pathname4_val, 1575 sizeof (utf8string) * pn4->pathname4_len); 1576 pn4->pathname4_val = 0; 1577 } 1578 1579 static void 1580 rfs4_free_fs_location4(fs_location4 *fsl4) 1581 { 1582 if (fsl4 == NULL) 1583 return; 1584 1585 rfs4_free_pathname4((pathname4 *)&fsl4->server_len); 1586 rfs4_free_pathname4(&fsl4->rootpath); 1587 } 1588 1589 void 1590 rfs4_free_fs_locations4(fs_locations4 *fsls4) 1591 { 1592 int i, len; 1593 fs_location4 *fsl4; 1594 1595 if (fsls4 == NULL) 1596 return; 1597 1598 /* free fs_root */ 1599 rfs4_free_pathname4(&fsls4->fs_root); 1600 1601 if ((len = fsls4->locations_len) == 0 || 1602 (fsl4 = fsls4->locations_val) == NULL) 1603 return; 1604 1605 /* free fs_location4 */ 1606 for (i = 0; i < len; i++) { 1607 rfs4_free_fs_location4(fsl4); 1608 fsl4++; 1609 } 1610 1611 kmem_free(fsls4->locations_val, sizeof (fs_location4) * len); 1612 fsls4->locations_val = NULL; 1613 } 1614 1615 /* ARGSUSED */ 1616 static int 1617 rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1618 union nfs4_attr_u *na) 1619 { 1620 int error = 0; 1621 fs_locations4 *fsl; 1622 1623 if (RFS4_MANDATTR_ONLY) 1624 return (ENOTSUP); 1625 1626 switch (cmd) { 1627 case NFS4ATTR_SUPPORTED: 1628 if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT) 1629 error = EINVAL; 1630 break; /* this attr is supported */ 1631 1632 case NFS4ATTR_GETIT: 1633 { 1634 kstat_named_t *stat = 1635 sarg->cs->exi->exi_ne->ne_globals->svstat[NFS_V4]; 1636 1637 fsl = fetch_referral(sarg->cs->vp, sarg->cs->cr); 1638 if (fsl == NULL) 1639 (void) memset(&(na->fs_locations), 0, 1640 sizeof (fs_locations4)); 1641 else { 1642 na->fs_locations = *fsl; 1643 kmem_free(fsl, sizeof (fs_locations4)); 1644 } 1645 stat[NFS_REFERRALS].value.ui64++; 1646 break; 1647 } 1648 case NFS4ATTR_FREEIT: 1649 if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT) 1650 error = EINVAL; 1651 rfs4_free_fs_locations4(&na->fs_locations); 1652 break; 1653 1654 case NFS4ATTR_SETIT: 1655 case NFS4ATTR_VERIT: 1656 /* 1657 * read-only attr 1658 */ 1659 error = EINVAL; 1660 break; 1661 } 1662 return (error); 1663 } 1664 1665 /* ARGSUSED */ 1666 static int 1667 rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1668 union nfs4_attr_u *na) 1669 { 1670 return (ENOTSUP); 1671 } 1672 1673 /* ARGSUSED */ 1674 static int 1675 rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1676 union nfs4_attr_u *na) 1677 { 1678 int error = 0; 1679 1680 if (RFS4_MANDATTR_ONLY) 1681 return (ENOTSUP); 1682 1683 switch (cmd) { 1684 case NFS4ATTR_SUPPORTED: 1685 if (sarg->op == NFS4ATTR_SETIT) 1686 error = EINVAL; 1687 break; /* this attr is supported */ 1688 case NFS4ATTR_GETIT: 1689 na->homogeneous = TRUE; /* XXX - need a VOP extension */ 1690 break; 1691 case NFS4ATTR_SETIT: 1692 /* 1693 * read-only attr 1694 */ 1695 error = EINVAL; 1696 break; 1697 case NFS4ATTR_VERIT: 1698 if (!na->homogeneous) 1699 error = -1; /* no match */ 1700 break; 1701 case NFS4ATTR_FREEIT: 1702 break; 1703 } 1704 return (error); 1705 } 1706 1707 /* ARGSUSED */ 1708 static int 1709 rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1710 union nfs4_attr_u *na) 1711 { 1712 int error = 0; 1713 ulong_t val; 1714 fattr4_maxfilesize maxfilesize; 1715 1716 if (RFS4_MANDATTR_ONLY) 1717 return (ENOTSUP); 1718 1719 switch (cmd) { 1720 case NFS4ATTR_SUPPORTED: 1721 if (sarg->op == NFS4ATTR_SETIT) 1722 error = EINVAL; 1723 break; /* this attr is supported */ 1724 case NFS4ATTR_GETIT: 1725 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) { 1726 error = -1; /* may be okay if rdattr_error */ 1727 break; 1728 } 1729 ASSERT(sarg->cs->vp != NULL); 1730 error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val, 1731 sarg->cs->cr, NULL); 1732 if (error) 1733 break; 1734 1735 /* 1736 * If the underlying file system does not support 1737 * _PC_FILESIZEBITS, return a reasonable default. Note that 1738 * error code on VOP_PATHCONF will be 0, even if the underlying 1739 * file system does not support _PC_FILESIZEBITS. 1740 */ 1741 if (val == (ulong_t)-1) { 1742 na->maxfilesize = MAXOFF32_T; 1743 } else { 1744 if (val >= (sizeof (uint64_t) * 8)) 1745 na->maxfilesize = INT64_MAX; 1746 else 1747 na->maxfilesize = ((1LL << (val - 1)) - 1); 1748 } 1749 break; 1750 case NFS4ATTR_SETIT: 1751 /* 1752 * read-only attr 1753 */ 1754 error = EINVAL; 1755 break; 1756 case NFS4ATTR_VERIT: 1757 ASSERT(sarg->cs->vp != NULL); 1758 error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val, 1759 sarg->cs->cr, NULL); 1760 if (error) 1761 break; 1762 /* 1763 * If the underlying file system does not support 1764 * _PC_FILESIZEBITS, return a reasonable default. Note that 1765 * error code on VOP_PATHCONF will be 0, even if the underlying 1766 * file system does not support _PC_FILESIZEBITS. 1767 */ 1768 if (val == (ulong_t)-1) { 1769 maxfilesize = MAXOFF32_T; 1770 } else { 1771 if (val >= (sizeof (uint64_t) * 8)) 1772 maxfilesize = INT64_MAX; 1773 else 1774 maxfilesize = ((1LL << (val - 1)) - 1); 1775 } 1776 if (na->maxfilesize != maxfilesize) 1777 error = -1; /* no match */ 1778 break; 1779 case NFS4ATTR_FREEIT: 1780 break; 1781 } 1782 return (error); 1783 } 1784 1785 /* ARGSUSED */ 1786 static int 1787 rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1788 union nfs4_attr_u *na) 1789 { 1790 int error = 0; 1791 ulong_t val; 1792 1793 if (RFS4_MANDATTR_ONLY) 1794 return (ENOTSUP); 1795 1796 switch (cmd) { 1797 case NFS4ATTR_SUPPORTED: 1798 if (sarg->op == NFS4ATTR_SETIT) 1799 error = EINVAL; 1800 break; /* this attr is supported */ 1801 case NFS4ATTR_GETIT: 1802 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) { 1803 error = -1; /* may be okay if rdattr_error */ 1804 break; 1805 } 1806 ASSERT(sarg->cs->vp != NULL); 1807 error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val, 1808 sarg->cs->cr, NULL); 1809 if (error == 0) { 1810 na->maxlink = val; 1811 } 1812 break; 1813 case NFS4ATTR_SETIT: 1814 /* 1815 * read-only attr 1816 */ 1817 error = EINVAL; 1818 break; 1819 case NFS4ATTR_VERIT: 1820 ASSERT(sarg->cs->vp != NULL); 1821 error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val, 1822 sarg->cs->cr, NULL); 1823 if (!error && (na->maxlink != (uint32_t)val)) 1824 error = -1; /* no match */ 1825 break; 1826 case NFS4ATTR_FREEIT: 1827 break; 1828 } 1829 return (error); 1830 } 1831 1832 /* ARGSUSED */ 1833 static int 1834 rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1835 union nfs4_attr_u *na) 1836 { 1837 int error = 0; 1838 ulong_t val; 1839 1840 if (RFS4_MANDATTR_ONLY) 1841 return (ENOTSUP); 1842 1843 switch (cmd) { 1844 case NFS4ATTR_SUPPORTED: 1845 if (sarg->op == NFS4ATTR_SETIT) 1846 error = EINVAL; 1847 break; /* this attr is supported */ 1848 case NFS4ATTR_GETIT: 1849 if (sarg->rdattr_error && (sarg->cs->vp == NULL)) { 1850 error = -1; /* may be okay if rdattr_error */ 1851 break; 1852 } 1853 ASSERT(sarg->cs->vp != NULL); 1854 error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val, 1855 sarg->cs->cr, NULL); 1856 if (error == 0) { 1857 na->maxname = val; 1858 } 1859 break; 1860 case NFS4ATTR_SETIT: 1861 /* 1862 * read-only attr 1863 */ 1864 error = EINVAL; 1865 break; 1866 case NFS4ATTR_VERIT: 1867 ASSERT(sarg->cs->vp != NULL); 1868 error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val, 1869 sarg->cs->cr, NULL); 1870 if (!error && (na->maxname != val)) 1871 error = -1; /* no match */ 1872 break; 1873 case NFS4ATTR_FREEIT: 1874 break; 1875 } 1876 return (error); 1877 } 1878 1879 /* ARGSUSED */ 1880 static int 1881 rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1882 union nfs4_attr_u *na) 1883 { 1884 int error = 0; 1885 1886 if (RFS4_MANDATTR_ONLY) 1887 return (ENOTSUP); 1888 1889 switch (cmd) { 1890 case NFS4ATTR_SUPPORTED: 1891 if (sarg->op == NFS4ATTR_SETIT) 1892 error = EINVAL; 1893 break; /* this attr is supported */ 1894 case NFS4ATTR_GETIT: 1895 na->maxread = rfs4_tsize(sarg->cs->req); 1896 break; 1897 case NFS4ATTR_SETIT: 1898 /* 1899 * read-only attr 1900 */ 1901 error = EINVAL; 1902 break; 1903 case NFS4ATTR_VERIT: 1904 if (na->maxread != rfs4_tsize(sarg->cs->req)) 1905 error = -1; /* no match */ 1906 break; 1907 case NFS4ATTR_FREEIT: 1908 break; 1909 } 1910 return (error); 1911 } 1912 1913 /* ARGSUSED */ 1914 static int 1915 rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1916 union nfs4_attr_u *na) 1917 { 1918 int error = 0; 1919 1920 if (RFS4_MANDATTR_ONLY) 1921 return (ENOTSUP); 1922 1923 switch (cmd) { 1924 case NFS4ATTR_SUPPORTED: 1925 if (sarg->op == NFS4ATTR_SETIT) 1926 error = EINVAL; 1927 break; /* this attr is supported */ 1928 case NFS4ATTR_GETIT: 1929 na->maxwrite = rfs4_tsize(sarg->cs->req); 1930 break; 1931 case NFS4ATTR_SETIT: 1932 /* 1933 * read-only attr 1934 */ 1935 error = EINVAL; 1936 break; 1937 case NFS4ATTR_VERIT: 1938 if (na->maxwrite != rfs4_tsize(sarg->cs->req)) 1939 error = -1; /* no match */ 1940 break; 1941 case NFS4ATTR_FREEIT: 1942 break; 1943 } 1944 return (error); 1945 } 1946 1947 /* ARGSUSED */ 1948 static int 1949 rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1950 union nfs4_attr_u *na) 1951 { 1952 return (ENOTSUP); 1953 } 1954 1955 /* ARGSUSED */ 1956 static int 1957 rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 1958 union nfs4_attr_u *na) 1959 { 1960 int error = 0; 1961 1962 if (RFS4_MANDATTR_ONLY) 1963 return (ENOTSUP); 1964 1965 switch (cmd) { 1966 case NFS4ATTR_SUPPORTED: 1967 break; /* this attr is supported */ 1968 case NFS4ATTR_GETIT: 1969 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MODE)) { 1970 error = -1; /* may be okay if rdattr_error */ 1971 break; 1972 } 1973 ASSERT(sarg->vap->va_mask & AT_MODE); 1974 na->mode = sarg->vap->va_mode; 1975 break; 1976 case NFS4ATTR_SETIT: 1977 ASSERT(sarg->vap->va_mask & AT_MODE); 1978 sarg->vap->va_mode = na->mode; 1979 /* 1980 * If the filesystem is exported with nosuid, then mask off 1981 * the setuid and setgid bits. 1982 */ 1983 if (sarg->cs->vp->v_type == VREG && 1984 (sarg->cs->exi->exi_export.ex_flags & EX_NOSUID)) 1985 sarg->vap->va_mode &= ~(VSUID | VSGID); 1986 break; 1987 case NFS4ATTR_VERIT: 1988 ASSERT(sarg->vap->va_mask & AT_MODE); 1989 if (sarg->vap->va_mode != na->mode) 1990 error = -1; /* no match */ 1991 break; 1992 case NFS4ATTR_FREEIT: 1993 break; 1994 } 1995 return (error); 1996 } 1997 1998 /* ARGSUSED */ 1999 static int 2000 rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2001 union nfs4_attr_u *na) 2002 { 2003 int error = 0; 2004 2005 if (RFS4_MANDATTR_ONLY) 2006 return (ENOTSUP); 2007 2008 switch (cmd) { 2009 case NFS4ATTR_SUPPORTED: 2010 if (sarg->op == NFS4ATTR_SETIT) 2011 error = EINVAL; 2012 break; /* this attr is supported */ 2013 case NFS4ATTR_GETIT: 2014 na->no_trunc = TRUE; 2015 break; 2016 case NFS4ATTR_SETIT: 2017 /* 2018 * read-only attr 2019 */ 2020 error = EINVAL; 2021 break; 2022 case NFS4ATTR_VERIT: 2023 if (!na->no_trunc) 2024 error = -1; /* no match */ 2025 break; 2026 case NFS4ATTR_FREEIT: 2027 break; 2028 } 2029 return (error); 2030 } 2031 2032 /* ARGSUSED */ 2033 static int 2034 rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2035 union nfs4_attr_u *na) 2036 { 2037 int error = 0; 2038 2039 if (RFS4_MANDATTR_ONLY) 2040 return (ENOTSUP); 2041 2042 switch (cmd) { 2043 case NFS4ATTR_SUPPORTED: 2044 if (sarg->op == NFS4ATTR_SETIT) 2045 error = EINVAL; 2046 break; /* this attr is supported */ 2047 case NFS4ATTR_GETIT: 2048 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NLINK)) { 2049 error = -1; /* may be okay if rdattr_error */ 2050 break; 2051 } 2052 ASSERT(sarg->vap->va_mask & AT_NLINK); 2053 na->numlinks = sarg->vap->va_nlink; 2054 break; 2055 case NFS4ATTR_SETIT: 2056 /* 2057 * read-only attr 2058 */ 2059 error = EINVAL; 2060 break; 2061 case NFS4ATTR_VERIT: 2062 ASSERT(sarg->vap->va_mask & AT_NLINK); 2063 if (sarg->vap->va_nlink != na->numlinks) 2064 error = -1; /* no match */ 2065 break; 2066 case NFS4ATTR_FREEIT: 2067 break; 2068 } 2069 return (error); 2070 } 2071 2072 /* ARGSUSED */ 2073 static int 2074 rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2075 union nfs4_attr_u *na) 2076 { 2077 int error = 0; 2078 uid_t uid; 2079 2080 if (RFS4_MANDATTR_ONLY) 2081 return (ENOTSUP); 2082 2083 switch (cmd) { 2084 case NFS4ATTR_SUPPORTED: 2085 break; /* this attr is supported */ 2086 case NFS4ATTR_GETIT: 2087 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_UID)) { 2088 error = -1; /* may be okay if rdattr_error */ 2089 break; 2090 } 2091 ASSERT(sarg->vap->va_mask & AT_UID); 2092 2093 /* 2094 * There are well defined polices for what happens on server- 2095 * side GETATTR when uid to attribute string conversion cannot 2096 * occur. Please refer to nfs4_idmap.c for details. 2097 */ 2098 error = nfs_idmap_uid_str(sarg->vap->va_uid, &na->owner, TRUE); 2099 switch (error) { 2100 case ECONNREFUSED: 2101 error = NFS4ERR_DELAY; 2102 break; 2103 default: 2104 break; 2105 } 2106 break; 2107 2108 case NFS4ATTR_SETIT: 2109 ASSERT(sarg->vap->va_mask & AT_UID); 2110 2111 /* 2112 * There are well defined policies for what happens on server- 2113 * side SETATTR of 'owner' when a "user@domain" mapping cannot 2114 * occur. Please refer to nfs4_idmap.c for details. 2115 * 2116 * Any other errors, such as the mapping not being found by 2117 * nfsmapid(8), and interrupted clnt_call, etc, will result 2118 * in NFS4ERR_BADOWNER. 2119 * 2120 * XXX need to return consistent errors, perhaps all 2121 * server side attribute routines should return NFS4ERR*. 2122 */ 2123 error = nfs_idmap_str_uid(&na->owner, &sarg->vap->va_uid, TRUE); 2124 switch (error) { 2125 case NFS4_OK: 2126 case ENOTSUP: 2127 /* 2128 * Ignore warning that we are the 2129 * nfsmapid (can't happen on srv) 2130 */ 2131 error = 0; 2132 MSG_PRT_DEBUG = FALSE; 2133 break; 2134 2135 case ECOMM: 2136 case ECONNREFUSED: 2137 if (!MSG_PRT_DEBUG) { 2138 /* 2139 * printed just once per daemon death, 2140 * inform the user and then stay silent 2141 */ 2142 cmn_err(CE_WARN, "!Unable to contact " 2143 "nfsmapid"); 2144 MSG_PRT_DEBUG = TRUE; 2145 } 2146 error = NFS4ERR_DELAY; 2147 break; 2148 2149 case EINVAL: 2150 error = NFS4ERR_INVAL; 2151 break; 2152 2153 default: 2154 error = NFS4ERR_BADOWNER; 2155 break; 2156 } 2157 break; 2158 2159 case NFS4ATTR_VERIT: 2160 ASSERT(sarg->vap->va_mask & AT_UID); 2161 error = nfs_idmap_str_uid(&na->owner, &uid, TRUE); 2162 /* 2163 * Ignore warning that we are the nfsmapid (can't happen on srv) 2164 */ 2165 if (error == ENOTSUP) 2166 error = 0; 2167 if (error) 2168 error = -1; /* no match */ 2169 else if (sarg->vap->va_uid != uid) 2170 error = -1; /* no match */ 2171 break; 2172 case NFS4ATTR_FREEIT: 2173 if (sarg->op == NFS4ATTR_GETIT) { 2174 if (na->owner.utf8string_val) { 2175 UTF8STRING_FREE(na->owner) 2176 bzero(&na->owner, sizeof (na->owner)); 2177 } 2178 } 2179 break; 2180 } 2181 return (error); 2182 } 2183 2184 /* ARGSUSED */ 2185 static int 2186 rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2187 union nfs4_attr_u *na) 2188 { 2189 int error = 0; 2190 gid_t gid; 2191 2192 if (RFS4_MANDATTR_ONLY) 2193 return (ENOTSUP); 2194 2195 switch (cmd) { 2196 case NFS4ATTR_SUPPORTED: 2197 break; /* this attr is supported */ 2198 case NFS4ATTR_GETIT: 2199 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_GID)) { 2200 error = -1; /* may be okay if rdattr_error */ 2201 break; 2202 } 2203 ASSERT(sarg->vap->va_mask & AT_GID); 2204 2205 /* 2206 * There are well defined polices for what happens on server- 2207 * side GETATTR when gid to attribute string conversion cannot 2208 * occur. Please refer to nfs4_idmap.c for details. 2209 */ 2210 error = nfs_idmap_gid_str(sarg->vap->va_gid, &na->owner_group, 2211 TRUE); 2212 switch (error) { 2213 case ECONNREFUSED: 2214 error = NFS4ERR_DELAY; 2215 break; 2216 default: 2217 break; 2218 } 2219 break; 2220 2221 case NFS4ATTR_SETIT: 2222 ASSERT(sarg->vap->va_mask & AT_GID); 2223 2224 /* 2225 * There are well defined policies for what happens on server- 2226 * side SETATTR of 'owner_group' when a "group@domain" mapping 2227 * cannot occur. Please refer to nfs4_idmap.c for details. 2228 * 2229 * Any other errors, such as the mapping not being found by 2230 * nfsmapid(8), and interrupted clnt_call, etc, will result 2231 * in NFS4ERR_BADOWNER. 2232 * 2233 * XXX need to return consistent errors, perhaps all 2234 * server side attribute routines should return NFS4ERR*. 2235 */ 2236 error = nfs_idmap_str_gid(&na->owner_group, &sarg->vap->va_gid, 2237 TRUE); 2238 switch (error) { 2239 case NFS4_OK: 2240 case ENOTSUP: 2241 /* 2242 * Ignore warning that we are the 2243 * nfsmapid (can't happen on srv) 2244 */ 2245 error = 0; 2246 MSG_PRT_DEBUG = FALSE; 2247 break; 2248 2249 case ECOMM: 2250 case ECONNREFUSED: 2251 if (!MSG_PRT_DEBUG) { 2252 /* 2253 * printed just once per daemon death, 2254 * inform the user and then stay silent 2255 */ 2256 cmn_err(CE_WARN, "!Unable to contact " 2257 "nfsmapid"); 2258 MSG_PRT_DEBUG = TRUE; 2259 } 2260 error = NFS4ERR_DELAY; 2261 break; 2262 2263 case EINVAL: 2264 error = NFS4ERR_INVAL; 2265 break; 2266 2267 default: 2268 error = NFS4ERR_BADOWNER; 2269 break; 2270 } 2271 break; 2272 2273 case NFS4ATTR_VERIT: 2274 ASSERT(sarg->vap->va_mask & AT_GID); 2275 error = nfs_idmap_str_gid(&na->owner_group, &gid, TRUE); 2276 /* 2277 * Ignore warning that we are the nfsmapid (can't happen on srv) 2278 */ 2279 if (error == ENOTSUP) 2280 error = 0; 2281 if (error) 2282 error = -1; /* no match */ 2283 else if (sarg->vap->va_gid != gid) 2284 error = -1; /* no match */ 2285 break; 2286 case NFS4ATTR_FREEIT: 2287 if (sarg->op == NFS4ATTR_GETIT) { 2288 if (na->owner_group.utf8string_val) { 2289 UTF8STRING_FREE(na->owner_group) 2290 bzero(&na->owner_group, 2291 sizeof (na->owner_group)); 2292 } 2293 } 2294 break; 2295 } 2296 return (error); 2297 } 2298 2299 /* XXX - quota attributes should be supportable on Solaris 2 */ 2300 /* ARGSUSED */ 2301 static int 2302 rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2303 union nfs4_attr_u *na) 2304 { 2305 return (ENOTSUP); 2306 } 2307 2308 /* ARGSUSED */ 2309 static int 2310 rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2311 union nfs4_attr_u *na) 2312 { 2313 return (ENOTSUP); 2314 } 2315 2316 /* ARGSUSED */ 2317 static int 2318 rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2319 union nfs4_attr_u *na) 2320 { 2321 return (ENOTSUP); 2322 } 2323 2324 /* ARGSUSED */ 2325 static int 2326 rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2327 union nfs4_attr_u *na) 2328 { 2329 int error = 0; 2330 2331 if (RFS4_MANDATTR_ONLY) 2332 return (ENOTSUP); 2333 2334 switch (cmd) { 2335 case NFS4ATTR_SUPPORTED: 2336 if (sarg->op == NFS4ATTR_SETIT) 2337 error = EINVAL; 2338 break; /* this attr is supported */ 2339 case NFS4ATTR_GETIT: 2340 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_RDEV)) { 2341 error = -1; /* may be okay if rdattr_error */ 2342 break; 2343 } 2344 ASSERT(sarg->vap->va_mask & AT_RDEV); 2345 na->rawdev.specdata1 = (uint32)getmajor(sarg->vap->va_rdev); 2346 na->rawdev.specdata2 = (uint32)getminor(sarg->vap->va_rdev); 2347 break; 2348 case NFS4ATTR_SETIT: 2349 /* 2350 * read-only attr 2351 */ 2352 error = EINVAL; 2353 break; 2354 case NFS4ATTR_VERIT: 2355 ASSERT(sarg->vap->va_mask & AT_RDEV); 2356 if ((na->rawdev.specdata1 != 2357 (uint32)getmajor(sarg->vap->va_rdev)) || 2358 (na->rawdev.specdata2 != 2359 (uint32)getminor(sarg->vap->va_rdev))) 2360 error = -1; /* no match */ 2361 break; 2362 case NFS4ATTR_FREEIT: 2363 break; 2364 } 2365 return (error); 2366 } 2367 2368 /* ARGSUSED */ 2369 static int 2370 rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2371 union nfs4_attr_u *na) 2372 { 2373 int error = 0; 2374 2375 if (RFS4_MANDATTR_ONLY) 2376 return (ENOTSUP); 2377 2378 switch (cmd) { 2379 case NFS4ATTR_SUPPORTED: 2380 if (sarg->op == NFS4ATTR_SETIT) 2381 error = EINVAL; 2382 break; /* this attr is supported */ 2383 case NFS4ATTR_GETIT: 2384 if (sarg->rdattr_error && (sarg->sbp == NULL)) { 2385 error = -1; /* may be okay if rdattr_error */ 2386 break; 2387 } 2388 ASSERT(sarg->sbp != NULL); 2389 if (sarg->sbp->f_bavail != (fsblkcnt64_t)-1) { 2390 na->space_avail = 2391 (fattr4_space_avail) sarg->sbp->f_frsize * 2392 (fattr4_space_avail) sarg->sbp->f_bavail; 2393 } else { 2394 na->space_avail = 2395 (fattr4_space_avail) sarg->sbp->f_bavail; 2396 } 2397 break; 2398 case NFS4ATTR_SETIT: 2399 /* 2400 * read-only attr 2401 */ 2402 error = EINVAL; 2403 break; 2404 case NFS4ATTR_VERIT: 2405 ASSERT(sarg->sbp != NULL); 2406 if (sarg->sbp->f_bavail != na->space_avail) 2407 error = -1; /* no match */ 2408 break; 2409 case NFS4ATTR_FREEIT: 2410 break; 2411 } 2412 return (error); 2413 } 2414 2415 /* ARGSUSED */ 2416 static int 2417 rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2418 union nfs4_attr_u *na) 2419 { 2420 int error = 0; 2421 2422 if (RFS4_MANDATTR_ONLY) 2423 return (ENOTSUP); 2424 2425 switch (cmd) { 2426 case NFS4ATTR_SUPPORTED: 2427 if (sarg->op == NFS4ATTR_SETIT) 2428 error = EINVAL; 2429 break; /* this attr is supported */ 2430 case NFS4ATTR_GETIT: 2431 if (sarg->rdattr_error && (sarg->sbp == NULL)) { 2432 error = -1; /* may be okay if rdattr_error */ 2433 break; 2434 } 2435 ASSERT(sarg->sbp != NULL); 2436 if (sarg->sbp->f_bfree != (fsblkcnt64_t)-1) { 2437 na->space_free = 2438 (fattr4_space_free) sarg->sbp->f_frsize * 2439 (fattr4_space_free) sarg->sbp->f_bfree; 2440 } else { 2441 na->space_free = 2442 (fattr4_space_free) sarg->sbp->f_bfree; 2443 } 2444 break; 2445 case NFS4ATTR_SETIT: 2446 /* 2447 * read-only attr 2448 */ 2449 error = EINVAL; 2450 break; 2451 case NFS4ATTR_VERIT: 2452 ASSERT(sarg->sbp != NULL); 2453 if (sarg->sbp->f_bfree != na->space_free) 2454 error = -1; /* no match */ 2455 break; 2456 case NFS4ATTR_FREEIT: 2457 break; 2458 } 2459 return (error); 2460 } 2461 2462 /* ARGSUSED */ 2463 static int 2464 rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2465 union nfs4_attr_u *na) 2466 { 2467 int error = 0; 2468 2469 if (RFS4_MANDATTR_ONLY) 2470 return (ENOTSUP); 2471 2472 switch (cmd) { 2473 case NFS4ATTR_SUPPORTED: 2474 if (sarg->op == NFS4ATTR_SETIT) 2475 error = EINVAL; 2476 break; /* this attr is supported */ 2477 case NFS4ATTR_GETIT: 2478 if (sarg->rdattr_error_req && (sarg->sbp == NULL)) { 2479 error = -1; /* may be okay if rdattr_error */ 2480 break; 2481 } 2482 ASSERT(sarg->sbp != NULL); 2483 if (sarg->sbp->f_blocks != (fsblkcnt64_t)-1) { 2484 na->space_total = 2485 (fattr4_space_total) sarg->sbp->f_frsize * 2486 (fattr4_space_total) sarg->sbp->f_blocks; 2487 } else { 2488 na->space_total = 2489 (fattr4_space_total) sarg->sbp->f_blocks; 2490 } 2491 break; 2492 case NFS4ATTR_SETIT: 2493 /* 2494 * read-only attr 2495 */ 2496 error = EINVAL; 2497 break; 2498 case NFS4ATTR_VERIT: 2499 ASSERT(sarg->sbp != NULL); 2500 if (sarg->sbp->f_blocks != na->space_total) 2501 error = -1; /* no match */ 2502 break; 2503 case NFS4ATTR_FREEIT: 2504 break; 2505 } 2506 return (error); 2507 } 2508 2509 /* ARGSUSED */ 2510 static int 2511 rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2512 union nfs4_attr_u *na) 2513 { 2514 int error = 0; 2515 2516 if (RFS4_MANDATTR_ONLY) 2517 return (ENOTSUP); 2518 2519 switch (cmd) { 2520 case NFS4ATTR_SUPPORTED: 2521 if (sarg->op == NFS4ATTR_SETIT) 2522 error = EINVAL; 2523 break; /* this attr is supported */ 2524 case NFS4ATTR_GETIT: 2525 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NBLOCKS)) { 2526 error = -1; /* may be okay if rdattr_error */ 2527 break; 2528 } 2529 ASSERT(sarg->vap->va_mask & AT_NBLOCKS); 2530 na->space_used = (fattr4_space_used) DEV_BSIZE * 2531 (fattr4_space_used) sarg->vap->va_nblocks; 2532 break; 2533 case NFS4ATTR_SETIT: 2534 /* 2535 * read-only attr 2536 */ 2537 error = EINVAL; 2538 break; 2539 case NFS4ATTR_VERIT: 2540 ASSERT(sarg->vap->va_mask & AT_NBLOCKS); 2541 if (sarg->vap->va_nblocks != na->space_used) 2542 error = -1; /* no match */ 2543 break; 2544 case NFS4ATTR_FREEIT: 2545 break; 2546 } 2547 return (error); 2548 } 2549 2550 /* ARGSUSED */ 2551 static int 2552 rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2553 union nfs4_attr_u *na) 2554 { 2555 return (ENOTSUP); 2556 } 2557 2558 /* ARGSUSED */ 2559 static int 2560 rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2561 union nfs4_attr_u *na) 2562 { 2563 int error = 0; 2564 timestruc_t atime; 2565 2566 if (RFS4_MANDATTR_ONLY) 2567 return (ENOTSUP); 2568 2569 switch (cmd) { 2570 case NFS4ATTR_SUPPORTED: 2571 if (sarg->op == NFS4ATTR_SETIT) 2572 error = EINVAL; 2573 break; /* this attr is supported */ 2574 case NFS4ATTR_GETIT: 2575 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_ATIME)) { 2576 error = -1; /* may be okay if rdattr_error */ 2577 break; 2578 } 2579 ASSERT(sarg->vap->va_mask & AT_ATIME); 2580 error = nfs4_time_vton(&sarg->vap->va_atime, &na->time_access); 2581 break; 2582 case NFS4ATTR_SETIT: 2583 /* 2584 * read-only attr 2585 */ 2586 error = EINVAL; 2587 break; 2588 case NFS4ATTR_VERIT: 2589 ASSERT(sarg->vap->va_mask & AT_ATIME); 2590 error = nfs4_time_ntov(&na->time_access, &atime); 2591 if (error) 2592 break; 2593 if (bcmp(&atime, &sarg->vap->va_atime, sizeof (atime))) 2594 error = -1; /* no match */ 2595 break; 2596 case NFS4ATTR_FREEIT: 2597 break; 2598 } 2599 return (error); 2600 } 2601 2602 /* 2603 * XXX - need to support the setting of access time 2604 */ 2605 /* ARGSUSED */ 2606 static int 2607 rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2608 union nfs4_attr_u *na) 2609 { 2610 int error = 0; 2611 settime4 *ta; 2612 2613 if (RFS4_MANDATTR_ONLY) 2614 return (ENOTSUP); 2615 2616 switch (cmd) { 2617 case NFS4ATTR_SUPPORTED: 2618 if ((sarg->op == NFS4ATTR_GETIT) || 2619 (sarg->op == NFS4ATTR_VERIT)) 2620 error = EINVAL; 2621 break; /* this attr is supported */ 2622 case NFS4ATTR_GETIT: 2623 case NFS4ATTR_VERIT: 2624 /* 2625 * write only attr 2626 */ 2627 error = EINVAL; 2628 break; 2629 case NFS4ATTR_SETIT: 2630 ASSERT(sarg->vap->va_mask & AT_ATIME); 2631 /* 2632 * Set access time (by server or by client) 2633 */ 2634 ta = &na->time_access_set; 2635 if (ta->set_it == SET_TO_CLIENT_TIME4) { 2636 error = nfs4_time_ntov(&ta->time, &sarg->vap->va_atime); 2637 } else if (ta->set_it == SET_TO_SERVER_TIME4) { 2638 gethrestime(&sarg->vap->va_atime); 2639 } else { 2640 error = EINVAL; 2641 } 2642 break; 2643 case NFS4ATTR_FREEIT: 2644 break; 2645 } 2646 return (error); 2647 } 2648 2649 /* ARGSUSED */ 2650 static int 2651 rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2652 union nfs4_attr_u *na) 2653 { 2654 return (ENOTSUP); 2655 } 2656 2657 /* ARGSUSED */ 2658 static int 2659 rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2660 union nfs4_attr_u *na) 2661 { 2662 return (ENOTSUP); 2663 } 2664 2665 /* ARGSUSED */ 2666 static int 2667 rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2668 union nfs4_attr_u *na) 2669 { 2670 int error = 0; 2671 2672 if (RFS4_MANDATTR_ONLY) 2673 return (ENOTSUP); 2674 2675 switch (cmd) { 2676 case NFS4ATTR_SUPPORTED: 2677 if (sarg->op == NFS4ATTR_SETIT) 2678 error = EINVAL; 2679 break; /* this attr is supported */ 2680 case NFS4ATTR_GETIT: 2681 na->time_delta.seconds = 0; 2682 na->time_delta.nseconds = 1000; 2683 break; 2684 case NFS4ATTR_SETIT: 2685 /* 2686 * write only attr 2687 */ 2688 error = EINVAL; 2689 break; 2690 case NFS4ATTR_VERIT: 2691 if ((na->time_delta.seconds != 0) || 2692 (na->time_delta.nseconds != 1000)) 2693 error = -1; /* no match */ 2694 break; 2695 case NFS4ATTR_FREEIT: 2696 break; 2697 } 2698 return (error); 2699 } 2700 2701 /* ARGSUSED */ 2702 static int 2703 rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2704 union nfs4_attr_u *na) 2705 { 2706 int error = 0; 2707 timestruc_t ctime; 2708 2709 if (RFS4_MANDATTR_ONLY) 2710 return (ENOTSUP); 2711 2712 switch (cmd) { 2713 case NFS4ATTR_SUPPORTED: 2714 if (sarg->op == NFS4ATTR_SETIT) 2715 error = EINVAL; 2716 break; /* this attr is supported */ 2717 case NFS4ATTR_GETIT: 2718 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_CTIME)) { 2719 error = -1; /* may be okay if rdattr_error */ 2720 break; 2721 } 2722 ASSERT(sarg->vap->va_mask & AT_CTIME); 2723 error = nfs4_time_vton(&sarg->vap->va_ctime, 2724 &na->time_metadata); 2725 break; 2726 case NFS4ATTR_SETIT: 2727 /* 2728 * read-only attr 2729 */ 2730 error = EINVAL; 2731 break; 2732 case NFS4ATTR_VERIT: 2733 ASSERT(sarg->vap->va_mask & AT_CTIME); 2734 error = nfs4_time_ntov(&na->time_metadata, &ctime); 2735 if (error) 2736 break; 2737 if (bcmp(&ctime, &sarg->vap->va_ctime, sizeof (ctime))) 2738 error = -1; /* no match */ 2739 break; 2740 case NFS4ATTR_FREEIT: 2741 break; 2742 } 2743 return (error); 2744 } 2745 2746 /* ARGSUSED */ 2747 static int 2748 rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2749 union nfs4_attr_u *na) 2750 { 2751 int error = 0; 2752 timestruc_t mtime; 2753 2754 if (RFS4_MANDATTR_ONLY) 2755 return (ENOTSUP); 2756 2757 switch (cmd) { 2758 case NFS4ATTR_SUPPORTED: 2759 if (sarg->op == NFS4ATTR_SETIT) 2760 error = EINVAL; 2761 break; /* this attr is supported */ 2762 case NFS4ATTR_GETIT: 2763 if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MTIME)) { 2764 error = -1; /* may be okay if rdattr_error */ 2765 break; 2766 } 2767 ASSERT(sarg->vap->va_mask & AT_MTIME); 2768 error = nfs4_time_vton(&sarg->vap->va_mtime, &na->time_modify); 2769 break; 2770 case NFS4ATTR_SETIT: 2771 /* 2772 * read-only attr 2773 */ 2774 error = EINVAL; 2775 break; 2776 case NFS4ATTR_VERIT: 2777 ASSERT(sarg->vap->va_mask & AT_MTIME); 2778 error = nfs4_time_ntov(&na->time_modify, &mtime); 2779 if (error) 2780 break; 2781 if (bcmp(&mtime, &sarg->vap->va_mtime, sizeof (mtime))) 2782 error = -1; /* no match */ 2783 break; 2784 case NFS4ATTR_FREEIT: 2785 break; 2786 } 2787 return (error); 2788 } 2789 2790 /* 2791 * XXX - need to add support for setting modify time 2792 */ 2793 /* ARGSUSED */ 2794 static int 2795 rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg, 2796 union nfs4_attr_u *na) 2797 { 2798 int error = 0; 2799 settime4 *tm; 2800 2801 if (RFS4_MANDATTR_ONLY) 2802 return (ENOTSUP); 2803 2804 switch (cmd) { 2805 case NFS4ATTR_SUPPORTED: 2806 if ((sarg->op == NFS4ATTR_GETIT) || 2807 (sarg->op == NFS4ATTR_VERIT)) 2808 error = EINVAL; 2809 break; /* this attr is supported */ 2810 case NFS4ATTR_GETIT: 2811 case NFS4ATTR_VERIT: 2812 /* 2813 * write only attr 2814 */ 2815 error = EINVAL; 2816 break; 2817 case NFS4ATTR_SETIT: 2818 ASSERT(sarg->vap->va_mask & AT_MTIME); 2819 /* 2820 * Set modify time (by server or by client) 2821 */ 2822 tm = &na->time_modify_set; 2823 if (tm->set_it == SET_TO_CLIENT_TIME4) { 2824 error = nfs4_time_ntov(&tm->time, &sarg->vap->va_mtime); 2825 sarg->flag = ATTR_UTIME; 2826 } else if (tm->set_it == SET_TO_SERVER_TIME4) { 2827 gethrestime(&sarg->vap->va_mtime); 2828 } else { 2829 error = EINVAL; 2830 } 2831 break; 2832 case NFS4ATTR_FREEIT: 2833 break; 2834 } 2835 return (error); 2836 } 2837 2838 /* ARGSUSED */ 2839 static int 2840 rfs4_fattr4_suppattr_exclcreat(nfs4_attr_cmd_t cmd, 2841 struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na) 2842 { 2843 int error = 0; 2844 2845 /* Not supported for nfs4.0 */ 2846 if (sarg->cs->minorversion == 0) 2847 return (ENOTSUP); 2848 2849 switch (cmd) { 2850 case NFS4ATTR_SUPPORTED: 2851 if (sarg->op == NFS4ATTR_SETIT) 2852 error = EINVAL; 2853 break; /* this attr is supported */ 2854 case NFS4ATTR_GETIT: 2855 na->supp_exclcreat = RFS4_SUPPATTR_EXCLCREAT; 2856 break; 2857 case NFS4ATTR_SETIT: 2858 /* 2859 * read-only attr 2860 */ 2861 error = EINVAL; 2862 break; 2863 case NFS4ATTR_VERIT: 2864 if (na->supp_exclcreat != RFS4_SUPPATTR_EXCLCREAT) 2865 error = -1; /* no match */ 2866 break; 2867 case NFS4ATTR_FREEIT: 2868 break; 2869 } 2870 return (error); 2871 } 2872 2873 static void 2874 rfs4_ntov_init(void) 2875 { 2876 /* index must be same as corresponding FATTR4_* define */ 2877 nfs4_ntov_map[0].sv_getit = rfs4_fattr4_supported_attrs; 2878 nfs4_ntov_map[1].sv_getit = rfs4_fattr4_type; 2879 nfs4_ntov_map[2].sv_getit = rfs4_fattr4_fh_expire_type; 2880 nfs4_ntov_map[3].sv_getit = rfs4_fattr4_change; 2881 nfs4_ntov_map[4].sv_getit = rfs4_fattr4_size; 2882 nfs4_ntov_map[5].sv_getit = rfs4_fattr4_link_support; 2883 nfs4_ntov_map[6].sv_getit = rfs4_fattr4_symlink_support; 2884 nfs4_ntov_map[7].sv_getit = rfs4_fattr4_named_attr; 2885 nfs4_ntov_map[8].sv_getit = rfs4_fattr4_fsid; 2886 nfs4_ntov_map[9].sv_getit = rfs4_fattr4_unique_handles; 2887 nfs4_ntov_map[10].sv_getit = rfs4_fattr4_lease_time; 2888 nfs4_ntov_map[11].sv_getit = rfs4_fattr4_rdattr_error; 2889 nfs4_ntov_map[12].sv_getit = rfs4_fattr4_acl; 2890 nfs4_ntov_map[13].sv_getit = rfs4_fattr4_aclsupport; 2891 nfs4_ntov_map[14].sv_getit = rfs4_fattr4_archive; 2892 nfs4_ntov_map[15].sv_getit = rfs4_fattr4_cansettime; 2893 nfs4_ntov_map[16].sv_getit = rfs4_fattr4_case_insensitive; 2894 nfs4_ntov_map[17].sv_getit = rfs4_fattr4_case_preserving; 2895 nfs4_ntov_map[18].sv_getit = rfs4_fattr4_chown_restricted; 2896 nfs4_ntov_map[19].sv_getit = rfs4_fattr4_filehandle; 2897 nfs4_ntov_map[20].sv_getit = rfs4_fattr4_fileid; 2898 nfs4_ntov_map[21].sv_getit = rfs4_fattr4_files_avail; 2899 nfs4_ntov_map[22].sv_getit = rfs4_fattr4_files_free; 2900 nfs4_ntov_map[23].sv_getit = rfs4_fattr4_files_total; 2901 nfs4_ntov_map[24].sv_getit = rfs4_fattr4_fs_locations; 2902 nfs4_ntov_map[25].sv_getit = rfs4_fattr4_hidden; 2903 nfs4_ntov_map[26].sv_getit = rfs4_fattr4_homogeneous; 2904 nfs4_ntov_map[27].sv_getit = rfs4_fattr4_maxfilesize; 2905 nfs4_ntov_map[28].sv_getit = rfs4_fattr4_maxlink; 2906 nfs4_ntov_map[29].sv_getit = rfs4_fattr4_maxname; 2907 nfs4_ntov_map[30].sv_getit = rfs4_fattr4_maxread; 2908 nfs4_ntov_map[31].sv_getit = rfs4_fattr4_maxwrite; 2909 nfs4_ntov_map[32].sv_getit = rfs4_fattr4_mimetype; 2910 nfs4_ntov_map[33].sv_getit = rfs4_fattr4_mode; 2911 nfs4_ntov_map[34].sv_getit = rfs4_fattr4_no_trunc; 2912 nfs4_ntov_map[35].sv_getit = rfs4_fattr4_numlinks; 2913 nfs4_ntov_map[36].sv_getit = rfs4_fattr4_owner; 2914 nfs4_ntov_map[37].sv_getit = rfs4_fattr4_owner_group; 2915 nfs4_ntov_map[38].sv_getit = rfs4_fattr4_quota_avail_hard; 2916 nfs4_ntov_map[39].sv_getit = rfs4_fattr4_quota_avail_soft; 2917 nfs4_ntov_map[40].sv_getit = rfs4_fattr4_quota_used; 2918 nfs4_ntov_map[41].sv_getit = rfs4_fattr4_rawdev; 2919 nfs4_ntov_map[42].sv_getit = rfs4_fattr4_space_avail; 2920 nfs4_ntov_map[43].sv_getit = rfs4_fattr4_space_free; 2921 nfs4_ntov_map[44].sv_getit = rfs4_fattr4_space_total; 2922 nfs4_ntov_map[45].sv_getit = rfs4_fattr4_space_used; 2923 nfs4_ntov_map[46].sv_getit = rfs4_fattr4_system; 2924 nfs4_ntov_map[47].sv_getit = rfs4_fattr4_time_access; 2925 nfs4_ntov_map[48].sv_getit = rfs4_fattr4_time_access_set; 2926 nfs4_ntov_map[49].sv_getit = rfs4_fattr4_time_backup; 2927 nfs4_ntov_map[50].sv_getit = rfs4_fattr4_time_create; 2928 nfs4_ntov_map[51].sv_getit = rfs4_fattr4_time_delta; 2929 nfs4_ntov_map[52].sv_getit = rfs4_fattr4_time_metadata; 2930 nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify; 2931 nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set; 2932 nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid; 2933 nfs4_ntov_map[56].sv_getit = rfs4_fattr4_suppattr_exclcreat; 2934 } 2935