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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * vnode ops for the /dev filesystem 30 * 31 * - VDIR, VCHR, CBLK, and VLNK are considered must supported files 32 * - VREG and VDOOR are used for some internal implementations in 33 * the global zone, e.g. devname and devfsadm communication 34 * - other file types are unusual in this namespace and 35 * not supported for now 36 */ 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/t_lock.h> 41 #include <sys/systm.h> 42 #include <sys/sysmacros.h> 43 #include <sys/user.h> 44 #include <sys/time.h> 45 #include <sys/vfs.h> 46 #include <sys/vnode.h> 47 #include <sys/vfs_opreg.h> 48 #include <sys/file.h> 49 #include <sys/fcntl.h> 50 #include <sys/flock.h> 51 #include <sys/kmem.h> 52 #include <sys/uio.h> 53 #include <sys/errno.h> 54 #include <sys/stat.h> 55 #include <sys/cred.h> 56 #include <sys/cred_impl.h> 57 #include <sys/dirent.h> 58 #include <sys/pathname.h> 59 #include <sys/cmn_err.h> 60 #include <sys/debug.h> 61 #include <sys/policy.h> 62 #include <vm/hat.h> 63 #include <vm/seg_vn.h> 64 #include <vm/seg_map.h> 65 #include <vm/seg.h> 66 #include <vm/as.h> 67 #include <vm/page.h> 68 #include <sys/proc.h> 69 #include <sys/mode.h> 70 #include <sys/sunndi.h> 71 #include <sys/ptms.h> 72 #include <fs/fs_subr.h> 73 #include <sys/fs/dv_node.h> 74 #include <sys/fs/sdev_impl.h> 75 #include <sys/fs/sdev_node.h> 76 77 /*ARGSUSED*/ 78 static int 79 sdev_open(struct vnode **vpp, int flag, struct cred *cred) 80 { 81 struct sdev_node *dv = VTOSDEV(*vpp); 82 struct sdev_node *ddv = dv->sdev_dotdot; 83 int error = 0; 84 85 if ((*vpp)->v_type == VDIR) 86 return (0); 87 88 if (!SDEV_IS_GLOBAL(dv)) 89 return (ENOTSUP); 90 91 ASSERT((*vpp)->v_type == VREG); 92 if ((*vpp)->v_type != VREG) 93 return (ENOTSUP); 94 95 ASSERT(ddv); 96 rw_enter(&ddv->sdev_contents, RW_READER); 97 if (dv->sdev_attrvp == NULL) { 98 rw_exit(&ddv->sdev_contents); 99 return (ENOENT); 100 } 101 error = VOP_OPEN(&(dv->sdev_attrvp), flag, cred); 102 rw_exit(&ddv->sdev_contents); 103 return (error); 104 } 105 106 /*ARGSUSED1*/ 107 static int 108 sdev_close(struct vnode *vp, int flag, int count, 109 offset_t offset, struct cred *cred) 110 { 111 struct sdev_node *dv = VTOSDEV(vp); 112 113 if (vp->v_type == VDIR) { 114 cleanlocks(vp, ttoproc(curthread)->p_pid, 0); 115 cleanshares(vp, ttoproc(curthread)->p_pid); 116 return (0); 117 } 118 119 if (!SDEV_IS_GLOBAL(dv)) 120 return (ENOTSUP); 121 122 ASSERT(vp->v_type == VREG); 123 if (vp->v_type != VREG) 124 return (ENOTSUP); 125 126 ASSERT(dv->sdev_attrvp); 127 return (VOP_CLOSE(dv->sdev_attrvp, flag, count, offset, cred)); 128 } 129 130 /*ARGSUSED*/ 131 static int 132 sdev_read(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred, 133 struct caller_context *ct) 134 { 135 struct sdev_node *dv = (struct sdev_node *)VTOSDEV(vp); 136 int error; 137 138 if (!SDEV_IS_GLOBAL(dv)) 139 return (EINVAL); 140 141 if (vp->v_type == VDIR) 142 return (EISDIR); 143 144 /* only supporting regular files in /dev */ 145 ASSERT(vp->v_type == VREG); 146 if (vp->v_type != VREG) 147 return (EINVAL); 148 149 ASSERT(RW_READ_HELD(&VTOSDEV(vp)->sdev_contents)); 150 ASSERT(dv->sdev_attrvp); 151 (void) VOP_RWLOCK(dv->sdev_attrvp, 0, NULL); 152 error = VOP_READ(dv->sdev_attrvp, uio, ioflag, cred, ct); 153 VOP_RWUNLOCK(dv->sdev_attrvp, 0, NULL); 154 return (error); 155 } 156 157 /*ARGSUSED*/ 158 static int 159 sdev_write(struct vnode *vp, struct uio *uio, int ioflag, struct cred *cred, 160 struct caller_context *ct) 161 { 162 struct sdev_node *dv = VTOSDEV(vp); 163 int error = 0; 164 165 if (!SDEV_IS_GLOBAL(dv)) 166 return (EINVAL); 167 168 if (vp->v_type == VDIR) 169 return (EISDIR); 170 171 /* only supporting regular files in /dev */ 172 ASSERT(vp->v_type == VREG); 173 if (vp->v_type != VREG) 174 return (EINVAL); 175 176 ASSERT(dv->sdev_attrvp); 177 178 (void) VOP_RWLOCK(dv->sdev_attrvp, 1, NULL); 179 error = VOP_WRITE(dv->sdev_attrvp, uio, ioflag, cred, ct); 180 VOP_RWUNLOCK(dv->sdev_attrvp, 1, NULL); 181 if (error == 0) { 182 sdev_update_timestamps(dv->sdev_attrvp, kcred, 183 AT_MTIME); 184 } 185 return (error); 186 } 187 188 /*ARGSUSED*/ 189 static int 190 sdev_ioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, 191 struct cred *cred, int *rvalp) 192 { 193 struct sdev_node *dv = VTOSDEV(vp); 194 195 if (!SDEV_IS_GLOBAL(dv) || (vp->v_type == VDIR)) 196 return (ENOTTY); 197 198 ASSERT(vp->v_type == VREG); 199 if (vp->v_type != VREG) 200 return (EINVAL); 201 202 ASSERT(dv->sdev_attrvp); 203 return (VOP_IOCTL(dv->sdev_attrvp, cmd, arg, flag, cred, rvalp)); 204 } 205 206 static int 207 sdev_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr) 208 { 209 int error = 0; 210 struct sdev_node *dv = VTOSDEV(vp); 211 struct sdev_node *parent = dv->sdev_dotdot; 212 struct devname_nsmap *map = NULL; 213 struct devname_ops *dirops = NULL; 214 int (*fn)(devname_handle_t *, struct vattr *, struct cred *); 215 216 ASSERT(parent); 217 218 rw_enter(&parent->sdev_contents, RW_READER); 219 ASSERT(dv->sdev_attr || dv->sdev_attrvp); 220 if (SDEV_IS_GLOBAL(dv) && (dv->sdev_state != SDEV_ZOMBIE)) { 221 map = sdev_get_map(parent, 0); 222 dirops = map ? map->dir_ops : NULL; 223 } 224 225 /* 226 * search order: 227 * - for persistent nodes (SDEV_PERSIST): backstore 228 * - for non-persistent nodes: module ops if global, then memory 229 */ 230 if (dv->sdev_attrvp) { 231 rw_exit(&parent->sdev_contents); 232 error = VOP_GETATTR(dv->sdev_attrvp, vap, flags, cr); 233 sdev_vattr_merge(dv, vap); 234 } else if (dirops && (fn = dirops->devnops_getattr)) { 235 sdev_vattr_merge(dv, vap); 236 rw_exit(&parent->sdev_contents); 237 error = (*fn)(&(dv->sdev_handle), vap, cr); 238 } else { 239 ASSERT(dv->sdev_attr); 240 *vap = *dv->sdev_attr; 241 sdev_vattr_merge(dv, vap); 242 rw_exit(&parent->sdev_contents); 243 } 244 245 return (error); 246 } 247 248 /*ARGSUSED4*/ 249 static int 250 sdev_setattr(struct vnode *vp, struct vattr *vap, int flags, 251 struct cred *cred, caller_context_t *ctp) 252 { 253 return (devname_setattr_func(vp, vap, flags, cred, NULL, 0)); 254 } 255 256 static int 257 sdev_getsecattr(struct vnode *vp, struct vsecattr *vsap, int flags, 258 struct cred *cr) 259 { 260 int error; 261 struct sdev_node *dv = VTOSDEV(vp); 262 struct vnode *avp = dv->sdev_attrvp; 263 264 if (avp == NULL) { 265 /* return fs_fab_acl() if flavor matches, else do nothing */ 266 if ((SDEV_ACL_FLAVOR(vp) == _ACL_ACLENT_ENABLED && 267 (vsap->vsa_mask & (VSA_ACLCNT | VSA_DFACLCNT))) || 268 (SDEV_ACL_FLAVOR(vp) == _ACL_ACE_ENABLED && 269 (vsap->vsa_mask & (VSA_ACECNT | VSA_ACE)))) 270 return (fs_fab_acl(vp, vsap, flags, cr)); 271 272 return (ENOSYS); 273 } 274 275 (void) VOP_RWLOCK(avp, 1, NULL); 276 error = VOP_GETSECATTR(avp, vsap, flags, cr); 277 VOP_RWUNLOCK(avp, 1, NULL); 278 return (error); 279 } 280 281 static int 282 sdev_setsecattr(struct vnode *vp, struct vsecattr *vsap, int flags, 283 struct cred *cr) 284 { 285 int error; 286 struct sdev_node *dv = VTOSDEV(vp); 287 struct vnode *avp = dv->sdev_attrvp; 288 289 if (dv->sdev_state == SDEV_ZOMBIE) 290 return (0); 291 292 if (avp == NULL) { 293 if (SDEV_IS_GLOBAL(dv) && !SDEV_IS_PERSIST(dv)) 294 return (fs_nosys()); 295 ASSERT(dv->sdev_attr); 296 /* 297 * if coming in directly, the acl system call will 298 * have held the read-write lock via VOP_RWLOCK() 299 * If coming in via specfs, specfs will have 300 * held the rw lock on the realvp i.e. us. 301 */ 302 ASSERT(RW_WRITE_HELD(&dv->sdev_contents)); 303 sdev_vattr_merge(dv, dv->sdev_attr); 304 error = sdev_shadow_node(dv, cr); 305 if (error) { 306 return (fs_nosys()); 307 } 308 309 ASSERT(dv->sdev_attrvp); 310 /* clean out the memory copy if any */ 311 if (dv->sdev_attr) { 312 kmem_free(dv->sdev_attr, sizeof (struct vattr)); 313 dv->sdev_attr = NULL; 314 } 315 avp = dv->sdev_attrvp; 316 } 317 ASSERT(avp); 318 319 (void) VOP_RWLOCK(avp, V_WRITELOCK_TRUE, NULL); 320 error = VOP_SETSECATTR(avp, vsap, flags, cr); 321 VOP_RWUNLOCK(avp, V_WRITELOCK_TRUE, NULL); 322 return (error); 323 } 324 325 int 326 sdev_unlocked_access(void *vdv, int mode, struct cred *cr) 327 { 328 struct sdev_node *dv = vdv; 329 int shift = 0; 330 uid_t owner = dv->sdev_attr->va_uid; 331 332 if (crgetuid(cr) != owner) { 333 shift += 3; 334 if (groupmember(dv->sdev_attr->va_gid, cr) == 0) 335 shift += 3; 336 } 337 338 mode &= ~(dv->sdev_attr->va_mode << shift); 339 if (mode == 0) 340 return (0); 341 342 return (secpolicy_vnode_access(cr, SDEVTOV(dv), owner, mode)); 343 } 344 345 static int 346 sdev_access(struct vnode *vp, int mode, int flags, struct cred *cr) 347 { 348 struct sdev_node *dv = VTOSDEV(vp); 349 int ret = 0; 350 351 ASSERT(dv->sdev_attr || dv->sdev_attrvp); 352 353 if (dv->sdev_attrvp) { 354 ret = VOP_ACCESS(dv->sdev_attrvp, mode, flags, cr); 355 } else if (dv->sdev_attr) { 356 rw_enter(&dv->sdev_contents, RW_READER); 357 ret = sdev_unlocked_access(dv, mode, cr); 358 if (ret) 359 ret = EACCES; 360 rw_exit(&dv->sdev_contents); 361 } 362 363 return (ret); 364 } 365 366 /* 367 * Lookup 368 */ 369 /*ARGSUSED3*/ 370 static int 371 sdev_lookup(struct vnode *dvp, char *nm, struct vnode **vpp, 372 struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred) 373 { 374 struct sdev_node *parent; 375 int error; 376 377 parent = VTOSDEV(dvp); 378 ASSERT(parent); 379 380 /* execute access is required to search the directory */ 381 if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) 382 return (error); 383 384 if (!SDEV_IS_GLOBAL(parent)) 385 return (prof_lookup(dvp, nm, vpp, cred)); 386 return (devname_lookup_func(parent, nm, vpp, cred, NULL, 0)); 387 } 388 389 /*ARGSUSED2*/ 390 static int 391 sdev_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl, 392 int mode, struct vnode **vpp, struct cred *cred, int flag) 393 { 394 struct vnode *vp = NULL; 395 struct vnode *avp; 396 struct sdev_node *parent; 397 struct sdev_node *self = NULL; 398 int error = 0; 399 vtype_t type = vap->va_type; 400 401 ASSERT(type != VNON && type != VBAD); 402 403 if ((type == VFIFO) || (type == VSOCK) || 404 (type == VPROC) || (type == VPORT)) 405 return (ENOTSUP); 406 407 parent = VTOSDEV(dvp); 408 ASSERT(parent); 409 410 rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER); 411 if (parent->sdev_state == SDEV_ZOMBIE) { 412 rw_exit(&parent->sdev_dotdot->sdev_contents); 413 return (ENOENT); 414 } 415 416 /* non-global do not allow pure node creation */ 417 if (!SDEV_IS_GLOBAL(parent)) { 418 rw_exit(&parent->sdev_dotdot->sdev_contents); 419 return (prof_lookup(dvp, nm, vpp, cred)); 420 } 421 rw_exit(&parent->sdev_dotdot->sdev_contents); 422 423 /* execute access is required to search the directory */ 424 if ((error = VOP_ACCESS(dvp, VEXEC|VWRITE, 0, cred)) != 0) 425 return (error); 426 427 /* check existing name */ 428 error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred); 429 430 /* name found */ 431 if (error == 0) { 432 ASSERT(vp); 433 if (excl == EXCL) { 434 error = EEXIST; 435 } else if ((vp->v_type == VDIR) && (mode & VWRITE)) { 436 /* allowing create/read-only an existing directory */ 437 error = EISDIR; 438 } else { 439 error = VOP_ACCESS(vp, mode, flag, cred); 440 } 441 442 if (error) { 443 VN_RELE(vp); 444 return (error); 445 } 446 447 /* truncation first */ 448 if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) && 449 (vap->va_size == 0)) { 450 ASSERT(parent->sdev_attrvp); 451 ASSERT(VTOSDEV(vp)->sdev_attrvp); 452 error = VOP_CREATE(parent->sdev_attrvp, 453 nm, vap, excl, mode, &avp, cred, flag); 454 455 if (error) { 456 VN_RELE(vp); 457 return (error); 458 } 459 } 460 461 sdev_update_timestamps(vp, kcred, 462 AT_CTIME|AT_MTIME|AT_ATIME); 463 *vpp = vp; 464 return (0); 465 } 466 467 /* bail out early */ 468 if (error != ENOENT) 469 return (error); 470 471 /* 472 * For memory-based (ROFS) directory: 473 * - either disallow node creation; 474 * - or implement VOP_CREATE of its own 475 */ 476 rw_enter(&parent->sdev_contents, RW_WRITER); 477 if (!SDEV_IS_PERSIST(parent)) { 478 rw_exit(&parent->sdev_contents); 479 return (ENOTSUP); 480 } 481 ASSERT(parent->sdev_attrvp); 482 error = sdev_mknode(parent, nm, &self, vap, NULL, NULL, 483 cred, SDEV_READY); 484 if (error) { 485 rw_exit(&parent->sdev_contents); 486 if (self) 487 SDEV_RELE(self); 488 return (error); 489 } 490 rw_exit(&parent->sdev_contents); 491 492 ASSERT(self); 493 /* take care the timestamps for the node and its parent */ 494 sdev_update_timestamps(SDEVTOV(self), kcred, 495 AT_CTIME|AT_MTIME|AT_ATIME); 496 sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME); 497 if (SDEV_IS_GLOBAL(parent)) 498 atomic_inc_ulong(&parent->sdev_gdir_gen); 499 500 /* wake up other threads blocked on looking up this node */ 501 mutex_enter(&self->sdev_lookup_lock); 502 SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP); 503 mutex_exit(&self->sdev_lookup_lock); 504 error = sdev_to_vp(self, vpp); 505 return (error); 506 } 507 508 static int 509 sdev_remove(struct vnode *dvp, char *nm, struct cred *cred) 510 { 511 int error; 512 struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp); 513 struct vnode *vp = NULL; 514 struct sdev_node *dv = NULL; 515 struct devname_nsmap *map = NULL; 516 struct devname_ops *dirops = NULL; 517 int (*fn)(devname_handle_t *); 518 int len; 519 int bkstore = 0; 520 521 /* bail out early */ 522 len = strlen(nm); 523 if (nm[0] == '.') { 524 if (len == 1) { 525 return (EINVAL); 526 } else if (len == 2 && nm[1] == '.') { 527 return (EEXIST); 528 } 529 } 530 531 ASSERT(parent); 532 rw_enter(&parent->sdev_contents, RW_READER); 533 if (!SDEV_IS_GLOBAL(parent)) { 534 rw_exit(&parent->sdev_contents); 535 return (ENOTSUP); 536 } 537 538 /* execute access is required to search the directory */ 539 if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) { 540 rw_exit(&parent->sdev_contents); 541 return (error); 542 } 543 544 /* check existence first */ 545 dv = sdev_cache_lookup(parent, nm); 546 if (dv == NULL) { 547 rw_exit(&parent->sdev_contents); 548 return (ENOENT); 549 } 550 551 vp = SDEVTOV(dv); 552 if ((dv->sdev_state == SDEV_INIT) || 553 (dv->sdev_state == SDEV_ZOMBIE)) { 554 rw_exit(&parent->sdev_contents); 555 VN_RELE(vp); 556 return (ENOENT); 557 } 558 559 /* write access is required to remove an entry */ 560 if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) { 561 rw_exit(&parent->sdev_contents); 562 VN_RELE(vp); 563 return (error); 564 } 565 566 /* the module may record/reject removing a device node */ 567 map = sdev_get_map(parent, 0); 568 dirops = map ? map->dir_ops : NULL; 569 if (dirops && ((fn = dirops->devnops_remove) != NULL)) { 570 error = (*fn)(&(dv->sdev_handle)); 571 if (error) { 572 rw_exit(&parent->sdev_contents); 573 VN_RELE(vp); 574 return (error); 575 } 576 } 577 578 /* 579 * sdev_dirdelete does the real job of: 580 * - make sure no open ref count 581 * - destroying the sdev_node 582 * - releasing the hold on attrvp 583 */ 584 bkstore = SDEV_IS_PERSIST(dv) ? 1 : 0; 585 if (!rw_tryupgrade(&parent->sdev_contents)) { 586 rw_exit(&parent->sdev_contents); 587 rw_enter(&parent->sdev_contents, RW_WRITER); 588 } 589 error = sdev_cache_update(parent, &dv, nm, SDEV_CACHE_DELETE); 590 rw_exit(&parent->sdev_contents); 591 592 sdcmn_err2(("sdev_remove: cache_update error %d\n", error)); 593 if (error && (error != EBUSY)) { 594 /* report errors other than EBUSY */ 595 VN_RELE(vp); 596 } else { 597 sdcmn_err2(("sdev_remove: cleaning node %s from cache " 598 " with error %d\n", nm, error)); 599 600 /* 601 * best efforts clean up the backing store 602 */ 603 if (bkstore) { 604 ASSERT(parent->sdev_attrvp); 605 error = VOP_REMOVE(parent->sdev_attrvp, nm, cred); 606 /* 607 * do not report BUSY error 608 * because the backing store ref count is released 609 * when the last ref count on the sdev_node is 610 * released. 611 */ 612 if (error == EBUSY) { 613 sdcmn_err2(("sdev_remove: device %s is still on" 614 "disk %s\n", nm, parent->sdev_path)); 615 error = 0; 616 } 617 } 618 619 if (error == EBUSY) 620 error = 0; 621 } 622 623 return (error); 624 } 625 626 /* 627 * Some restrictions for this file system: 628 * - both oldnm and newnm are in the scope of /dev file system, 629 * to simply the namespace management model. 630 */ 631 static int 632 sdev_rename(struct vnode *odvp, char *onm, struct vnode *ndvp, char *nnm, 633 struct cred *cred) 634 { 635 struct sdev_node *fromparent = NULL; 636 struct vattr vattr; 637 struct sdev_node *toparent; 638 struct sdev_node *fromdv = NULL; /* source node */ 639 struct vnode *ovp = NULL; /* source vnode */ 640 struct sdev_node *todv = NULL; /* destination node */ 641 struct vnode *nvp = NULL; /* destination vnode */ 642 int samedir = 0; /* set if odvp == ndvp */ 643 struct vnode *realvp; 644 int len; 645 char nnm_path[MAXPATHLEN]; 646 struct devname_nsmap *omap = NULL; 647 struct devname_ops *odirops = NULL; 648 int (*fn)(devname_handle_t *, char *); 649 int (*rmfn)(devname_handle_t *); 650 int error = 0; 651 dev_t fsid; 652 int bkstore = 0; 653 vtype_t type; 654 655 /* prevent modifying "." and ".." */ 656 if ((onm[0] == '.' && 657 (onm[1] == '\0' || (onm[1] == '.' && onm[2] == '\0'))) || 658 (nnm[0] == '.' && 659 (nnm[1] == '\0' || (nnm[1] == '.' && nnm[2] == '\0')))) { 660 return (EINVAL); 661 } 662 663 fromparent = VTOSDEV(odvp); 664 toparent = VTOSDEV(ndvp); 665 666 /* ZOMBIE parent doesn't allow new node creation */ 667 rw_enter(&fromparent->sdev_dotdot->sdev_contents, RW_READER); 668 if (fromparent->sdev_state == SDEV_ZOMBIE) { 669 rw_exit(&fromparent->sdev_dotdot->sdev_contents); 670 return (ENOENT); 671 } 672 673 /* renaming only supported for global device nodes */ 674 if (!SDEV_IS_GLOBAL(fromparent)) { 675 rw_exit(&fromparent->sdev_dotdot->sdev_contents); 676 return (ENOTSUP); 677 } 678 rw_exit(&fromparent->sdev_dotdot->sdev_contents); 679 680 rw_enter(&toparent->sdev_dotdot->sdev_contents, RW_READER); 681 if (toparent->sdev_state == SDEV_ZOMBIE) { 682 rw_exit(&toparent->sdev_dotdot->sdev_contents); 683 return (ENOENT); 684 } 685 rw_exit(&toparent->sdev_dotdot->sdev_contents); 686 687 /* 688 * acquire the global lock to prevent 689 * mount/unmount/other rename activities. 690 */ 691 mutex_enter(&sdev_lock); 692 693 /* check existence of the source node */ 694 error = VOP_LOOKUP(odvp, onm, &ovp, NULL, 0, NULL, cred); 695 if (error) { 696 sdcmn_err2(("sdev_rename: the source node %s exists\n", 697 onm)); 698 mutex_exit(&sdev_lock); 699 return (error); 700 } 701 702 if (VOP_REALVP(ovp, &realvp) == 0) { 703 VN_HOLD(realvp); 704 VN_RELE(ovp); 705 ovp = realvp; 706 } 707 708 /* check existence of destination */ 709 error = VOP_LOOKUP(ndvp, nnm, &nvp, NULL, 0, NULL, cred); 710 if (error && (error != ENOENT)) { 711 mutex_exit(&sdev_lock); 712 VN_RELE(ovp); 713 return (error); 714 } 715 716 if (nvp && (VOP_REALVP(nvp, &realvp) == 0)) { 717 VN_HOLD(realvp); 718 VN_RELE(nvp); 719 nvp = realvp; 720 } 721 722 /* 723 * make sure the source and the destination are 724 * in the same dev filesystem 725 */ 726 if (odvp != ndvp) { 727 vattr.va_mask = AT_FSID; 728 if (error = VOP_GETATTR(odvp, &vattr, 0, cred)) { 729 mutex_exit(&sdev_lock); 730 VN_RELE(ovp); 731 return (error); 732 } 733 fsid = vattr.va_fsid; 734 vattr.va_mask = AT_FSID; 735 if (error = VOP_GETATTR(ndvp, &vattr, 0, cred)) { 736 mutex_exit(&sdev_lock); 737 VN_RELE(ovp); 738 return (error); 739 } 740 if (fsid != vattr.va_fsid) { 741 mutex_exit(&sdev_lock); 742 VN_RELE(ovp); 743 return (EXDEV); 744 } 745 } 746 747 /* make sure the old entry can be deleted */ 748 error = VOP_ACCESS(odvp, VWRITE, 0, cred); 749 if (error) { 750 mutex_exit(&sdev_lock); 751 VN_RELE(ovp); 752 return (error); 753 } 754 755 /* make sure the destination allows creation */ 756 samedir = (fromparent == toparent); 757 if (!samedir) { 758 error = VOP_ACCESS(ndvp, VEXEC|VWRITE, 0, cred); 759 if (error) { 760 mutex_exit(&sdev_lock); 761 VN_RELE(ovp); 762 return (error); 763 } 764 } 765 766 fromdv = VTOSDEV(ovp); 767 ASSERT(fromdv); 768 769 /* check with the plug-in modules for the source directory */ 770 rw_enter(&fromparent->sdev_contents, RW_READER); 771 omap = sdev_get_map(fromparent, 0); 772 rw_exit(&fromparent->sdev_contents); 773 odirops = omap ? omap->dir_ops : NULL; 774 if (odirops && ((fn = odirops->devnops_rename) != NULL)) { 775 if (samedir) { 776 error = (*fn)(&(fromdv->sdev_handle), nnm); 777 } else { 778 len = strlen(nnm) + strlen(toparent->sdev_name) + 2; 779 (void) snprintf(nnm_path, len, "%s/%s", 780 toparent->sdev_name, nnm); 781 error = (*fn)(&(fromdv->sdev_handle), nnm); 782 } 783 784 if (error) { 785 mutex_exit(&sdev_lock); 786 sdcmn_err2(("sdev_rename: DBNR doesn't " 787 "allow rename, error %d", error)); 788 VN_RELE(ovp); 789 return (error); 790 } 791 } 792 793 /* destination file exists */ 794 if (nvp) { 795 todv = VTOSDEV(nvp); 796 ASSERT(todv); 797 } 798 799 /* 800 * link source to new target in the memory 801 */ 802 error = sdev_rnmnode(fromparent, fromdv, toparent, &todv, nnm, cred); 803 if (error) { 804 sdcmn_err2(("sdev_rename: renaming %s to %s failed " 805 " with error %d\n", onm, nnm, error)); 806 mutex_exit(&sdev_lock); 807 if (nvp) 808 VN_RELE(nvp); 809 VN_RELE(ovp); 810 return (error); 811 } 812 813 /* notify the DBNR module the node is going away */ 814 if (odirops && ((rmfn = odirops->devnops_remove) != NULL)) { 815 (void) (*rmfn)(&(fromdv->sdev_handle)); 816 } 817 818 /* 819 * unlink from source 820 */ 821 rw_enter(&fromparent->sdev_contents, RW_READER); 822 fromdv = sdev_cache_lookup(fromparent, onm); 823 if (fromdv == NULL) { 824 rw_exit(&fromparent->sdev_contents); 825 mutex_exit(&sdev_lock); 826 sdcmn_err2(("sdev_rename: the source is deleted already\n")); 827 return (0); 828 } 829 830 if (fromdv->sdev_state == SDEV_ZOMBIE) { 831 rw_exit(&fromparent->sdev_contents); 832 mutex_exit(&sdev_lock); 833 VN_RELE(SDEVTOV(fromdv)); 834 sdcmn_err2(("sdev_rename: the source is being deleted\n")); 835 return (0); 836 } 837 rw_exit(&fromparent->sdev_contents); 838 ASSERT(SDEVTOV(fromdv) == ovp); 839 VN_RELE(ovp); 840 841 /* clean out the directory contents before it can be removed */ 842 type = SDEVTOV(fromdv)->v_type; 843 if (type == VDIR) { 844 error = sdev_cleandir(fromdv, NULL, 0); 845 sdcmn_err2(("sdev_rename: cleandir finished with %d\n", 846 error)); 847 if (error == EBUSY) 848 error = 0; 849 } 850 851 rw_enter(&fromparent->sdev_contents, RW_WRITER); 852 bkstore = SDEV_IS_PERSIST(fromdv) ? 1 : 0; 853 error = sdev_cache_update(fromparent, &fromdv, onm, 854 SDEV_CACHE_DELETE); 855 856 /* best effforts clean up the backing store */ 857 if (bkstore) { 858 ASSERT(fromparent->sdev_attrvp); 859 if (type != VDIR) { 860 error = VOP_REMOVE(fromparent->sdev_attrvp, 861 onm, kcred); 862 } else { 863 error = VOP_RMDIR(fromparent->sdev_attrvp, 864 onm, fromparent->sdev_attrvp, kcred); 865 } 866 867 if (error) { 868 sdcmn_err2(("sdev_rename: device %s is " 869 "still on disk %s\n", onm, 870 fromparent->sdev_path)); 871 error = 0; 872 } 873 } 874 rw_exit(&fromparent->sdev_contents); 875 mutex_exit(&sdev_lock); 876 877 /* once reached to this point, the rename is regarded successful */ 878 return (0); 879 } 880 881 /* 882 * dev-fs version of "ln -s path dev-name" 883 * tnm - path, e.g. /devices/... or /dev/... 884 * lnm - dev_name 885 */ 886 static int 887 sdev_symlink(struct vnode *dvp, char *lnm, struct vattr *tva, 888 char *tnm, struct cred *cred) 889 { 890 int error; 891 struct vnode *vp = NULL; 892 struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp); 893 struct sdev_node *self = (struct sdev_node *)NULL; 894 895 ASSERT(parent); 896 rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER); 897 if (parent->sdev_state == SDEV_ZOMBIE) { 898 rw_exit(&parent->sdev_dotdot->sdev_contents); 899 sdcmn_err2(("sdev_symlink: parent %s is ZOMBIED \n", 900 parent->sdev_name)); 901 return (ENOENT); 902 } 903 904 if (!SDEV_IS_GLOBAL(parent)) { 905 rw_exit(&parent->sdev_dotdot->sdev_contents); 906 return (ENOTSUP); 907 } 908 rw_exit(&parent->sdev_dotdot->sdev_contents); 909 910 /* execute access is required to search a directory */ 911 if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) 912 return (error); 913 914 /* find existing name */ 915 error = VOP_LOOKUP(dvp, lnm, &vp, NULL, 0, NULL, cred); 916 if (error == 0) { 917 ASSERT(vp); 918 VN_RELE(vp); 919 sdcmn_err2(("sdev_symlink: node %s already exists\n", lnm)); 920 return (EEXIST); 921 } 922 if (error != ENOENT) 923 return (error); 924 925 /* write access is required to create a symlink */ 926 if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) 927 return (error); 928 929 /* put it into memory cache */ 930 rw_enter(&parent->sdev_contents, RW_WRITER); 931 error = sdev_mknode(parent, lnm, &self, tva, NULL, (void *)tnm, 932 cred, SDEV_READY); 933 if (error) { 934 rw_exit(&parent->sdev_contents); 935 sdcmn_err2(("sdev_symlink: node %s creation failed\n", lnm)); 936 if (self) 937 SDEV_RELE(self); 938 939 return (error); 940 } 941 ASSERT(self && (self->sdev_state == SDEV_READY)); 942 rw_exit(&parent->sdev_contents); 943 944 /* take care the timestamps for the node and its parent */ 945 sdev_update_timestamps(SDEVTOV(self), kcred, 946 AT_CTIME|AT_MTIME|AT_ATIME); 947 sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME); 948 if (SDEV_IS_GLOBAL(parent)) 949 atomic_inc_ulong(&parent->sdev_gdir_gen); 950 951 /* wake up other threads blocked on looking up this node */ 952 mutex_enter(&self->sdev_lookup_lock); 953 SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP); 954 mutex_exit(&self->sdev_lookup_lock); 955 SDEV_RELE(self); /* don't return with vnode held */ 956 return (0); 957 } 958 959 static int 960 sdev_mkdir(struct vnode *dvp, char *nm, struct vattr *va, struct vnode **vpp, 961 struct cred *cred) 962 { 963 int error; 964 struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp); 965 struct sdev_node *self = NULL; 966 struct vnode *vp = NULL; 967 968 ASSERT(parent && parent->sdev_dotdot); 969 rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER); 970 if (parent->sdev_state == SDEV_ZOMBIE) { 971 rw_exit(&parent->sdev_dotdot->sdev_contents); 972 return (ENOENT); 973 } 974 975 /* non-global do not allow pure directory creation */ 976 if (!SDEV_IS_GLOBAL(parent)) { 977 rw_exit(&parent->sdev_dotdot->sdev_contents); 978 return (prof_lookup(dvp, nm, vpp, cred)); 979 } 980 rw_exit(&parent->sdev_dotdot->sdev_contents); 981 982 /* execute access is required to search the directory */ 983 if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) { 984 return (error); 985 } 986 987 /* find existing name */ 988 error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cred); 989 if (error == 0) { 990 VN_RELE(vp); 991 return (EEXIST); 992 } 993 if (error != ENOENT) 994 return (error); 995 996 /* require write access to create a directory */ 997 if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) { 998 return (error); 999 } 1000 1001 /* put it into memory */ 1002 rw_enter(&parent->sdev_contents, RW_WRITER); 1003 error = sdev_mknode(parent, nm, &self, 1004 va, NULL, NULL, cred, SDEV_READY); 1005 if (error) { 1006 rw_exit(&parent->sdev_contents); 1007 if (self) 1008 SDEV_RELE(self); 1009 return (error); 1010 } 1011 ASSERT(self && (self->sdev_state == SDEV_READY)); 1012 rw_exit(&parent->sdev_contents); 1013 1014 /* take care the timestamps for the node and its parent */ 1015 sdev_update_timestamps(SDEVTOV(self), kcred, 1016 AT_CTIME|AT_MTIME|AT_ATIME); 1017 sdev_update_timestamps(dvp, kcred, AT_MTIME|AT_ATIME); 1018 if (SDEV_IS_GLOBAL(parent)) 1019 atomic_inc_ulong(&parent->sdev_gdir_gen); 1020 1021 /* wake up other threads blocked on looking up this node */ 1022 mutex_enter(&self->sdev_lookup_lock); 1023 SDEV_UNBLOCK_OTHERS(self, SDEV_LOOKUP); 1024 mutex_exit(&self->sdev_lookup_lock); 1025 *vpp = SDEVTOV(self); 1026 return (0); 1027 } 1028 1029 /* 1030 * allowing removing an empty directory under /dev 1031 */ 1032 /*ARGSUSED*/ 1033 static int 1034 sdev_rmdir(struct vnode *dvp, char *nm, struct vnode *cdir, struct cred *cred) 1035 { 1036 int error = 0; 1037 struct sdev_node *parent = (struct sdev_node *)VTOSDEV(dvp); 1038 struct sdev_node *self = NULL; 1039 struct vnode *vp = NULL; 1040 1041 /* bail out early */ 1042 if (strcmp(nm, ".") == 0) 1043 return (EINVAL); 1044 if (strcmp(nm, "..") == 0) 1045 return (EEXIST); /* should be ENOTEMPTY */ 1046 1047 /* no destruction of non-global node */ 1048 ASSERT(parent && parent->sdev_dotdot); 1049 rw_enter(&parent->sdev_dotdot->sdev_contents, RW_READER); 1050 if (!SDEV_IS_GLOBAL(parent)) { 1051 rw_exit(&parent->sdev_dotdot->sdev_contents); 1052 return (ENOTSUP); 1053 } 1054 rw_exit(&parent->sdev_dotdot->sdev_contents); 1055 1056 /* execute access is required to search the directory */ 1057 if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) 1058 return (error); 1059 1060 /* check existing name */ 1061 rw_enter(&parent->sdev_contents, RW_WRITER); 1062 self = sdev_cache_lookup(parent, nm); 1063 if (self == NULL) { 1064 rw_exit(&parent->sdev_contents); 1065 return (ENOENT); 1066 } 1067 1068 vp = SDEVTOV(self); 1069 if ((self->sdev_state == SDEV_INIT) || 1070 (self->sdev_state == SDEV_ZOMBIE)) { 1071 rw_exit(&parent->sdev_contents); 1072 VN_RELE(vp); 1073 return (ENOENT); 1074 } 1075 1076 /* write access is required to remove a directory */ 1077 if ((error = VOP_ACCESS(dvp, VWRITE, 0, cred)) != 0) { 1078 rw_exit(&parent->sdev_contents); 1079 VN_RELE(vp); 1080 return (error); 1081 } 1082 1083 /* some sanity checks */ 1084 if (vp == dvp || vp == cdir) { 1085 rw_exit(&parent->sdev_contents); 1086 VN_RELE(vp); 1087 return (EINVAL); 1088 } 1089 1090 if (vp->v_type != VDIR) { 1091 rw_exit(&parent->sdev_contents); 1092 VN_RELE(vp); 1093 return (ENOTDIR); 1094 } 1095 1096 if (vn_vfswlock(vp)) { 1097 rw_exit(&parent->sdev_contents); 1098 VN_RELE(vp); 1099 return (EBUSY); 1100 } 1101 1102 if (vn_mountedvfs(vp) != NULL) { 1103 rw_exit(&parent->sdev_contents); 1104 vn_vfsunlock(vp); 1105 VN_RELE(vp); 1106 return (EBUSY); 1107 } 1108 1109 self = VTOSDEV(vp); 1110 /* bail out on a non-empty directory */ 1111 rw_enter(&self->sdev_contents, RW_READER); 1112 if (self->sdev_nlink > 2) { 1113 rw_exit(&self->sdev_contents); 1114 rw_exit(&parent->sdev_contents); 1115 vn_vfsunlock(vp); 1116 VN_RELE(vp); 1117 return (ENOTEMPTY); 1118 } 1119 rw_exit(&self->sdev_contents); 1120 1121 /* unlink it from the directory cache */ 1122 error = sdev_cache_update(parent, &self, nm, SDEV_CACHE_DELETE); 1123 rw_exit(&parent->sdev_contents); 1124 vn_vfsunlock(vp); 1125 1126 if (error && (error != EBUSY)) { 1127 VN_RELE(vp); 1128 } else { 1129 sdcmn_err2(("sdev_rmdir: cleaning node %s from directory " 1130 " cache with error %d\n", nm, error)); 1131 1132 /* best effort to clean up the backing store */ 1133 if (SDEV_IS_PERSIST(parent)) { 1134 ASSERT(parent->sdev_attrvp); 1135 error = VOP_RMDIR(parent->sdev_attrvp, nm, 1136 parent->sdev_attrvp, kcred); 1137 sdcmn_err2(("sdev_rmdir: cleaning device %s is on" 1138 " disk error %d\n", parent->sdev_path, error)); 1139 } 1140 1141 if (error == EBUSY) 1142 error = 0; 1143 } 1144 1145 return (error); 1146 } 1147 1148 /* 1149 * read the contents of a symbolic link 1150 */ 1151 static int 1152 sdev_readlink(struct vnode *vp, struct uio *uiop, struct cred *cred) 1153 { 1154 struct sdev_node *dv; 1155 int error = 0; 1156 1157 ASSERT(vp->v_type == VLNK); 1158 1159 dv = VTOSDEV(vp); 1160 1161 if (dv->sdev_attrvp) { 1162 /* non-NULL attrvp implys a persisted node at READY state */ 1163 return (VOP_READLINK(dv->sdev_attrvp, uiop, cred)); 1164 } else if (dv->sdev_symlink != NULL) { 1165 /* memory nodes, e.g. local nodes */ 1166 rw_enter(&dv->sdev_contents, RW_READER); 1167 sdcmn_err2(("sdev_readlink link is %s\n", dv->sdev_symlink)); 1168 error = uiomove(dv->sdev_symlink, strlen(dv->sdev_symlink), 1169 UIO_READ, uiop); 1170 rw_exit(&dv->sdev_contents); 1171 return (error); 1172 } 1173 1174 return (ENOENT); 1175 } 1176 1177 static int 1178 sdev_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp) 1179 { 1180 struct sdev_node *parent = VTOSDEV(dvp); 1181 int error; 1182 1183 /* execute access is required to search the directory */ 1184 if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred)) != 0) 1185 return (error); 1186 1187 ASSERT(parent); 1188 if (!SDEV_IS_GLOBAL(parent)) 1189 prof_filldir(parent); 1190 return (devname_readdir_func(dvp, uiop, cred, eofp, SDEV_BROWSE)); 1191 } 1192 1193 /*ARGSUSED1*/ 1194 static void 1195 sdev_inactive(struct vnode *vp, struct cred *cred) 1196 { 1197 int clean; 1198 struct sdev_node *dv = VTOSDEV(vp); 1199 struct sdev_node *ddv = dv->sdev_dotdot; 1200 struct sdev_node *idv; 1201 struct sdev_node *prev = NULL; 1202 int state; 1203 struct devname_nsmap *map = NULL; 1204 struct devname_ops *dirops = NULL; 1205 void (*fn)(devname_handle_t *, struct cred *) = NULL; 1206 1207 rw_enter(&ddv->sdev_contents, RW_WRITER); 1208 state = dv->sdev_state; 1209 1210 mutex_enter(&vp->v_lock); 1211 ASSERT(vp->v_count >= 1); 1212 1213 clean = (vp->v_count == 1) && (state == SDEV_ZOMBIE); 1214 1215 /* 1216 * last ref count on the ZOMBIE node is released. 1217 * clean up the sdev_node, and 1218 * release the hold on the backing store node so that 1219 * the ZOMBIE backing stores also cleaned out. 1220 */ 1221 if (clean) { 1222 ASSERT(ddv); 1223 if (SDEV_IS_GLOBAL(dv)) { 1224 map = ddv->sdev_mapinfo; 1225 dirops = map ? map->dir_ops : NULL; 1226 if (dirops && (fn = dirops->devnops_inactive)) 1227 (*fn)(&(dv->sdev_handle), cred); 1228 } 1229 1230 ddv->sdev_nlink--; 1231 if (vp->v_type == VDIR) { 1232 dv->sdev_nlink--; 1233 } 1234 for (idv = ddv->sdev_dot; idv && idv != dv; 1235 prev = idv, idv = idv->sdev_next); 1236 ASSERT(idv == dv); 1237 if (prev == NULL) 1238 ddv->sdev_dot = dv->sdev_next; 1239 else 1240 prev->sdev_next = dv->sdev_next; 1241 dv->sdev_next = NULL; 1242 dv->sdev_nlink--; 1243 --vp->v_count; 1244 mutex_exit(&vp->v_lock); 1245 sdev_nodedestroy(dv, 0); 1246 } else { 1247 --vp->v_count; 1248 mutex_exit(&vp->v_lock); 1249 } 1250 rw_exit(&ddv->sdev_contents); 1251 } 1252 1253 static int 1254 sdev_fid(struct vnode *vp, struct fid *fidp) 1255 { 1256 struct sdev_node *dv = VTOSDEV(vp); 1257 struct sdev_fid *sdev_fid; 1258 1259 if (fidp->fid_len < (sizeof (struct sdev_fid) - sizeof (ushort_t))) { 1260 fidp->fid_len = sizeof (struct sdev_fid) - sizeof (ushort_t); 1261 return (ENOSPC); 1262 } 1263 1264 sdev_fid = (struct sdev_fid *)fidp; 1265 bzero(sdev_fid, sizeof (struct sdev_fid)); 1266 sdev_fid->sdevfid_len = 1267 (int)sizeof (struct sdev_fid) - sizeof (ushort_t); 1268 sdev_fid->sdevfid_ino = dv->sdev_ino; 1269 1270 return (0); 1271 } 1272 1273 /* 1274 * This pair of routines bracket all VOP_READ, VOP_WRITE 1275 * and VOP_READDIR requests. The contents lock stops things 1276 * moving around while we're looking at them. 1277 */ 1278 /*ARGSUSED2*/ 1279 static int 1280 sdev_rwlock(struct vnode *vp, int write_flag, caller_context_t *ctp) 1281 { 1282 rw_enter(&VTOSDEV(vp)->sdev_contents, 1283 write_flag ? RW_WRITER : RW_READER); 1284 return (write_flag ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE); 1285 } 1286 1287 /*ARGSUSED1*/ 1288 static void 1289 sdev_rwunlock(struct vnode *vp, int write_flag, caller_context_t *ctp) 1290 { 1291 rw_exit(&VTOSDEV(vp)->sdev_contents); 1292 } 1293 1294 /*ARGSUSED1*/ 1295 static int 1296 sdev_seek(struct vnode *vp, offset_t ooff, offset_t *noffp) 1297 { 1298 struct vnode *attrvp = VTOSDEV(vp)->sdev_attrvp; 1299 1300 ASSERT(vp->v_type != VCHR && 1301 vp->v_type != VBLK && vp->v_type != VLNK); 1302 1303 if (vp->v_type == VDIR) 1304 return (fs_seek(vp, ooff, noffp)); 1305 1306 ASSERT(attrvp); 1307 return (VOP_SEEK(attrvp, ooff, noffp)); 1308 } 1309 1310 /*ARGSUSED1*/ 1311 static int 1312 sdev_frlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag, 1313 offset_t offset, struct flk_callback *flk_cbp, struct cred *cr) 1314 { 1315 int error; 1316 struct sdev_node *dv = VTOSDEV(vp); 1317 1318 ASSERT(dv); 1319 ASSERT(dv->sdev_attrvp); 1320 error = VOP_FRLOCK(dv->sdev_attrvp, cmd, bfp, flag, offset, 1321 flk_cbp, cr); 1322 1323 return (error); 1324 } 1325 1326 static int 1327 sdev_setfl(struct vnode *vp, int oflags, int nflags, cred_t *cr) 1328 { 1329 struct sdev_node *dv = VTOSDEV(vp); 1330 ASSERT(dv); 1331 ASSERT(dv->sdev_attrvp); 1332 1333 return (VOP_SETFL(dv->sdev_attrvp, oflags, nflags, cr)); 1334 } 1335 1336 static int 1337 sdev_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr) 1338 { 1339 switch (cmd) { 1340 case _PC_ACL_ENABLED: 1341 *valp = SDEV_ACL_FLAVOR(vp); 1342 return (0); 1343 } 1344 1345 return (fs_pathconf(vp, cmd, valp, cr)); 1346 } 1347 1348 vnodeops_t *sdev_vnodeops; 1349 1350 const fs_operation_def_t sdev_vnodeops_tbl[] = { 1351 VOPNAME_OPEN, { .vop_open = sdev_open }, 1352 VOPNAME_CLOSE, { .vop_close = sdev_close }, 1353 VOPNAME_READ, { .vop_read = sdev_read }, 1354 VOPNAME_WRITE, { .vop_write = sdev_write }, 1355 VOPNAME_IOCTL, { .vop_ioctl = sdev_ioctl }, 1356 VOPNAME_GETATTR, { .vop_getattr = sdev_getattr }, 1357 VOPNAME_SETATTR, { .vop_setattr = sdev_setattr }, 1358 VOPNAME_ACCESS, { .vop_access = sdev_access }, 1359 VOPNAME_LOOKUP, { .vop_lookup = sdev_lookup }, 1360 VOPNAME_CREATE, { .vop_create = sdev_create }, 1361 VOPNAME_RENAME, { .vop_rename = sdev_rename }, 1362 VOPNAME_REMOVE, { .vop_remove = sdev_remove }, 1363 VOPNAME_MKDIR, { .vop_mkdir = sdev_mkdir }, 1364 VOPNAME_RMDIR, { .vop_rmdir = sdev_rmdir }, 1365 VOPNAME_READDIR, { .vop_readdir = sdev_readdir }, 1366 VOPNAME_SYMLINK, { .vop_symlink = sdev_symlink }, 1367 VOPNAME_READLINK, { .vop_readlink = sdev_readlink }, 1368 VOPNAME_INACTIVE, { .vop_inactive = sdev_inactive }, 1369 VOPNAME_FID, { .vop_fid = sdev_fid }, 1370 VOPNAME_RWLOCK, { .vop_rwlock = sdev_rwlock }, 1371 VOPNAME_RWUNLOCK, { .vop_rwunlock = sdev_rwunlock }, 1372 VOPNAME_SEEK, { .vop_seek = sdev_seek }, 1373 VOPNAME_FRLOCK, { .vop_frlock = sdev_frlock }, 1374 VOPNAME_PATHCONF, { .vop_pathconf = sdev_pathconf }, 1375 VOPNAME_SETFL, { .vop_setfl = sdev_setfl }, 1376 VOPNAME_SETSECATTR, { .vop_setsecattr = sdev_setsecattr }, 1377 VOPNAME_GETSECATTR, { .vop_getsecattr = sdev_getsecattr }, 1378 NULL, NULL 1379 }; 1380 1381 int sdev_vnodeops_tbl_size = sizeof (sdev_vnodeops_tbl); 1382