1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2051 prabahar * Common Development and Distribution License (the "License"). 6 2051 prabahar * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 0 stevel /* All Rights Reserved */ 23 0 stevel 24 0 stevel 25 0 stevel /* 26 9749 Tim * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27 0 stevel * Use is subject to license terms. 28 0 stevel */ 29 0 stevel 30 0 stevel /* 31 0 stevel * Generic vnode operations. 32 0 stevel */ 33 0 stevel #include <sys/types.h> 34 0 stevel #include <sys/param.h> 35 0 stevel #include <sys/systm.h> 36 0 stevel #include <sys/errno.h> 37 0 stevel #include <sys/fcntl.h> 38 0 stevel #include <sys/flock.h> 39 0 stevel #include <sys/statvfs.h> 40 0 stevel #include <sys/vfs.h> 41 0 stevel #include <sys/vnode.h> 42 0 stevel #include <sys/proc.h> 43 0 stevel #include <sys/user.h> 44 0 stevel #include <sys/unistd.h> 45 0 stevel #include <sys/cred.h> 46 0 stevel #include <sys/poll.h> 47 0 stevel #include <sys/debug.h> 48 0 stevel #include <sys/cmn_err.h> 49 0 stevel #include <sys/stream.h> 50 0 stevel #include <fs/fs_subr.h> 51 10793 dai #include <fs/fs_reparse.h> 52 10793 dai #include <sys/door.h> 53 0 stevel #include <sys/acl.h> 54 0 stevel #include <sys/share.h> 55 0 stevel #include <sys/file.h> 56 0 stevel #include <sys/kmem.h> 57 0 stevel #include <sys/file.h> 58 0 stevel #include <sys/nbmlock.h> 59 789 ahrens #include <acl/acl_common.h> 60 10793 dai #include <sys/pathname.h> 61 0 stevel 62 0 stevel static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *); 63 2051 prabahar 64 2051 prabahar /* 65 2051 prabahar * Tunable to limit the number of retry to recover from STALE error. 66 2051 prabahar */ 67 2051 prabahar int fs_estale_retry = 5; 68 10793 dai 69 10793 dai /* 70 10793 dai * supports for reparse point door upcall 71 10793 dai */ 72 10793 dai static door_handle_t reparsed_door; 73 10793 dai static kmutex_t reparsed_door_lock; 74 0 stevel 75 0 stevel /* 76 0 stevel * The associated operation is not supported by the file system. 77 0 stevel */ 78 0 stevel int 79 0 stevel fs_nosys() 80 0 stevel { 81 0 stevel return (ENOSYS); 82 0 stevel } 83 0 stevel 84 0 stevel /* 85 0 stevel * The associated operation is invalid (on this vnode). 86 0 stevel */ 87 0 stevel int 88 0 stevel fs_inval() 89 0 stevel { 90 0 stevel return (EINVAL); 91 0 stevel } 92 0 stevel 93 0 stevel /* 94 0 stevel * The associated operation is valid only for directories. 95 0 stevel */ 96 0 stevel int 97 0 stevel fs_notdir() 98 0 stevel { 99 0 stevel return (ENOTDIR); 100 0 stevel } 101 0 stevel 102 0 stevel /* 103 0 stevel * Free the file system specific resources. For the file systems that 104 0 stevel * do not support the forced unmount, it will be a nop function. 105 0 stevel */ 106 0 stevel 107 0 stevel /*ARGSUSED*/ 108 0 stevel void 109 0 stevel fs_freevfs(vfs_t *vfsp) 110 0 stevel { 111 0 stevel } 112 0 stevel 113 0 stevel /* ARGSUSED */ 114 0 stevel int 115 0 stevel fs_nosys_map(struct vnode *vp, 116 0 stevel offset_t off, 117 0 stevel struct as *as, 118 0 stevel caddr_t *addrp, 119 0 stevel size_t len, 120 0 stevel uchar_t prot, 121 0 stevel uchar_t maxprot, 122 0 stevel uint_t flags, 123 5331 amw struct cred *cr, 124 5331 amw caller_context_t *ct) 125 0 stevel { 126 0 stevel return (ENOSYS); 127 0 stevel } 128 0 stevel 129 0 stevel /* ARGSUSED */ 130 0 stevel int 131 0 stevel fs_nosys_addmap(struct vnode *vp, 132 0 stevel offset_t off, 133 0 stevel struct as *as, 134 0 stevel caddr_t addr, 135 0 stevel size_t len, 136 0 stevel uchar_t prot, 137 0 stevel uchar_t maxprot, 138 0 stevel uint_t flags, 139 5331 amw struct cred *cr, 140 5331 amw caller_context_t *ct) 141 0 stevel { 142 0 stevel return (ENOSYS); 143 0 stevel } 144 0 stevel 145 0 stevel /* ARGSUSED */ 146 0 stevel int 147 0 stevel fs_nosys_poll(vnode_t *vp, 148 0 stevel register short events, 149 0 stevel int anyyet, 150 0 stevel register short *reventsp, 151 5331 amw struct pollhead **phpp, 152 5331 amw caller_context_t *ct) 153 0 stevel { 154 0 stevel return (ENOSYS); 155 0 stevel } 156 0 stevel 157 0 stevel 158 0 stevel /* 159 0 stevel * The file system has nothing to sync to disk. However, the 160 0 stevel * VFS_SYNC operation must not fail. 161 0 stevel */ 162 0 stevel /* ARGSUSED */ 163 0 stevel int 164 0 stevel fs_sync(struct vfs *vfspp, short flag, cred_t *cr) 165 5331 amw { 166 5331 amw return (0); 167 5331 amw } 168 5331 amw 169 5331 amw /* 170 5331 amw * Does nothing but VOP_FSYNC must not fail. 171 5331 amw */ 172 5331 amw /* ARGSUSED */ 173 5331 amw int 174 5331 amw fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 175 5331 amw { 176 5331 amw return (0); 177 5331 amw } 178 5331 amw 179 5331 amw /* 180 5331 amw * Does nothing but VOP_PUTPAGE must not fail. 181 5331 amw */ 182 5331 amw /* ARGSUSED */ 183 5331 amw int 184 5331 amw fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr, 185 5331 amw caller_context_t *ctp) 186 5331 amw { 187 5331 amw return (0); 188 5331 amw } 189 5331 amw 190 5331 amw /* 191 5331 amw * Does nothing but VOP_IOCTL must not fail. 192 5331 amw */ 193 5331 amw /* ARGSUSED */ 194 5331 amw int 195 5331 amw fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred, 196 5331 amw int *rvalp) 197 0 stevel { 198 0 stevel return (0); 199 0 stevel } 200 0 stevel 201 0 stevel /* 202 0 stevel * Read/write lock/unlock. Does nothing. 203 0 stevel */ 204 0 stevel /* ARGSUSED */ 205 0 stevel int 206 0 stevel fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 207 0 stevel { 208 0 stevel return (-1); 209 0 stevel } 210 0 stevel 211 0 stevel /* ARGSUSED */ 212 0 stevel void 213 0 stevel fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 214 0 stevel { 215 0 stevel } 216 0 stevel 217 0 stevel /* 218 0 stevel * Compare two vnodes. 219 0 stevel */ 220 5331 amw /*ARGSUSED2*/ 221 0 stevel int 222 5331 amw fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct) 223 0 stevel { 224 0 stevel return (vp1 == vp2); 225 0 stevel } 226 0 stevel 227 0 stevel /* 228 0 stevel * No-op seek operation. 229 0 stevel */ 230 0 stevel /* ARGSUSED */ 231 0 stevel int 232 5331 amw fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 233 0 stevel { 234 0 stevel return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0); 235 0 stevel } 236 0 stevel 237 0 stevel /* 238 0 stevel * File and record locking. 239 0 stevel */ 240 0 stevel /* ARGSUSED */ 241 0 stevel int 242 0 stevel fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 243 5331 amw offset_t offset, flk_callback_t *flk_cbp, cred_t *cr, 244 5331 amw caller_context_t *ct) 245 0 stevel { 246 0 stevel int frcmd; 247 0 stevel int nlmid; 248 0 stevel int error = 0; 249 0 stevel flk_callback_t serialize_callback; 250 0 stevel int serialize = 0; 251 5331 amw v_mode_t mode; 252 0 stevel 253 0 stevel switch (cmd) { 254 0 stevel 255 0 stevel case F_GETLK: 256 0 stevel case F_O_GETLK: 257 0 stevel if (flag & F_REMOTELOCK) { 258 0 stevel frcmd = RCMDLCK; 259 5331 amw } else if (flag & F_PXFSLOCK) { 260 5331 amw frcmd = PCMDLCK; 261 5331 amw } else { 262 5331 amw frcmd = 0; 263 5331 amw bfp->l_pid = ttoproc(curthread)->p_pid; 264 5331 amw bfp->l_sysid = 0; 265 0 stevel } 266 0 stevel break; 267 0 stevel 268 0 stevel case F_SETLK_NBMAND: 269 0 stevel /* 270 0 stevel * Are NBMAND locks allowed on this file? 271 0 stevel */ 272 0 stevel if (!vp->v_vfsp || 273 0 stevel !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 274 0 stevel error = EINVAL; 275 0 stevel goto done; 276 0 stevel } 277 0 stevel if (vp->v_type != VREG) { 278 0 stevel error = EINVAL; 279 0 stevel goto done; 280 0 stevel } 281 0 stevel /*FALLTHROUGH*/ 282 0 stevel 283 0 stevel case F_SETLK: 284 5331 amw if (flag & F_REMOTELOCK) { 285 5331 amw frcmd = SETFLCK|RCMDLCK; 286 5331 amw } else if (flag & F_PXFSLOCK) { 287 5331 amw frcmd = SETFLCK|PCMDLCK; 288 5331 amw } else { 289 5331 amw frcmd = SETFLCK; 290 5331 amw bfp->l_pid = ttoproc(curthread)->p_pid; 291 5331 amw bfp->l_sysid = 0; 292 5331 amw } 293 5331 amw if (cmd == F_SETLK_NBMAND && 294 5331 amw (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) { 295 5331 amw frcmd |= NBMLCK; 296 5331 amw } 297 7961 Natalie 298 0 stevel if (nbl_need_check(vp)) { 299 0 stevel nbl_start_crit(vp, RW_WRITER); 300 0 stevel serialize = 1; 301 5331 amw if (frcmd & NBMLCK) { 302 5331 amw mode = (bfp->l_type == F_RDLCK) ? 303 5331 amw V_READ : V_RDANDWR; 304 5331 amw if (vn_is_mapped(vp, mode)) { 305 5331 amw error = EAGAIN; 306 5331 amw goto done; 307 5331 amw } 308 0 stevel } 309 0 stevel } 310 0 stevel break; 311 0 stevel 312 0 stevel case F_SETLKW: 313 5331 amw if (flag & F_REMOTELOCK) { 314 5331 amw frcmd = SETFLCK|SLPFLCK|RCMDLCK; 315 5331 amw } else if (flag & F_PXFSLOCK) { 316 5331 amw frcmd = SETFLCK|SLPFLCK|PCMDLCK; 317 5331 amw } else { 318 5331 amw frcmd = SETFLCK|SLPFLCK; 319 5331 amw bfp->l_pid = ttoproc(curthread)->p_pid; 320 5331 amw bfp->l_sysid = 0; 321 5331 amw } 322 7961 Natalie 323 0 stevel if (nbl_need_check(vp)) { 324 0 stevel nbl_start_crit(vp, RW_WRITER); 325 0 stevel serialize = 1; 326 0 stevel } 327 0 stevel break; 328 0 stevel 329 0 stevel case F_HASREMOTELOCKS: 330 0 stevel nlmid = GETNLMID(bfp->l_sysid); 331 0 stevel if (nlmid != 0) { /* booted as a cluster */ 332 0 stevel l_has_rmt(bfp) = 333 5331 amw cl_flk_has_remote_locks_for_nlmid(vp, nlmid); 334 0 stevel } else { /* not booted as a cluster */ 335 0 stevel l_has_rmt(bfp) = flk_has_remote_locks(vp); 336 0 stevel } 337 0 stevel 338 0 stevel goto done; 339 0 stevel 340 0 stevel default: 341 0 stevel error = EINVAL; 342 0 stevel goto done; 343 0 stevel } 344 0 stevel 345 0 stevel /* 346 0 stevel * If this is a blocking lock request and we're serializing lock 347 0 stevel * requests, modify the callback list to leave the critical region 348 0 stevel * while we're waiting for the lock. 349 0 stevel */ 350 0 stevel 351 0 stevel if (serialize && (frcmd & SLPFLCK) != 0) { 352 0 stevel flk_add_callback(&serialize_callback, 353 5331 amw frlock_serialize_blocked, vp, flk_cbp); 354 0 stevel flk_cbp = &serialize_callback; 355 0 stevel } 356 0 stevel 357 0 stevel error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp); 358 0 stevel 359 0 stevel done: 360 0 stevel if (serialize) 361 0 stevel nbl_end_crit(vp); 362 0 stevel 363 0 stevel return (error); 364 0 stevel } 365 0 stevel 366 0 stevel /* 367 0 stevel * Callback when a lock request blocks and we are serializing requests. If 368 0 stevel * before sleeping, leave the critical region. If after wakeup, reenter 369 0 stevel * the critical region. 370 0 stevel */ 371 0 stevel 372 0 stevel static callb_cpr_t * 373 0 stevel frlock_serialize_blocked(flk_cb_when_t when, void *infop) 374 0 stevel { 375 0 stevel vnode_t *vp = (vnode_t *)infop; 376 0 stevel 377 0 stevel if (when == FLK_BEFORE_SLEEP) 378 0 stevel nbl_end_crit(vp); 379 0 stevel else { 380 0 stevel nbl_start_crit(vp, RW_WRITER); 381 0 stevel } 382 0 stevel 383 0 stevel return (NULL); 384 0 stevel } 385 0 stevel 386 0 stevel /* 387 0 stevel * Allow any flags. 388 0 stevel */ 389 0 stevel /* ARGSUSED */ 390 0 stevel int 391 5331 amw fs_setfl( 392 5331 amw vnode_t *vp, 393 5331 amw int oflags, 394 5331 amw int nflags, 395 5331 amw cred_t *cr, 396 5331 amw caller_context_t *ct) 397 0 stevel { 398 0 stevel return (0); 399 0 stevel } 400 0 stevel 401 0 stevel /* 402 0 stevel * Return the answer requested to poll() for non-device files. 403 0 stevel * Only POLLIN, POLLRDNORM, and POLLOUT are recognized. 404 0 stevel */ 405 0 stevel struct pollhead fs_pollhd; 406 0 stevel 407 0 stevel /* ARGSUSED */ 408 0 stevel int 409 0 stevel fs_poll(vnode_t *vp, 410 0 stevel register short events, 411 0 stevel int anyyet, 412 0 stevel register short *reventsp, 413 5331 amw struct pollhead **phpp, 414 5331 amw caller_context_t *ct) 415 0 stevel { 416 0 stevel *reventsp = 0; 417 0 stevel if (events & POLLIN) 418 0 stevel *reventsp |= POLLIN; 419 0 stevel if (events & POLLRDNORM) 420 0 stevel *reventsp |= POLLRDNORM; 421 0 stevel if (events & POLLRDBAND) 422 0 stevel *reventsp |= POLLRDBAND; 423 0 stevel if (events & POLLOUT) 424 0 stevel *reventsp |= POLLOUT; 425 0 stevel if (events & POLLWRBAND) 426 0 stevel *reventsp |= POLLWRBAND; 427 0 stevel *phpp = !anyyet && !*reventsp ? &fs_pollhd : (struct pollhead *)NULL; 428 0 stevel return (0); 429 0 stevel } 430 0 stevel 431 0 stevel /* 432 0 stevel * POSIX pathconf() support. 433 0 stevel */ 434 0 stevel /* ARGSUSED */ 435 0 stevel int 436 5331 amw fs_pathconf( 437 5331 amw vnode_t *vp, 438 5331 amw int cmd, 439 5331 amw ulong_t *valp, 440 5331 amw cred_t *cr, 441 5331 amw caller_context_t *ct) 442 0 stevel { 443 0 stevel register ulong_t val; 444 0 stevel register int error = 0; 445 0 stevel struct statvfs64 vfsbuf; 446 0 stevel 447 0 stevel switch (cmd) { 448 0 stevel 449 0 stevel case _PC_LINK_MAX: 450 0 stevel val = MAXLINK; 451 0 stevel break; 452 0 stevel 453 0 stevel case _PC_MAX_CANON: 454 0 stevel val = MAX_CANON; 455 0 stevel break; 456 0 stevel 457 0 stevel case _PC_MAX_INPUT: 458 0 stevel val = MAX_INPUT; 459 0 stevel break; 460 0 stevel 461 0 stevel case _PC_NAME_MAX: 462 0 stevel bzero(&vfsbuf, sizeof (vfsbuf)); 463 0 stevel if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf)) 464 0 stevel break; 465 0 stevel val = vfsbuf.f_namemax; 466 0 stevel break; 467 0 stevel 468 0 stevel case _PC_PATH_MAX: 469 0 stevel case _PC_SYMLINK_MAX: 470 0 stevel val = MAXPATHLEN; 471 0 stevel break; 472 0 stevel 473 0 stevel case _PC_PIPE_BUF: 474 0 stevel val = PIPE_BUF; 475 0 stevel break; 476 0 stevel 477 0 stevel case _PC_NO_TRUNC: 478 0 stevel if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC) 479 0 stevel val = 1; /* NOTRUNC is enabled for vp */ 480 0 stevel else 481 0 stevel val = (ulong_t)-1; 482 0 stevel break; 483 0 stevel 484 0 stevel case _PC_VDISABLE: 485 0 stevel val = _POSIX_VDISABLE; 486 0 stevel break; 487 0 stevel 488 0 stevel case _PC_CHOWN_RESTRICTED: 489 0 stevel if (rstchown) 490 0 stevel val = rstchown; /* chown restricted enabled */ 491 0 stevel else 492 0 stevel val = (ulong_t)-1; 493 0 stevel break; 494 0 stevel 495 0 stevel case _PC_FILESIZEBITS: 496 0 stevel 497 0 stevel /* 498 0 stevel * If ever we come here it means that underlying file system 499 0 stevel * does not recognise the command and therefore this 500 0 stevel * configurable limit cannot be determined. We return -1 501 0 stevel * and don't change errno. 502 0 stevel */ 503 0 stevel 504 0 stevel val = (ulong_t)-1; /* large file support */ 505 0 stevel break; 506 0 stevel 507 0 stevel case _PC_ACL_ENABLED: 508 0 stevel val = 0; 509 0 stevel break; 510 0 stevel 511 5331 amw case _PC_CASE_BEHAVIOR: 512 5331 amw val = _CASE_SENSITIVE; 513 5331 amw if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1) 514 5331 amw val |= _CASE_INSENSITIVE; 515 5331 amw if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1) 516 5331 amw val &= ~_CASE_SENSITIVE; 517 5331 amw break; 518 5331 amw 519 5331 amw case _PC_SATTR_ENABLED: 520 5331 amw case _PC_SATTR_EXISTS: 521 5331 amw val = 0; 522 5331 amw break; 523 5331 amw 524 9749 Tim case _PC_ACCESS_FILTERING: 525 9749 Tim val = 0; 526 9749 Tim break; 527 9749 Tim 528 0 stevel default: 529 0 stevel error = EINVAL; 530 0 stevel break; 531 0 stevel } 532 0 stevel 533 0 stevel if (error == 0) 534 0 stevel *valp = val; 535 0 stevel return (error); 536 0 stevel } 537 0 stevel 538 0 stevel /* 539 0 stevel * Dispose of a page. 540 0 stevel */ 541 0 stevel /* ARGSUSED */ 542 0 stevel void 543 5331 amw fs_dispose( 544 5331 amw struct vnode *vp, 545 5331 amw page_t *pp, 546 5331 amw int fl, 547 5331 amw int dn, 548 5331 amw struct cred *cr, 549 5331 amw caller_context_t *ct) 550 0 stevel { 551 0 stevel 552 0 stevel ASSERT(fl == B_FREE || fl == B_INVAL); 553 0 stevel 554 0 stevel if (fl == B_FREE) 555 0 stevel page_free(pp, dn); 556 0 stevel else 557 0 stevel page_destroy(pp, dn); 558 0 stevel } 559 0 stevel 560 0 stevel /* ARGSUSED */ 561 0 stevel void 562 5331 amw fs_nodispose( 563 5331 amw struct vnode *vp, 564 5331 amw page_t *pp, 565 5331 amw int fl, 566 5331 amw int dn, 567 5331 amw struct cred *cr, 568 5331 amw caller_context_t *ct) 569 0 stevel { 570 0 stevel cmn_err(CE_PANIC, "fs_nodispose invoked"); 571 0 stevel } 572 0 stevel 573 0 stevel /* 574 0 stevel * fabricate acls for file systems that do not support acls. 575 0 stevel */ 576 0 stevel /* ARGSUSED */ 577 0 stevel int 578 5331 amw fs_fab_acl( 579 5331 amw vnode_t *vp, 580 5331 amw vsecattr_t *vsecattr, 581 5331 amw int flag, 582 5331 amw cred_t *cr, 583 5331 amw caller_context_t *ct) 584 0 stevel { 585 0 stevel aclent_t *aclentp; 586 2123 szhou ace_t *acep; 587 0 stevel struct vattr vattr; 588 0 stevel int error; 589 5331 amw size_t aclsize; 590 0 stevel 591 0 stevel vsecattr->vsa_aclcnt = 0; 592 5331 amw vsecattr->vsa_aclentsz = 0; 593 0 stevel vsecattr->vsa_aclentp = NULL; 594 0 stevel vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */ 595 0 stevel vsecattr->vsa_dfaclentp = NULL; 596 0 stevel 597 2123 szhou vattr.va_mask = AT_MODE | AT_UID | AT_GID; 598 5331 amw if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct)) 599 2123 szhou return (error); 600 2123 szhou 601 2143 marks if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) { 602 5331 amw aclsize = 4 * sizeof (aclent_t); 603 0 stevel vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */ 604 5331 amw vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 605 0 stevel aclentp = vsecattr->vsa_aclentp; 606 0 stevel 607 0 stevel aclentp->a_type = USER_OBJ; /* Owner */ 608 0 stevel aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6; 609 0 stevel aclentp->a_id = vattr.va_uid; /* Really undefined */ 610 0 stevel aclentp++; 611 0 stevel 612 0 stevel aclentp->a_type = GROUP_OBJ; /* Group */ 613 0 stevel aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3; 614 0 stevel aclentp->a_id = vattr.va_gid; /* Really undefined */ 615 0 stevel aclentp++; 616 0 stevel 617 0 stevel aclentp->a_type = OTHER_OBJ; /* Other */ 618 0 stevel aclentp->a_perm = vattr.va_mode & 0007; 619 4321 casper aclentp->a_id = (gid_t)-1; /* Really undefined */ 620 0 stevel aclentp++; 621 0 stevel 622 0 stevel aclentp->a_type = CLASS_OBJ; /* Class */ 623 2123 szhou aclentp->a_perm = (ushort_t)(0007); 624 4321 casper aclentp->a_id = (gid_t)-1; /* Really undefined */ 625 2143 marks } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { 626 5331 amw aclsize = 6 * sizeof (ace_t); 627 2123 szhou vsecattr->vsa_aclcnt = 6; 628 5331 amw vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 629 5331 amw vsecattr->vsa_aclentsz = aclsize; 630 2123 szhou acep = vsecattr->vsa_aclentp; 631 2123 szhou (void) memcpy(acep, trivial_acl, sizeof (ace_t) * 6); 632 2123 szhou adjust_ace_pair(acep, (vattr.va_mode & 0700) >> 6); 633 2123 szhou adjust_ace_pair(acep + 2, (vattr.va_mode & 0070) >> 3); 634 2123 szhou adjust_ace_pair(acep + 4, vattr.va_mode & 0007); 635 2143 marks } 636 0 stevel 637 0 stevel return (0); 638 0 stevel } 639 0 stevel 640 0 stevel /* 641 0 stevel * Common code for implementing DOS share reservations 642 0 stevel */ 643 0 stevel /* ARGSUSED4 */ 644 0 stevel int 645 5331 amw fs_shrlock( 646 5331 amw struct vnode *vp, 647 5331 amw int cmd, 648 5331 amw struct shrlock *shr, 649 5331 amw int flag, 650 5331 amw cred_t *cr, 651 5331 amw caller_context_t *ct) 652 0 stevel { 653 0 stevel int error; 654 0 stevel 655 0 stevel /* 656 0 stevel * Make sure that the file was opened with permissions appropriate 657 0 stevel * for the request, and make sure the caller isn't trying to sneak 658 0 stevel * in an NBMAND request. 659 0 stevel */ 660 0 stevel if (cmd == F_SHARE) { 661 0 stevel if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) || 662 0 stevel ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0)) 663 0 stevel return (EBADF); 664 5331 amw if (shr->s_access & (F_RMACC | F_MDACC)) 665 5331 amw return (EINVAL); 666 5331 amw if (shr->s_deny & (F_MANDDNY | F_RMDNY)) 667 0 stevel return (EINVAL); 668 0 stevel } 669 0 stevel if (cmd == F_SHARE_NBMAND) { 670 0 stevel /* make sure nbmand is allowed on the file */ 671 0 stevel if (!vp->v_vfsp || 672 0 stevel !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 673 0 stevel return (EINVAL); 674 0 stevel } 675 0 stevel if (vp->v_type != VREG) { 676 0 stevel return (EINVAL); 677 0 stevel } 678 0 stevel } 679 0 stevel 680 0 stevel nbl_start_crit(vp, RW_WRITER); 681 0 stevel 682 0 stevel switch (cmd) { 683 0 stevel 684 0 stevel case F_SHARE_NBMAND: 685 0 stevel shr->s_deny |= F_MANDDNY; 686 0 stevel /*FALLTHROUGH*/ 687 0 stevel case F_SHARE: 688 0 stevel error = add_share(vp, shr); 689 0 stevel break; 690 0 stevel 691 0 stevel case F_UNSHARE: 692 0 stevel error = del_share(vp, shr); 693 0 stevel break; 694 0 stevel 695 0 stevel case F_HASREMOTELOCKS: 696 0 stevel /* 697 0 stevel * We are overloading this command to refer to remote 698 0 stevel * shares as well as remote locks, despite its name. 699 0 stevel */ 700 0 stevel shr->s_access = shr_has_remote_shares(vp, shr->s_sysid); 701 0 stevel error = 0; 702 0 stevel break; 703 0 stevel 704 0 stevel default: 705 0 stevel error = EINVAL; 706 0 stevel break; 707 0 stevel } 708 0 stevel 709 0 stevel nbl_end_crit(vp); 710 0 stevel return (error); 711 0 stevel } 712 0 stevel 713 0 stevel /*ARGSUSED1*/ 714 0 stevel int 715 5331 amw fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 716 5331 amw caller_context_t *ct) 717 0 stevel { 718 0 stevel ASSERT(vp != NULL); 719 0 stevel return (ENOTSUP); 720 0 stevel } 721 0 stevel 722 0 stevel /*ARGSUSED1*/ 723 0 stevel int 724 5331 amw fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 725 5331 amw caller_context_t *ct) 726 0 stevel { 727 0 stevel ASSERT(vp != NULL); 728 0 stevel return (0); 729 0 stevel } 730 789 ahrens 731 789 ahrens /* 732 789 ahrens * return 1 for non-trivial ACL. 733 789 ahrens * 734 789 ahrens * NB: It is not necessary for the caller to VOP_RWLOCK since 735 789 ahrens * we only issue VOP_GETSECATTR. 736 789 ahrens * 737 789 ahrens * Returns 0 == trivial 738 789 ahrens * 1 == NOT Trivial 739 789 ahrens * <0 could not determine. 740 789 ahrens */ 741 789 ahrens int 742 789 ahrens fs_acl_nontrivial(vnode_t *vp, cred_t *cr) 743 789 ahrens { 744 789 ahrens ulong_t acl_styles; 745 789 ahrens ulong_t acl_flavor; 746 789 ahrens vsecattr_t vsecattr; 747 789 ahrens int error; 748 789 ahrens int isnontrivial; 749 789 ahrens 750 789 ahrens /* determine the forms of ACLs maintained */ 751 5331 amw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL); 752 789 ahrens 753 789 ahrens /* clear bits we don't understand and establish default acl_style */ 754 789 ahrens acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED); 755 789 ahrens if (error || (acl_styles == 0)) 756 789 ahrens acl_styles = _ACL_ACLENT_ENABLED; 757 789 ahrens 758 789 ahrens vsecattr.vsa_aclentp = NULL; 759 789 ahrens vsecattr.vsa_dfaclentp = NULL; 760 789 ahrens vsecattr.vsa_aclcnt = 0; 761 789 ahrens vsecattr.vsa_dfaclcnt = 0; 762 789 ahrens 763 789 ahrens while (acl_styles) { 764 789 ahrens /* select one of the styles as current flavor */ 765 789 ahrens acl_flavor = 0; 766 789 ahrens if (acl_styles & _ACL_ACLENT_ENABLED) { 767 789 ahrens acl_flavor = _ACL_ACLENT_ENABLED; 768 789 ahrens vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT; 769 789 ahrens } else if (acl_styles & _ACL_ACE_ENABLED) { 770 789 ahrens acl_flavor = _ACL_ACE_ENABLED; 771 789 ahrens vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE; 772 789 ahrens } 773 789 ahrens 774 789 ahrens ASSERT(vsecattr.vsa_mask && acl_flavor); 775 5331 amw error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL); 776 789 ahrens if (error == 0) 777 789 ahrens break; 778 789 ahrens 779 789 ahrens /* that flavor failed */ 780 789 ahrens acl_styles &= ~acl_flavor; 781 789 ahrens } 782 789 ahrens 783 789 ahrens /* if all styles fail then assume trivial */ 784 789 ahrens if (acl_styles == 0) 785 789 ahrens return (0); 786 789 ahrens 787 789 ahrens /* process the flavor that worked */ 788 789 ahrens isnontrivial = 0; 789 789 ahrens if (acl_flavor & _ACL_ACLENT_ENABLED) { 790 789 ahrens if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES) 791 789 ahrens isnontrivial = 1; 792 789 ahrens if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 793 789 ahrens kmem_free(vsecattr.vsa_aclentp, 794 789 ahrens vsecattr.vsa_aclcnt * sizeof (aclent_t)); 795 789 ahrens if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL) 796 789 ahrens kmem_free(vsecattr.vsa_dfaclentp, 797 789 ahrens vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 798 789 ahrens } 799 789 ahrens if (acl_flavor & _ACL_ACE_ENABLED) { 800 789 ahrens 801 789 ahrens isnontrivial = ace_trivial(vsecattr.vsa_aclentp, 802 789 ahrens vsecattr.vsa_aclcnt); 803 789 ahrens 804 789 ahrens if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 805 789 ahrens kmem_free(vsecattr.vsa_aclentp, 806 789 ahrens vsecattr.vsa_aclcnt * sizeof (ace_t)); 807 789 ahrens /* ACE has no vsecattr.vsa_dfaclcnt */ 808 789 ahrens } 809 789 ahrens return (isnontrivial); 810 789 ahrens } 811 2051 prabahar 812 2051 prabahar /* 813 2051 prabahar * Check whether we need a retry to recover from STALE error. 814 2051 prabahar */ 815 2051 prabahar int 816 2051 prabahar fs_need_estale_retry(int retry_count) 817 2051 prabahar { 818 2051 prabahar if (retry_count < fs_estale_retry) 819 2051 prabahar return (1); 820 2051 prabahar else 821 2051 prabahar return (0); 822 2051 prabahar } 823 5331 amw 824 5331 amw 825 5331 amw static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL; 826 5331 amw 827 5331 amw /* 828 5331 amw * Routine for anti-virus scanner to call to register its scanning routine. 829 5331 amw */ 830 5331 amw void 831 5331 amw fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int)) 832 5331 amw { 833 5331 amw fs_av_scan = av_scan; 834 5331 amw } 835 5331 amw 836 5331 amw /* 837 5331 amw * Routine for file systems to call to initiate anti-virus scanning. 838 5331 amw * Scanning will only be done on REGular files (currently). 839 5331 amw */ 840 5331 amw int 841 5331 amw fs_vscan(vnode_t *vp, cred_t *cr, int async) 842 5331 amw { 843 5331 amw int ret = 0; 844 5331 amw 845 5331 amw if (fs_av_scan && vp->v_type == VREG) 846 5331 amw ret = (*fs_av_scan)(vp, cr, async); 847 5331 amw 848 5331 amw return (ret); 849 5331 amw } 850 10793 dai 851 10793 dai /* 852 10793 dai * support functions for reparse point 853 10793 dai */ 854 10793 dai /* 855 10793 dai * reparse_vnode_parse 856 10793 dai * 857 10793 dai * Read the symlink data of a reparse point specified by the vnode 858 10793 dai * and return the reparse data as name-value pair in the nvlist. 859 10793 dai */ 860 10793 dai int 861 10793 dai reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl) 862 10793 dai { 863 10793 dai int err; 864 10793 dai char *lkdata; 865 10793 dai struct uio uio; 866 10793 dai struct iovec iov; 867 10793 dai 868 10793 dai if (vp == NULL || nvl == NULL) 869 10793 dai return (EINVAL); 870 10793 dai 871 10793 dai lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP); 872 10793 dai 873 10793 dai /* 874 10793 dai * Set up io vector to read sym link data 875 10793 dai */ 876 10793 dai iov.iov_base = lkdata; 877 10793 dai iov.iov_len = MAXREPARSELEN; 878 10793 dai uio.uio_iov = &iov; 879 10793 dai uio.uio_iovcnt = 1; 880 10793 dai uio.uio_segflg = UIO_SYSSPACE; 881 10793 dai uio.uio_extflg = UIO_COPY_CACHED; 882 10793 dai uio.uio_loffset = (offset_t)0; 883 10793 dai uio.uio_resid = MAXREPARSELEN; 884 10793 dai 885 10793 dai if ((err = VOP_READLINK(vp, &uio, kcred, NULL)) == 0) { 886 10793 dai *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0'; 887 10793 dai err = reparse_parse(lkdata, nvl); 888 10793 dai } 889 10793 dai kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */ 890 10793 dai 891 10793 dai return (err); 892 10793 dai } 893 10793 dai 894 10793 dai void 895 10793 dai reparse_point_init() 896 10793 dai { 897 10793 dai mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL); 898 10793 dai } 899 10793 dai 900 10793 dai static door_handle_t 901 10793 dai reparse_door_get_handle() 902 10793 dai { 903 10793 dai door_handle_t dh; 904 10793 dai 905 10793 dai mutex_enter(&reparsed_door_lock); 906 10793 dai if ((dh = reparsed_door) == NULL) { 907 10793 dai if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) { 908 10793 dai reparsed_door = NULL; 909 10793 dai dh = NULL; 910 10793 dai } else 911 10793 dai dh = reparsed_door; 912 10793 dai } 913 10793 dai mutex_exit(&reparsed_door_lock); 914 10793 dai return (dh); 915 10793 dai } 916 10793 dai 917 10793 dai static void 918 10793 dai reparse_door_reset_handle() 919 10793 dai { 920 10793 dai mutex_enter(&reparsed_door_lock); 921 10793 dai reparsed_door = NULL; 922 10793 dai mutex_exit(&reparsed_door_lock); 923 10793 dai } 924 10793 dai 925 10793 dai /* 926 10793 dai * reparse_kderef 927 10793 dai * 928 10793 dai * Accepts the service-specific item from the reparse point and returns 929 10793 dai * the service-specific data requested. The caller specifies the size of 930 10793 dai * the buffer provided via *bufsz; the routine will fail with EOVERFLOW 931 10793 dai * if the results will not fit in the buffer, in which case, *bufsz will 932 10793 dai * contain the number of bytes needed to hold the results. 933 10793 dai * 934 10793 dai * if ok return 0 and update *bufsize with length of actual result 935 10793 dai * else return error code. 936 10793 dai */ 937 10793 dai int 938 10793 dai reparse_kderef(const char *svc_type, const char *svc_data, char *buf, 939 10793 dai size_t *bufsize) 940 10793 dai { 941 10793 dai int err, retries, need_free; 942 10793 dai size_t dlen, res_len; 943 10793 dai char *darg; 944 10793 dai door_arg_t door_args; 945 10793 dai reparsed_door_res_t *resp; 946 10793 dai door_handle_t rp_door; 947 10793 dai 948 10793 dai if (svc_type == NULL || svc_data == NULL || buf == NULL || 949 10793 dai bufsize == NULL) 950 10793 dai return (EINVAL); 951 10793 dai 952 10793 dai /* get reparsed's door handle */ 953 10793 dai if ((rp_door = reparse_door_get_handle()) == NULL) 954 10793 dai return (EBADF); 955 10793 dai 956 10793 dai /* setup buffer for door_call args and results */ 957 10793 dai dlen = strlen(svc_type) + strlen(svc_data) + 2; 958 10793 dai if (*bufsize < dlen) { 959 10793 dai darg = kmem_alloc(dlen, KM_SLEEP); 960 10793 dai need_free = 1; 961 10793 dai } else { 962 10793 dai darg = buf; /* use same buffer for door's args & results */ 963 10793 dai need_free = 0; 964 10793 dai } 965 10793 dai 966 10793 dai /* build argument string of door call */ 967 10793 dai (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data); 968 10793 dai 969 10793 dai /* setup args for door call */ 970 10793 dai door_args.data_ptr = darg; 971 10793 dai door_args.data_size = dlen; 972 10793 dai door_args.desc_ptr = NULL; 973 10793 dai door_args.desc_num = 0; 974 10793 dai door_args.rbuf = buf; 975 10793 dai door_args.rsize = *bufsize; 976 10793 dai 977 10793 dai /* do the door_call */ 978 10793 dai retries = 0; 979 10793 dai door_ki_hold(rp_door); 980 10793 dai while ((err = door_ki_upcall_limited(rp_door, &door_args, 981 10793 dai NULL, SIZE_MAX, 0)) != 0) { 982 10793 dai if (err == EAGAIN || err == EINTR) { 983 10793 dai if (++retries < REPARSED_DOORCALL_MAX_RETRY) { 984 10793 dai delay(SEC_TO_TICK(1)); 985 10793 dai continue; 986 10793 dai } 987 10793 dai } else if (err == EBADF) { 988 10793 dai /* door server goes away... */ 989 10793 dai reparse_door_reset_handle(); 990 10793 dai } 991 10793 dai break; 992 10793 dai } 993 10793 dai door_ki_rele(rp_door); 994 10793 dai if (need_free) 995 10793 dai kmem_free(darg, dlen); /* done with args buffer */ 996 10793 dai 997 10793 dai if (err != 0) 998 10793 dai return (err); 999 10793 dai 1000 10793 dai resp = (reparsed_door_res_t *)door_args.rbuf; 1001 10793 dai if ((err = resp->res_status) == 0) { 1002 10793 dai /* 1003 10793 dai * have to save the length of the results before the 1004 10793 dai * bcopy below since it's can be an overlap copy that 1005 10793 dai * overwrites the reparsed_door_res_t structure at 1006 10793 dai * the beginning of the buffer. 1007 10793 dai */ 1008 10793 dai res_len = (size_t)resp->res_len; 1009 10793 dai 1010 10793 dai /* deref call is ok */ 1011 10793 dai if (res_len > *bufsize) 1012 10793 dai err = EOVERFLOW; 1013 10793 dai else 1014 10793 dai bcopy(resp->res_data, buf, res_len); 1015 10793 dai *bufsize = res_len; 1016 10793 dai } 1017 10793 dai if (door_args.rbuf != buf) 1018 10793 dai kmem_free(door_args.rbuf, door_args.rsize); 1019 10793 dai 1020 10793 dai return (err); 1021 10793 dai } 1022