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