1/* 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright 1997,1998 Julian Elischer. All rights reserved. 30 * julian@freebsd.org 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions are 34 * met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright notice, 38 * this list of conditions and the following disclaimer in the documentation 39 * and/or other materials provided with the distribution. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS 42 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 43 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR 45 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 47 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 48 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * devfs_vnops.c 54 */ 55 56/* 57 * HISTORY 58 * Clark Warner (warner_c@apple.com) Tue Feb 10 2000 59 * - Added err_copyfile to the vnode operations table 60 * Dieter Siegmund (dieter@apple.com) Thu Apr 8 14:08:19 PDT 1999 61 * - instead of duplicating specfs here, created a vnode-ops table 62 * that redirects most operations to specfs (as is done with ufs); 63 * - removed routines that made no sense 64 * - cleaned up reclaim: replaced devfs_vntodn() with a macro VTODN() 65 * - cleaned up symlink, link locking 66 * - added the devfs_lock to protect devfs data structures against 67 * driver's calling devfs_add_devswf()/etc. 68 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999 69 * - free the devfs devnode in devfs_inactive(), not just in devfs_reclaim() 70 * to free up kernel memory as soon as it's available 71 * - got rid of devfsspec_{read, write} 72 * Dieter Siegmund (dieter@apple.com) Fri Sep 17 09:58:38 PDT 1999 73 * - update the mod/access times 74 */ 75/* 76 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 77 * support for mandatory and extensible security protections. This notice 78 * is included in support of clause 2.2 (b) of the Apple Public License, 79 * Version 2.0. 80 */ 81 82#include <sys/param.h> 83#include <sys/systm.h> 84#include <sys/namei.h> 85#include <sys/kernel.h> 86#include <sys/fcntl.h> 87#include <sys/conf.h> 88#include <sys/disklabel.h> 89#include <sys/lock.h> 90#include <sys/stat.h> 91#include <sys/mount_internal.h> 92#include <sys/proc.h> 93#include <sys/kauth.h> 94#include <sys/time.h> 95#include <sys/vnode_internal.h> 96#include <miscfs/specfs/specdev.h> 97#include <sys/dirent.h> 98#include <sys/vmmeter.h> 99#include <sys/vm.h> 100#include <sys/uio_internal.h> 101 102#if CONFIG_MACF 103#include <security/mac_framework.h> 104#endif 105 106#include "devfsdefs.h" 107 108static int devfs_update(struct vnode *vp, struct timeval *access, 109 struct timeval *modify); 110 111 112/* 113 * Convert a component of a pathname into a pointer to a locked node. 114 * This is a very central and rather complicated routine. 115 * If the file system is not maintained in a strict tree hierarchy, 116 * this can result in a deadlock situation (see comments in code below). 117 * 118 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 119 * whether the name is to be looked up, created, renamed, or deleted. 120 * When CREATE, RENAME, or DELETE is specified, information usable in 121 * creating, renaming, or deleting a directory entry may be calculated. 122 * If flag has LOCKPARENT or'ed into it and the target of the pathname 123 * exists, lookup returns both the target and its parent directory locked. 124 * When creating or renaming and LOCKPARENT is specified, the target may 125 * not be ".". When deleting and LOCKPARENT is specified, the target may 126 * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK 127 * instead of two DNUNLOCKs. 128 * 129 * Overall outline of devfs_lookup: 130 * 131 * check accessibility of directory 132 * null terminate the component (lookup leaves the whole string alone) 133 * look for name in cache, if found, then if at end of path 134 * and deleting or creating, drop it, else return name 135 * search for name in directory, to found or notfound 136 * notfound: 137 * if creating, return locked directory, 138 * else return error 139 * found: 140 * if at end of path and deleting, return information to allow delete 141 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 142 * node and return info to allow rewrite 143 * if not at end, add name to cache; if at end and neither creating 144 * nor deleting, add name to cache 145 * On return to lookup, remove the null termination we put in at the start. 146 * 147 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked. 148 */ 149static int 150devfs_lookup(struct vnop_lookup_args *ap) 151 /*struct vnop_lookup_args { 152 struct vnode * a_dvp; directory vnode ptr 153 struct vnode ** a_vpp; where to put the result 154 struct componentname * a_cnp; the name we want 155 vfs_context_t a_context; 156 };*/ 157{ 158 struct componentname *cnp = ap->a_cnp; 159 vfs_context_t ctx = cnp->cn_context; 160 struct proc *p = vfs_context_proc(ctx); 161 struct vnode *dir_vnode = ap->a_dvp; 162 struct vnode **result_vnode = ap->a_vpp; 163 devnode_t * dir_node; /* the directory we are searching */ 164 devnode_t * node = NULL; /* the node we are searching for */ 165 devdirent_t * nodename; 166 int flags = cnp->cn_flags; 167 int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */ 168 int wantparent = flags & (LOCKPARENT|WANTPARENT); 169 int error = 0; 170 char heldchar; /* the char at the end of the name componet */ 171 172retry: 173 174 *result_vnode = NULL; /* safe not sorry */ /*XXX*/ 175 176 /* okay to look at directory vnodes ourside devfs lock as they are not aliased */ 177 dir_node = VTODN(dir_vnode); 178 179 /* 180 * Make sure that our node is a directory as well. 181 */ 182 if (dir_node->dn_type != DEV_DIR) { 183 return (ENOTDIR); 184 } 185 186 DEVFS_LOCK(); 187 /* 188 * temporarily terminate string component 189 */ 190 heldchar = cnp->cn_nameptr[cnp->cn_namelen]; 191 cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 192 193 nodename = dev_findname(dir_node, cnp->cn_nameptr); 194 /* 195 * restore saved character 196 */ 197 cnp->cn_nameptr[cnp->cn_namelen] = heldchar; 198 199 if (nodename) { 200 /* entry exists */ 201 node = nodename->de_dnp; 202 203 /* Do potential vnode allocation here inside the lock 204 * to make sure that our device node has a non-NULL dn_vn 205 * associated with it. The device node might otherwise 206 * get deleted out from under us (see devfs_dn_free()). 207 */ 208 error = devfs_dntovn(node, result_vnode, p); 209 } 210 DEVFS_UNLOCK(); 211 212 if (error) { 213 if (error == EAGAIN) 214 goto retry; 215 return error; 216 } 217 if (!nodename) { 218 /* 219 * we haven't called devfs_dntovn if we get here 220 * we have not taken a reference on the node.. no 221 * vnode_put is necessary on these error returns 222 * 223 * If it doesn't exist and we're not the last component, 224 * or we're at the last component, but we're not creating 225 * or renaming, return ENOENT. 226 */ 227 if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) { 228 return ENOENT; 229 } 230 /* 231 * We return with the directory locked, so that 232 * the parameters we set up above will still be 233 * valid if we actually decide to add a new entry. 234 * We return ni_vp == NULL to indicate that the entry 235 * does not currently exist; we leave a pointer to 236 * the (locked) directory vnode in namei_data->ni_dvp. 237 * 238 * NB - if the directory is unlocked, then this 239 * information cannot be used. 240 */ 241 return (EJUSTRETURN); 242 } 243 /* 244 * from this point forward, we need to vnode_put the reference 245 * picked up in devfs_dntovn if we decide to return an error 246 */ 247 248 /* 249 * If deleting, and at end of pathname, return 250 * parameters which can be used to remove file. 251 * If the wantparent flag isn't set, we return only 252 * the directory (in namei_data->ni_dvp), otherwise we go 253 * on and lock the node, being careful with ".". 254 */ 255 if (op == DELETE && (flags & ISLASTCN)) { 256 257 /* 258 * we are trying to delete '.'. What does this mean? XXX 259 */ 260 if (dir_node == node) { 261 if (*result_vnode) { 262 vnode_put(*result_vnode); 263 *result_vnode = NULL; 264 } 265 if ( ((error = vnode_get(dir_vnode)) == 0) ) { 266 *result_vnode = dir_vnode; 267 } 268 return (error); 269 } 270 return (0); 271 } 272 273 /* 274 * If rewriting (RENAME), return the vnode and the 275 * information required to rewrite the present directory 276 * Must get node of directory entry to verify it's a 277 * regular file, or empty directory. 278 */ 279 if (op == RENAME && wantparent && (flags & ISLASTCN)) { 280 281 /* 282 * Careful about locking second node. 283 * This can only occur if the target is ".". 284 */ 285 if (dir_node == node) { 286 error = EISDIR; 287 goto drop_ref; 288 } 289 return (0); 290 } 291 292 /* 293 * Step through the translation in the name. We do not unlock the 294 * directory because we may need it again if a symbolic link 295 * is relative to the current directory. Instead we save it 296 * unlocked as "saved_dir_node" XXX. We must get the target 297 * node before unlocking 298 * the directory to insure that the node will not be removed 299 * before we get it. We prevent deadlock by always fetching 300 * nodes from the root, moving down the directory tree. Thus 301 * when following backward pointers ".." we must unlock the 302 * parent directory before getting the requested directory. 303 * There is a potential race condition here if both the current 304 * and parent directories are removed before the lock for the 305 * node associated with ".." returns. We hope that this occurs 306 * infrequently since we cannot avoid this race condition without 307 * implementing a sophisticated deadlock detection algorithm. 308 * Note also that this simple deadlock detection scheme will not 309 * work if the file system has any hard links other than ".." 310 * that point backwards in the directory structure. 311 */ 312 if ((flags & ISDOTDOT) == 0 && dir_node == node) { 313 if (*result_vnode) { 314 vnode_put(*result_vnode); 315 *result_vnode = NULL; 316 } 317 if ( (error = vnode_get(dir_vnode)) ) { 318 return (error); 319 } 320 *result_vnode = dir_vnode; 321 } 322 return (0); 323 324drop_ref: 325 if (*result_vnode) { 326 vnode_put(*result_vnode); 327 *result_vnode = NULL; 328 } 329 return (error); 330} 331 332static int 333devfs_getattr(struct vnop_getattr_args *ap) 334 /*struct vnop_getattr_args { 335 struct vnode *a_vp; 336 struct vnode_attr *a_vap; 337 kauth_cred_t a_cred; 338 struct proc *a_p; 339 } */ 340{ 341 struct vnode *vp = ap->a_vp; 342 struct vnode_attr *vap = ap->a_vap; 343 devnode_t * file_node; 344 struct timeval now; 345 346 347 DEVFS_LOCK(); 348 file_node = VTODN(vp); 349 350 microtime(&now); 351 dn_times(file_node, &now, &now, &now); 352 353 VATTR_RETURN(vap, va_mode, file_node->dn_mode); 354 355 /* 356 * Note: for DEV_CDEV and DEV_BDEV, we return the device from 357 * the vp, not the file_node; if we getting information on a 358 * cloning device, we want the cloned information, not the template. 359 */ 360 switch (file_node->dn_type) 361 { 362 case DEV_DIR: 363 VATTR_RETURN(vap, va_rdev, (dev_t)file_node->dn_dvm); 364 vap->va_mode |= (S_IFDIR); 365 break; 366 case DEV_CDEV: 367 VATTR_RETURN(vap, va_rdev, vp->v_rdev); 368 vap->va_mode |= (S_IFCHR); 369 break; 370 case DEV_BDEV: 371 VATTR_RETURN(vap, va_rdev, vp->v_rdev); 372 vap->va_mode |= (S_IFBLK); 373 break; 374 case DEV_SLNK: 375 VATTR_RETURN(vap, va_rdev, 0); 376 vap->va_mode |= (S_IFLNK); 377 break; 378 default: 379 VATTR_RETURN(vap, va_rdev, 0); /* default value only */ 380 } 381 VATTR_RETURN(vap, va_type, vp->v_type); 382 VATTR_RETURN(vap, va_nlink, file_node->dn_links); 383 VATTR_RETURN(vap, va_uid, file_node->dn_uid); 384 VATTR_RETURN(vap, va_gid, file_node->dn_gid); 385 VATTR_RETURN(vap, va_fsid, (uintptr_t)file_node->dn_dvm); 386 VATTR_RETURN(vap, va_fileid, (uintptr_t)file_node); 387 VATTR_RETURN(vap, va_data_size, file_node->dn_len); 388 389 /* return an override block size (advisory) */ 390 if (vp->v_type == VBLK) 391 VATTR_RETURN(vap, va_iosize, BLKDEV_IOSIZE); 392 else if (vp->v_type == VCHR) 393 VATTR_RETURN(vap, va_iosize, MAXPHYSIO); 394 else 395 VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize); 396 /* if the time is bogus, set it to the boot time */ 397 if (file_node->dn_ctime.tv_sec == 0) { 398 file_node->dn_ctime.tv_sec = boottime_sec(); 399 file_node->dn_ctime.tv_nsec = 0; 400 } 401 if (file_node->dn_mtime.tv_sec == 0) 402 file_node->dn_mtime = file_node->dn_ctime; 403 if (file_node->dn_atime.tv_sec == 0) 404 file_node->dn_atime = file_node->dn_ctime; 405 VATTR_RETURN(vap, va_change_time, file_node->dn_ctime); 406 VATTR_RETURN(vap, va_modify_time, file_node->dn_mtime); 407 VATTR_RETURN(vap, va_access_time, file_node->dn_atime); 408 VATTR_RETURN(vap, va_gen, 0); 409 VATTR_RETURN(vap, va_flags, 0); 410 VATTR_RETURN(vap, va_filerev, 0); 411 VATTR_RETURN(vap, va_acl, NULL); 412 413 DEVFS_UNLOCK(); 414 415 return 0; 416} 417 418static int 419devfs_setattr(struct vnop_setattr_args *ap) 420 /*struct vnop_setattr_args { 421 struct vnode *a_vp; 422 struct vnode_attr *a_vap; 423 vfs_context_t a_context; 424 } */ 425{ 426 struct vnode *vp = ap->a_vp; 427 struct vnode_attr *vap = ap->a_vap; 428 int error = 0; 429 devnode_t * file_node; 430 struct timeval atimeval, mtimeval; 431 432 DEVFS_LOCK(); 433 434 file_node = VTODN(vp); 435 /* 436 * Go through the fields and update if set. 437 */ 438 if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) { 439 440 441 if (VATTR_IS_ACTIVE(vap, va_access_time)) 442 file_node->dn_access = 1; 443 if (VATTR_IS_ACTIVE(vap, va_modify_time)) { 444 file_node->dn_change = 1; 445 file_node->dn_update = 1; 446 } 447 atimeval.tv_sec = vap->va_access_time.tv_sec; 448 atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000; 449 mtimeval.tv_sec = vap->va_modify_time.tv_sec; 450 mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000; 451 452 if ( (error = devfs_update(vp, &atimeval, &mtimeval)) ) 453 goto exit; 454 } 455 VATTR_SET_SUPPORTED(vap, va_access_time); 456 VATTR_SET_SUPPORTED(vap, va_change_time); 457 458 /* 459 * Change the permissions. 460 */ 461 if (VATTR_IS_ACTIVE(vap, va_mode)) { 462 file_node->dn_mode &= ~07777; 463 file_node->dn_mode |= vap->va_mode & 07777; 464 } 465 VATTR_SET_SUPPORTED(vap, va_mode); 466 467 /* 468 * Change the owner. 469 */ 470 if (VATTR_IS_ACTIVE(vap, va_uid)) 471 file_node->dn_uid = vap->va_uid; 472 VATTR_SET_SUPPORTED(vap, va_uid); 473 474 /* 475 * Change the group. 476 */ 477 if (VATTR_IS_ACTIVE(vap, va_gid)) 478 file_node->dn_gid = vap->va_gid; 479 VATTR_SET_SUPPORTED(vap, va_gid); 480 exit: 481 DEVFS_UNLOCK(); 482 483 return error; 484} 485 486#if CONFIG_MACF 487static int 488devfs_setlabel(struct vnop_setlabel_args *ap) 489 /* struct vnop_setlabel_args { 490 struct vnodeop_desc *a_desc; 491 struct vnode *a_vp; 492 struct label *a_vl; 493 vfs_context_t a_context; 494 } */ 495{ 496 struct vnode *vp; 497 struct devnode *de; 498 499 vp = ap->a_vp; 500 de = VTODN(vp); 501 502 mac_vnode_label_update(ap->a_context, vp, ap->a_vl); 503 mac_devfs_label_update(vp->v_mount, de, vp); 504 505 return (0); 506} 507#endif 508 509static int 510devfs_read(struct vnop_read_args *ap) 511 /* struct vnop_read_args { 512 struct vnode *a_vp; 513 struct uio *a_uio; 514 int a_ioflag; 515 vfs_context_t a_context; 516 } */ 517{ 518 devnode_t * dn_p = VTODN(ap->a_vp); 519 520 switch (ap->a_vp->v_type) { 521 case VDIR: { 522 dn_p->dn_access = 1; 523 524 return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context); 525 } 526 default: { 527 printf("devfs_read(): bad file type %d", ap->a_vp->v_type); 528 return(EINVAL); 529 break; 530 } 531 } 532 return (0); /* not reached */ 533} 534 535static int 536devfs_close(struct vnop_close_args *ap) 537 /* struct vnop_close_args { 538 struct vnode *a_vp; 539 int a_fflag; 540 vfs_context_t a_context; 541 } */ 542{ 543 struct vnode * vp = ap->a_vp; 544 register devnode_t * dnp; 545 struct timeval now; 546 547 if (vnode_isinuse(vp, 1)) { 548 DEVFS_LOCK(); 549 dnp = VTODN(vp); 550 microtime(&now); 551 dn_times(dnp, &now, &now, &now); 552 DEVFS_UNLOCK(); 553 } 554 return (0); 555} 556 557static int 558devfsspec_close(struct vnop_close_args *ap) 559 /* struct vnop_close_args { 560 struct vnode *a_vp; 561 int a_fflag; 562 vfs_context_t a_context; 563 } */ 564{ 565 struct vnode * vp = ap->a_vp; 566 register devnode_t * dnp; 567 struct timeval now; 568 int ref = 1; 569 570 if (vp->v_type == VBLK) 571 ref = 0; 572 573 if (vnode_isinuse(vp, ref)) { 574 DEVFS_LOCK(); 575 microtime(&now); 576 dnp = VTODN(vp); 577 dn_times(dnp, &now, &now, &now); 578 DEVFS_UNLOCK(); 579 } 580 581 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_close), ap)); 582} 583 584static int 585devfsspec_read(struct vnop_read_args *ap) 586 /* struct vnop_read_args { 587 struct vnode *a_vp; 588 struct uio *a_uio; 589 int a_ioflag; 590 kauth_cred_t a_cred; 591 } */ 592{ 593 register devnode_t * dnp = VTODN(ap->a_vp); 594 595 dnp->dn_access = 1; 596 597 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_read), ap)); 598} 599 600static int 601devfsspec_write(struct vnop_write_args *ap) 602 /* struct vnop_write_args { 603 struct vnode *a_vp; 604 struct uio *a_uio; 605 int a_ioflag; 606 vfs_context_t a_context; 607 } */ 608{ 609 register devnode_t * dnp = VTODN(ap->a_vp); 610 611 dnp->dn_change = 1; 612 dnp->dn_update = 1; 613 614 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_write), ap)); 615} 616 617/* 618 * Write data to a file or directory. 619 */ 620static int 621devfs_write(struct vnop_write_args *ap) 622 /* struct vnop_write_args { 623 struct vnode *a_vp; 624 struct uio *a_uio; 625 int a_ioflag; 626 kauth_cred_t a_cred; 627 } */ 628{ 629 switch (ap->a_vp->v_type) { 630 case VDIR: 631 return(EISDIR); 632 default: 633 printf("devfs_write(): bad file type %d", ap->a_vp->v_type); 634 return (EINVAL); 635 } 636 return 0; /* not reached */ 637} 638 639static int 640devfs_remove(struct vnop_remove_args *ap) 641 /* struct vnop_remove_args { 642 struct vnode *a_dvp; 643 struct vnode *a_vp; 644 struct componentname *a_cnp; 645 } */ 646{ 647 struct vnode *vp = ap->a_vp; 648 struct vnode *dvp = ap->a_dvp; 649 struct componentname *cnp = ap->a_cnp; 650 devnode_t * tp; 651 devnode_t * tdp; 652 devdirent_t * tnp; 653 int doingdirectory = 0; 654 int error = 0; 655 656 /* 657 * assume that the name is null terminated as they 658 * are the end of the path. Get pointers to all our 659 * devfs structures. 660 */ 661 DEVFS_LOCK(); 662 663 tp = VTODN(vp); 664 tdp = VTODN(dvp); 665 666 667 tnp = dev_findname(tdp, cnp->cn_nameptr); 668 669 if (tnp == NULL) { 670 error = ENOENT; 671 goto abort; 672 } 673 674 /* 675 * Make sure that we don't try do something stupid 676 */ 677 if ((tp->dn_type) == DEV_DIR) { 678 /* 679 * Avoid ".", "..", and aliases of "." for obvious reasons. 680 */ 681 if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') 682 || (cnp->cn_flags&ISDOTDOT) ) { 683 error = EINVAL; 684 goto abort; 685 } 686 doingdirectory++; 687 } 688 689 /*********************************** 690 * Start actually doing things.... * 691 ***********************************/ 692 tdp->dn_change = 1; 693 tdp->dn_update = 1; 694 695 /* 696 * Target must be empty if a directory and have no links 697 * to it. Also, ensure source and target are compatible 698 * (both directories, or both not directories). 699 */ 700 if (( doingdirectory) && (tp->dn_links > 2)) { 701 error = ENOTEMPTY; 702 goto abort; 703 } 704 dev_free_name(tnp); 705abort: 706 DEVFS_UNLOCK(); 707 708 return (error); 709} 710 711/* 712 */ 713static int 714devfs_link(struct vnop_link_args *ap) 715 /*struct vnop_link_args { 716 struct vnode *a_tdvp; 717 struct vnode *a_vp; 718 struct componentname *a_cnp; 719 vfs_context_t a_context; 720 } */ 721{ 722 struct vnode *vp = ap->a_vp; 723 struct vnode *tdvp = ap->a_tdvp; 724 struct componentname *cnp = ap->a_cnp; 725 devnode_t * fp; 726 devnode_t * tdp; 727 devdirent_t * tnp; 728 int error = 0; 729 struct timeval now; 730 731 /* 732 * First catch an arbitrary restriction for this FS 733 */ 734 if (cnp->cn_namelen > DEVMAXNAMESIZE) { 735 error = ENAMETOOLONG; 736 goto out1; 737 } 738 739 /* 740 * Lock our directories and get our name pointers 741 * assume that the names are null terminated as they 742 * are the end of the path. Get pointers to all our 743 * devfs structures. 744 */ 745 /* can lookup dnode safely for tdvp outside of devfs lock as it is not aliased */ 746 tdp = VTODN(tdvp); 747 748 if (tdvp->v_mount != vp->v_mount) { 749 return (EXDEV); 750 } 751 DEVFS_LOCK(); 752 753 fp = VTODN(vp); 754 755 /*********************************** 756 * Start actually doing things.... * 757 ***********************************/ 758 fp->dn_change = 1; 759 760 microtime(&now); 761 error = devfs_update(vp, &now, &now); 762 763 if (!error) { 764 error = dev_add_name(cnp->cn_nameptr, tdp, NULL, fp, &tnp); 765 } 766out1: 767 DEVFS_UNLOCK(); 768 769 return (error); 770} 771 772/* 773 * Rename system call. Seems overly complicated to me... 774 * rename("foo", "bar"); 775 * is essentially 776 * unlink("bar"); 777 * link("foo", "bar"); 778 * unlink("foo"); 779 * but ``atomically''. 780 * 781 * When the target exists, both the directory 782 * and target vnodes are locked. 783 * the source and source-parent vnodes are referenced 784 * 785 * 786 * Basic algorithm is: 787 * 788 * 1) Bump link count on source while we're linking it to the 789 * target. This also ensure the inode won't be deleted out 790 * from underneath us while we work (it may be truncated by 791 * a concurrent `trunc' or `open' for creation). 792 * 2) Link source to destination. If destination already exists, 793 * delete it first. 794 * 3) Unlink source reference to node if still around. If a 795 * directory was moved and the parent of the destination 796 * is different from the source, patch the ".." entry in the 797 * directory. 798 */ 799static int 800devfs_rename(struct vnop_rename_args *ap) 801 /*struct vnop_rename_args { 802 struct vnode *a_fdvp; 803 struct vnode *a_fvp; 804 struct componentname *a_fcnp; 805 struct vnode *a_tdvp; 806 struct vnode *a_tvp; 807 struct componentname *a_tcnp; 808 vfs_context_t a_context; 809 } */ 810{ 811 struct vnode *tvp = ap->a_tvp; 812 struct vnode *tdvp = ap->a_tdvp; 813 struct vnode *fvp = ap->a_fvp; 814 struct vnode *fdvp = ap->a_fdvp; 815 struct componentname *tcnp = ap->a_tcnp; 816 struct componentname *fcnp = ap->a_fcnp; 817 devnode_t *fp, *fdp, *tp, *tdp; 818 devdirent_t *fnp,*tnp; 819 int doingdirectory = 0; 820 int error = 0; 821 struct timeval now; 822 823 DEVFS_LOCK(); 824 /* 825 * First catch an arbitrary restriction for this FS 826 */ 827 if (tcnp->cn_namelen > DEVMAXNAMESIZE) { 828 error = ENAMETOOLONG; 829 goto out; 830 } 831 832 /* 833 * assume that the names are null terminated as they 834 * are the end of the path. Get pointers to all our 835 * devfs structures. 836 */ 837 tdp = VTODN(tdvp); 838 fdp = VTODN(fdvp); 839 fp = VTODN(fvp); 840 841 fnp = dev_findname(fdp, fcnp->cn_nameptr); 842 843 if (fnp == NULL) { 844 error = ENOENT; 845 goto out; 846 } 847 tp = NULL; 848 tnp = NULL; 849 850 if (tvp) { 851 tnp = dev_findname(tdp, tcnp->cn_nameptr); 852 853 if (tnp == NULL) { 854 error = ENOENT; 855 goto out; 856 } 857 tp = VTODN(tvp); 858 } 859 860 /* 861 * Make sure that we don't try do something stupid 862 */ 863 if ((fp->dn_type) == DEV_DIR) { 864 /* 865 * Avoid ".", "..", and aliases of "." for obvious reasons. 866 */ 867 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') 868 || (fcnp->cn_flags&ISDOTDOT) 869 || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.') 870 || (tcnp->cn_flags&ISDOTDOT) 871 || (tdp == fp )) { 872 error = EINVAL; 873 goto out; 874 } 875 doingdirectory++; 876 } 877 878 /* 879 * If ".." must be changed (ie the directory gets a new 880 * parent) then the source directory must not be in the 881 * directory hierarchy above the target, as this would 882 * orphan everything below the source directory. Also 883 * the user must have write permission in the source so 884 * as to be able to change "..". 885 */ 886 if (doingdirectory && (tdp != fdp)) { 887 devnode_t * tmp, *ntmp; 888 tmp = tdp; 889 do { 890 if(tmp == fp) { 891 /* XXX unlock stuff here probably */ 892 error = EINVAL; 893 goto out; 894 } 895 ntmp = tmp; 896 } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp); 897 } 898 899 /*********************************** 900 * Start actually doing things.... * 901 ***********************************/ 902 fp->dn_change = 1; 903 microtime(&now); 904 905 if ( (error = devfs_update(fvp, &now, &now)) ) { 906 goto out; 907 } 908 /* 909 * Check if just deleting a link name. 910 */ 911 if (fvp == tvp) { 912 if (fvp->v_type == VDIR) { 913 error = EINVAL; 914 goto out; 915 } 916 /* Release destination completely. */ 917 dev_free_name(fnp); 918 919 DEVFS_UNLOCK(); 920 return 0; 921 } 922 /* 923 * 1) Bump link count while we're moving stuff 924 * around. If we crash somewhere before 925 * completing our work, too bad :) 926 */ 927 fp->dn_links++; 928 /* 929 * If the target exists zap it (unless it's a non-empty directory) 930 * We could do that as well but won't 931 */ 932 if (tp) { 933 /* 934 * Target must be empty if a directory and have no links 935 * to it. Also, ensure source and target are compatible 936 * (both directories, or both not directories). 937 */ 938 if (( doingdirectory) && (tp->dn_links > 2)) { 939 error = ENOTEMPTY; 940 goto bad; 941 } 942 dev_free_name(tnp); 943 tp = NULL; 944 } 945 dev_add_name(tcnp->cn_nameptr,tdp,NULL,fp,&tnp); 946 fnp->de_dnp = NULL; 947 fp->dn_links--; /* one less link to it.. */ 948 949 dev_free_name(fnp); 950bad: 951 fp->dn_links--; /* we added one earlier*/ 952out: 953 DEVFS_UNLOCK(); 954 return (error); 955} 956 957static int 958devfs_mkdir(struct vnop_mkdir_args *ap) 959 /*struct vnop_mkdir_args { 960 struct vnode *a_dvp; 961 struct vnode **a_vpp; 962 struct componentname *a_cnp; 963 struct vnode_attr *a_vap; 964 vfs_context_t a_context; 965 } */ 966{ 967 struct componentname * cnp = ap->a_cnp; 968 vfs_context_t ctx = cnp->cn_context; 969 struct proc *p = vfs_context_proc(ctx); 970 int error = 0; 971 devnode_t * dir_p; 972 devdirent_t * nm_p; 973 devnode_t * dev_p; 974 struct vnode_attr * vap = ap->a_vap; 975 struct vnode * * vpp = ap->a_vpp; 976 977 DEVFS_LOCK(); 978 979 dir_p = VTODN(ap->a_dvp); 980 error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_DIR, 981 NULL, NULL, NULL, &nm_p); 982 if (error) { 983 goto failure; 984 } 985 dev_p = nm_p->de_dnp; 986 dev_p->dn_uid = dir_p->dn_uid; 987 dev_p->dn_gid = dir_p->dn_gid; 988 dev_p->dn_mode = vap->va_mode; 989 dn_copy_times(dev_p, dir_p); 990 991 error = devfs_dntovn(dev_p, vpp, p); 992failure: 993 DEVFS_UNLOCK(); 994 995 return error; 996} 997 998/* 999 * An rmdir is a special type of remove, which we already support; we wrap 1000 * and reexpress the arguments to call devfs_remove directly. The only 1001 * different argument is flags, which we do not set, since it's ignored. 1002 */ 1003static int 1004devfs_rmdir(struct vnop_rmdir_args *ap) 1005 /* struct vnop_rmdir_args { 1006 struct vnode *a_dvp; 1007 struct vnode *a_vp; 1008 struct componentname *a_cnp; 1009 vfs_context_t a_context; 1010 } */ 1011{ 1012 struct vnop_remove_args ra; 1013 1014 ra.a_dvp = ap->a_dvp; 1015 ra.a_vp = ap->a_vp; 1016 ra.a_cnp = ap->a_cnp; 1017 ra.a_flags = 0; /* XXX */ 1018 ra.a_context = ap->a_context; 1019 1020 return devfs_remove(&ra); 1021} 1022 1023 1024static int 1025devfs_symlink(struct vnop_symlink_args *ap) 1026 /*struct vnop_symlink_args { 1027 struct vnode *a_dvp; 1028 struct vnode **a_vpp; 1029 struct componentname *a_cnp; 1030 struct vnode_attr *a_vap; 1031 char *a_target; 1032 vfs_context_t a_context; 1033 } */ 1034{ 1035 struct componentname * cnp = ap->a_cnp; 1036 vfs_context_t ctx = cnp->cn_context; 1037 struct proc *p = vfs_context_proc(ctx); 1038 int error = 0; 1039 devnode_t * dir_p; 1040 devnode_type_t typeinfo; 1041 devdirent_t * nm_p; 1042 devnode_t * dev_p; 1043 struct vnode_attr * vap = ap->a_vap; 1044 struct vnode * * vpp = ap->a_vpp; 1045 1046 typeinfo.Slnk.name = ap->a_target; 1047 typeinfo.Slnk.namelen = strlen(ap->a_target); 1048 1049 DEVFS_LOCK(); 1050 1051 dir_p = VTODN(ap->a_dvp); 1052 1053 error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK, 1054 &typeinfo, NULL, NULL, &nm_p); 1055 if (error) { 1056 goto failure; 1057 } 1058 dev_p = nm_p->de_dnp; 1059 dev_p->dn_uid = dir_p->dn_uid; 1060 dev_p->dn_gid = dir_p->dn_gid; 1061 dev_p->dn_mode = vap->va_mode; 1062 dn_copy_times(dev_p, dir_p); 1063 1064 error = devfs_dntovn(dev_p, vpp, p); 1065failure: 1066 DEVFS_UNLOCK(); 1067 1068 return error; 1069} 1070 1071/* 1072 * Mknod vnode call 1073 */ 1074static int 1075devfs_mknod(struct vnop_mknod_args *ap) 1076 /* struct vnop_mknod_args { 1077 struct vnode *a_dvp; 1078 struct vnode **a_vpp; 1079 struct componentname *a_cnp; 1080 struct vnode_attr *a_vap; 1081 vfs_context_t a_context; 1082 } */ 1083{ 1084 struct componentname * cnp = ap->a_cnp; 1085 vfs_context_t ctx = cnp->cn_context; 1086 struct proc *p = vfs_context_proc(ctx); 1087 devnode_t * dev_p; 1088 devdirent_t * devent; 1089 devnode_t * dir_p; /* devnode for parent directory */ 1090 struct vnode * dvp = ap->a_dvp; 1091 int error = 0; 1092 devnode_type_t typeinfo; 1093 struct vnode_attr * vap = ap->a_vap; 1094 struct vnode ** vpp = ap->a_vpp; 1095 1096 *vpp = NULL; 1097 if (!(vap->va_type == VBLK) && !(vap->va_type == VCHR)) { 1098 return (EINVAL); /* only support mknod of special files */ 1099 } 1100 typeinfo.dev = vap->va_rdev; 1101 1102 DEVFS_LOCK(); 1103 1104 dir_p = VTODN(dvp); 1105 1106 error = dev_add_entry(cnp->cn_nameptr, dir_p, 1107 (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV, 1108 &typeinfo, NULL, NULL, &devent); 1109 if (error) { 1110 goto failure; 1111 } 1112 dev_p = devent->de_dnp; 1113 error = devfs_dntovn(dev_p, vpp, p); 1114 if (error) 1115 goto failure; 1116 dev_p->dn_uid = vap->va_uid; 1117 dev_p->dn_gid = vap->va_gid; 1118 dev_p->dn_mode = vap->va_mode; 1119 VATTR_SET_SUPPORTED(vap, va_uid); 1120 VATTR_SET_SUPPORTED(vap, va_gid); 1121 VATTR_SET_SUPPORTED(vap, va_mode); 1122failure: 1123 DEVFS_UNLOCK(); 1124 1125 return (error); 1126} 1127 1128/* 1129 * Vnode op for readdir 1130 */ 1131static int 1132devfs_readdir(struct vnop_readdir_args *ap) 1133 /*struct vnop_readdir_args { 1134 struct vnode *a_vp; 1135 struct uio *a_uio; 1136 int a_flags; 1137 int *a_eofflag; 1138 int *a_numdirent; 1139 vfs_context_t a_context; 1140 } */ 1141{ 1142 struct vnode *vp = ap->a_vp; 1143 struct uio *uio = ap->a_uio; 1144 struct dirent dirent; 1145 devnode_t * dir_node; 1146 devdirent_t * name_node; 1147 const char *name; 1148 int error = 0; 1149 int reclen; 1150 int nodenumber; 1151 int startpos,pos; 1152 1153 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) 1154 return (EINVAL); 1155 1156 /* set up refs to dir */ 1157 dir_node = VTODN(vp); 1158 if (dir_node->dn_type != DEV_DIR) 1159 return(ENOTDIR); 1160 pos = 0; 1161 startpos = uio->uio_offset; 1162 1163 DEVFS_LOCK(); 1164 1165 name_node = dir_node->dn_typeinfo.Dir.dirlist; 1166 nodenumber = 0; 1167 1168 dir_node->dn_access = 1; 1169 1170 while ((name_node || (nodenumber < 2)) && (uio_resid(uio) > 0)) 1171 { 1172 switch(nodenumber) 1173 { 1174 case 0: 1175 dirent.d_fileno = (int32_t)(void *)dir_node; 1176 name = "."; 1177 dirent.d_namlen = 1; 1178 dirent.d_type = DT_DIR; 1179 break; 1180 case 1: 1181 if(dir_node->dn_typeinfo.Dir.parent) 1182 dirent.d_fileno 1183 = (int32_t)dir_node->dn_typeinfo.Dir.parent; 1184 else 1185 dirent.d_fileno = (u_int32_t)dir_node; 1186 name = ".."; 1187 dirent.d_namlen = 2; 1188 dirent.d_type = DT_DIR; 1189 break; 1190 default: 1191 dirent.d_fileno = (int32_t)(void *)name_node->de_dnp; 1192 dirent.d_namlen = strlen(name_node->de_name); 1193 name = name_node->de_name; 1194 switch(name_node->de_dnp->dn_type) { 1195 case DEV_BDEV: 1196 dirent.d_type = DT_BLK; 1197 break; 1198 case DEV_CDEV: 1199 dirent.d_type = DT_CHR; 1200 break; 1201 case DEV_DIR: 1202 dirent.d_type = DT_DIR; 1203 break; 1204 case DEV_SLNK: 1205 dirent.d_type = DT_LNK; 1206 break; 1207 default: 1208 dirent.d_type = DT_UNKNOWN; 1209 } 1210 } 1211#define GENERIC_DIRSIZ(dp) \ 1212 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) 1213 1214 reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent); 1215 1216 if(pos >= startpos) /* made it to the offset yet? */ 1217 { 1218 if (uio_resid(uio) < reclen) /* will it fit? */ 1219 break; 1220 strlcpy(dirent.d_name, name, DEVMAXNAMESIZE); 1221 if ((error = uiomove ((caddr_t)&dirent, 1222 dirent.d_reclen, uio)) != 0) 1223 break; 1224 } 1225 pos += reclen; 1226 if((nodenumber >1) && name_node) 1227 name_node = name_node->de_next; 1228 nodenumber++; 1229 } 1230 DEVFS_UNLOCK(); 1231 uio->uio_offset = pos; 1232 1233 return (error); 1234} 1235 1236 1237/* 1238 */ 1239static int 1240devfs_readlink(struct vnop_readlink_args *ap) 1241 /*struct vnop_readlink_args { 1242 struct vnode *a_vp; 1243 struct uio *a_uio; 1244 vfs_context_t a_context; 1245 } */ 1246{ 1247 struct vnode *vp = ap->a_vp; 1248 struct uio *uio = ap->a_uio; 1249 devnode_t * lnk_node; 1250 int error = 0; 1251 1252 /* set up refs to dir */ 1253 lnk_node = VTODN(vp); 1254 1255 if (lnk_node->dn_type != DEV_SLNK) { 1256 error = EINVAL; 1257 goto out; 1258 } 1259 error = uiomove(lnk_node->dn_typeinfo.Slnk.name, 1260 lnk_node->dn_typeinfo.Slnk.namelen, uio); 1261out: 1262 return error; 1263} 1264 1265static int 1266devfs_reclaim(struct vnop_reclaim_args *ap) 1267 /*struct vnop_reclaim_args { 1268 struct vnode *a_vp; 1269 } */ 1270{ 1271 struct vnode * vp = ap->a_vp; 1272 devnode_t * dnp; 1273 1274 DEVFS_LOCK(); 1275 1276 dnp = VTODN(vp); 1277 1278 if (dnp) { 1279 /* 1280 * do the same as devfs_inactive in case it is not called 1281 * before us (can that ever happen?) 1282 */ 1283 dnp->dn_vn = NULL; 1284 vp->v_data = NULL; 1285 1286 if (dnp->dn_delete) { 1287 devnode_free(dnp); 1288 } 1289 } 1290 DEVFS_UNLOCK(); 1291 1292 return(0); 1293} 1294 1295 1296/* 1297 * Get configurable pathname variables. 1298 */ 1299static int 1300devs_vnop_pathconf( 1301 struct vnop_pathconf_args /* { 1302 struct vnode *a_vp; 1303 int a_name; 1304 int *a_retval; 1305 vfs_context_t a_context; 1306 } */ *ap) 1307{ 1308 switch (ap->a_name) { 1309 case _PC_LINK_MAX: 1310 /* arbitrary limit matching HFS; devfs has no hard limit */ 1311 *ap->a_retval = 32767; 1312 break; 1313 case _PC_NAME_MAX: 1314 *ap->a_retval = DEVMAXNAMESIZE - 1; /* includes NUL */ 1315 break; 1316 case _PC_PATH_MAX: 1317 *ap->a_retval = DEVMAXPATHSIZE - 1; /* XXX nonconformant */ 1318 break; 1319 case _PC_CHOWN_RESTRICTED: 1320 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ 1321 break; 1322 case _PC_NO_TRUNC: 1323 *ap->a_retval = 0; 1324 break; 1325 case _PC_CASE_SENSITIVE: 1326 *ap->a_retval = 1; 1327 break; 1328 case _PC_CASE_PRESERVING: 1329 *ap->a_retval = 1; 1330 break; 1331 default: 1332 return (EINVAL); 1333 } 1334 1335 return (0); 1336} 1337 1338 1339 1340/**************************************************************************\ 1341* pseudo ops * 1342\**************************************************************************/ 1343 1344/* 1345 * 1346 * struct vnop_inactive_args { 1347 * struct vnode *a_vp; 1348 * vfs_context_t a_context; 1349 * } 1350 */ 1351 1352static int 1353devfs_inactive(__unused struct vnop_inactive_args *ap) 1354{ 1355 return (0); 1356} 1357 1358/* 1359 * called with DEVFS_LOCK held 1360 */ 1361static int 1362devfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify) 1363{ 1364 devnode_t * ip; 1365 struct timeval now; 1366 1367 ip = VTODN(vp); 1368 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 1369 ip->dn_access = 0; 1370 ip->dn_change = 0; 1371 ip->dn_update = 0; 1372 1373 return (0); 1374 } 1375 microtime(&now); 1376 dn_times(ip, access, modify, &now); 1377 1378 return (0); 1379} 1380 1381#define VOPFUNC int (*)(void *) 1382 1383/* The following ops are used by directories and symlinks */ 1384int (**devfs_vnodeop_p)(void *); 1385static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 1386 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 1387 { &vnop_lookup_desc, (VOPFUNC)devfs_lookup }, /* lookup */ 1388 { &vnop_create_desc, (VOPFUNC)err_create }, /* create */ 1389 { &vnop_whiteout_desc, (VOPFUNC)err_whiteout }, /* whiteout */ 1390 { &vnop_mknod_desc, (VOPFUNC)devfs_mknod }, /* mknod */ 1391 { &vnop_open_desc, (VOPFUNC)nop_open }, /* open */ 1392 { &vnop_close_desc, (VOPFUNC)devfs_close }, /* close */ 1393 { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */ 1394 { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */ 1395 { &vnop_read_desc, (VOPFUNC)devfs_read }, /* read */ 1396 { &vnop_write_desc, (VOPFUNC)devfs_write }, /* write */ 1397 { &vnop_ioctl_desc, (VOPFUNC)err_ioctl }, /* ioctl */ 1398 { &vnop_select_desc, (VOPFUNC)err_select }, /* select */ 1399 { &vnop_revoke_desc, (VOPFUNC)err_revoke }, /* revoke */ 1400 { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */ 1401 { &vnop_fsync_desc, (VOPFUNC)nop_fsync }, /* fsync */ 1402 { &vnop_remove_desc, (VOPFUNC)devfs_remove }, /* remove */ 1403 { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */ 1404 { &vnop_rename_desc, (VOPFUNC)devfs_rename }, /* rename */ 1405 { &vnop_mkdir_desc, (VOPFUNC)devfs_mkdir }, /* mkdir */ 1406 { &vnop_rmdir_desc, (VOPFUNC)devfs_rmdir }, /* rmdir */ 1407 { &vnop_symlink_desc, (VOPFUNC)devfs_symlink }, /* symlink */ 1408 { &vnop_readdir_desc, (VOPFUNC)devfs_readdir }, /* readdir */ 1409 { &vnop_readlink_desc, (VOPFUNC)devfs_readlink }, /* readlink */ 1410 { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */ 1411 { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */ 1412 { &vnop_strategy_desc, (VOPFUNC)err_strategy }, /* strategy */ 1413 { &vnop_pathconf_desc, (VOPFUNC)devs_vnop_pathconf }, /* pathconf */ 1414 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */ 1415 { &vnop_bwrite_desc, (VOPFUNC)err_bwrite }, 1416 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */ 1417 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */ 1418 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ 1419 { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff */ 1420 { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */ 1421 { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap */ 1422#if CONFIG_MACF 1423 { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */ 1424#endif 1425 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1426}; 1427struct vnodeopv_desc devfs_vnodeop_opv_desc = 1428 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 1429 1430/* The following ops are used by the device nodes */ 1431int (**devfs_spec_vnodeop_p)(void *); 1432static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = { 1433 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 1434 { &vnop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */ 1435 { &vnop_create_desc, (VOPFUNC)spec_create }, /* create */ 1436 { &vnop_mknod_desc, (VOPFUNC)spec_mknod }, /* mknod */ 1437 { &vnop_open_desc, (VOPFUNC)spec_open }, /* open */ 1438 { &vnop_close_desc, (VOPFUNC)devfsspec_close }, /* close */ 1439 { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */ 1440 { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */ 1441 { &vnop_read_desc, (VOPFUNC)devfsspec_read }, /* read */ 1442 { &vnop_write_desc, (VOPFUNC)devfsspec_write }, /* write */ 1443 { &vnop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */ 1444 { &vnop_select_desc, (VOPFUNC)spec_select }, /* select */ 1445 { &vnop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */ 1446 { &vnop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */ 1447 { &vnop_fsync_desc, (VOPFUNC)spec_fsync }, /* fsync */ 1448 { &vnop_remove_desc, (VOPFUNC)devfs_remove }, /* remove */ 1449 { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */ 1450 { &vnop_rename_desc, (VOPFUNC)spec_rename }, /* rename */ 1451 { &vnop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */ 1452 { &vnop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */ 1453 { &vnop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */ 1454 { &vnop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */ 1455 { &vnop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */ 1456 { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */ 1457 { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */ 1458 { &vnop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */ 1459 { &vnop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */ 1460 { &vnop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */ 1461 { &vnop_bwrite_desc, (VOPFUNC)vn_bwrite }, 1462 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */ 1463 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */ 1464 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ 1465 { &vnop_blktooff_desc, (VOPFUNC)spec_blktooff }, /* blktooff */ 1466 { &vnop_blktooff_desc, (VOPFUNC)spec_offtoblk }, /* blkofftoblk */ 1467 { &vnop_blockmap_desc, (VOPFUNC)spec_blockmap }, /* blockmap */ 1468#if CONFIG_MACF 1469 { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */ 1470#endif 1471 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1472}; 1473struct vnodeopv_desc devfs_spec_vnodeop_opv_desc = 1474 { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries }; 1475