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