]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/miscfs/devfs/devfs_vnops.c
This commit was generated by cvs2svn to compensate for changes in r50894,
[FreeBSD/FreeBSD.git] / sys / miscfs / devfs / devfs_vnops.c
1 /*
2  * Copyright 1997,1998 Julian Elischer.  All rights reserved.
3  * julian@freebsd.org
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *  1. Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  * 
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED.  IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  * 
26  * $FreeBSD$
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/buf.h>
32 #include <sys/namei.h>
33 #include <sys/kernel.h>
34 #include <sys/fcntl.h>
35 #include <sys/conf.h>
36 #include <sys/disklabel.h>
37 #include <sys/lock.h>
38 #include <sys/stat.h>
39 #include <sys/mount.h>
40 #include <sys/proc.h>
41 #include <sys/time.h>
42 #include <sys/vnode.h>
43 #include <sys/dirent.h>
44 #include <miscfs/devfs/devfsdefs.h>
45 #include <sys/vmmeter.h>                                                        
46
47 #include <vm/vm.h>
48 #include <vm/vm_prot.h>
49 #include <vm/vm_object.h>
50 #include <vm/vm_page.h>
51 #include <vm/vm_pager.h>
52 #include <vm/vnode_pager.h>
53 #include <vm/vm_extern.h>
54
55
56 /*
57  * Insert description here
58  */
59
60
61 /*
62  * Convert a component of a pathname into a pointer to a locked node.
63  * This is a very central and rather complicated routine.
64  * If the file system is not maintained in a strict tree hierarchy,
65  * this can result in a deadlock situation (see comments in code below).
66  *
67  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
68  * whether the name is to be looked up, created, renamed, or deleted.
69  * When CREATE, RENAME, or DELETE is specified, information usable in
70  * creating, renaming, or deleting a directory entry may be calculated.
71  * If flag has LOCKPARENT or'ed into it and the target of the pathname
72  * exists, lookup returns both the target and its parent directory locked.
73  * When creating or renaming and LOCKPARENT is specified, the target may
74  * not be ".".  When deleting and LOCKPARENT is specified, the target may
75  * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
76  * instead of two DNUNLOCKs.
77  *
78  * Overall outline of devfs_lookup:
79  *
80  *      check accessibility of directory
81  *      null terminate the component (lookup leaves the whole string alone)
82  *      look for name in cache, if found, then if at end of path
83  *        and deleting or creating, drop it, else return name
84  *      search for name in directory, to found or notfound
85  * notfound:
86  *      if creating, return locked directory,
87  *      else return error
88  * found:
89  *      if at end of path and deleting, return information to allow delete
90  *      if at end of path and rewriting (RENAME and LOCKPARENT), lock target
91  *        node and return info to allow rewrite
92  *      if not at end, add name to cache; if at end and neither creating
93  *        nor deleting, add name to cache
94  * On return to lookup, remove the null termination we put in at the start.
95  *
96  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
97  */
98 static int
99 devfs_lookup(struct vop_lookup_args *ap)
100         /*struct vop_lookup_args {
101                 struct vnode * a_dvp; directory vnode ptr
102                 struct vnode ** a_vpp; where to put the result
103                 struct componentname * a_cnp; the name we want
104         };*/
105 {
106         struct componentname *cnp = ap->a_cnp;
107         struct vnode *dir_vnode = ap->a_dvp;
108         struct vnode **result_vnode = ap->a_vpp;
109         dn_p   dir_node;       /* the directory we are searching */
110         dn_p   new_node;       /* the node we are searching for */
111         devnm_p new_nodename;
112         int flags = cnp->cn_flags;
113         int op = cnp->cn_nameiop;       /* LOOKUP, CREATE, RENAME, or DELETE */
114         int lockparent = flags & LOCKPARENT;
115         int wantparent = flags & (LOCKPARENT|WANTPARENT);
116         int error = 0;
117         struct proc *p = cnp->cn_proc;
118         char    heldchar;       /* the char at the end of the name componet */
119
120         *result_vnode = NULL; /* safe not sorry */ /*XXX*/
121
122 DBPRINT(("lookup\n"));
123
124         if (dir_vnode->v_usecount == 0)
125             printf("dir had no refs ");
126         if (devfs_vntodn(dir_vnode,&dir_node))
127         {
128                 printf("vnode has changed?\n");
129                 vprint("=",dir_vnode);
130                 return(EINVAL);
131         }
132
133         /*
134          * Check accessiblity of directory.
135          */
136         if (dir_node->type != DEV_DIR) /* XXX or symlink? */
137         {
138                 return (ENOTDIR);
139         }
140         if ((error = VOP_ACCESS(dir_vnode, VEXEC, cnp->cn_cred, p)) != 0)
141         {
142                 return (error);
143         }
144
145         /*
146          * We now have a segment name to search for, and a directory to search.
147          *
148          */
149
150 /***********************************************************************\
151 * SEARCH FOR NAME                                                       *
152 * while making sure the component is null terminated for the strcmp     *
153 \***********************************************************************/
154
155         heldchar = cnp->cn_nameptr[cnp->cn_namelen];
156         cnp->cn_nameptr[cnp->cn_namelen] = '\0';
157         new_nodename = dev_findname(dir_node,cnp->cn_nameptr);
158         cnp->cn_nameptr[cnp->cn_namelen] = heldchar;
159         if(!new_nodename) {
160                 /*******************************************************\
161                 * Failed to find it.. (That may be good)                *
162                 \*******************************************************/
163                 new_node = NULL; /* to be safe */
164                 /*
165                  * If creating, and at end of pathname
166                  * then can consider
167                  * allowing file to be created.
168                  */
169                 if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) {
170                         return ENOENT;
171                 }
172                 /*
173                  * Access for write is interpreted as allowing
174                  * creation of files in the directory.
175                  */
176                 if ((error = VOP_ACCESS(dir_vnode, VWRITE,
177                                 cnp->cn_cred, p)) != 0)
178                 {
179 DBPRINT(("MKACCESS "));
180                         return (error);
181                 }
182                 /*
183                  * We return with the directory locked, so that
184                  * the parameters we set up above will still be
185                  * valid if we actually decide to add a new entry.
186                  * We return ni_vp == NULL to indicate that the entry
187                  * does not currently exist; we leave a pointer to
188                  * the (locked) directory vnode in namei_data->ni_dvp.
189                  * The pathname buffer is saved so that the name
190                  * can be obtained later.
191                  *
192                  * NB - if the directory is unlocked, then this
193                  * information cannot be used.
194                  */
195                 cnp->cn_flags |= SAVENAME; /*XXX why? */
196                 if (!lockparent)
197                         VOP_UNLOCK(dir_vnode, 0, p);
198                 return (EJUSTRETURN);
199         }
200
201         /***************************************************************\
202         * Found it.. this is not always a good thing..                  *
203         \***************************************************************/
204         new_node = new_nodename->dnp;
205         new_node->last_lookup = new_nodename; /* for unlink */
206         /*
207          * If deleting, and at end of pathname, return
208          * parameters which can be used to remove file.
209          * If the wantparent flag isn't set, we return only
210          * the directory (in namei_data->ni_dvp), otherwise we go
211          * on and lock the node, being careful with ".".
212          */
213         if (op == DELETE && (flags & ISLASTCN)) {
214                 /*
215                  * Write access to directory required to delete files.
216                  */
217                 if ((error = VOP_ACCESS(dir_vnode, VWRITE,
218                                 cnp->cn_cred, p)) != 0)
219                         return (error);
220                 /*
221                  * we are trying to delete '.'.  What does this mean? XXX
222                  */
223                 if (dir_node == new_node) {
224                         VREF(dir_vnode);
225                         *result_vnode = dir_vnode;
226                         return (0);
227                 }
228                 /*
229                  * If directory is "sticky", then user must own
230                  * the directory, or the file in it, else she
231                  * may not delete it (unless she's root). This
232                  * implements append-only directories.
233                  */
234                 devfs_dntovn(new_node,result_vnode);
235 #ifdef NOTYET
236                 if ((dir_node->mode & ISVTX) &&
237                     cnp->cn_cred->cr_uid != 0 &&
238                     cnp->cn_cred->cr_uid != dir_node->uid &&
239                     cnp->cn_cred->cr_uid != new_node->uid) {
240                         VOP_UNLOCK(*result_vnode, 0, p);
241                         return (EPERM);
242                 }
243 #endif
244                 if (!lockparent)
245                         VOP_UNLOCK(dir_vnode, 0, p);
246                 return (0);
247         }
248
249         /*
250          * If rewriting (RENAME), return the vnode and the
251          * information required to rewrite the present directory
252          * Must get node of directory entry to verify it's a
253          * regular file, or empty directory.
254          */
255         if (op == RENAME && wantparent && (flags & ISLASTCN)) {
256                 /*
257                  * Are we allowed to change the holding directory?
258                  */
259                 if ((error = VOP_ACCESS(dir_vnode, VWRITE,
260                                 cnp->cn_cred, p)) != 0)
261                         return (error);
262                 /*
263                  * Careful about locking second node.
264                  * This can only occur if the target is ".".
265                  */
266                 if (dir_node == new_node)
267                         return (EISDIR);
268                 devfs_dntovn(new_node,result_vnode);
269                 /* hmm save the 'from' name (we need to delete it) */
270                 cnp->cn_flags |= SAVENAME;
271                 if (!lockparent)
272                         VOP_UNLOCK(dir_vnode, 0, p);
273                 return (0);
274         }
275
276         /*
277          * Step through the translation in the name.  We do not unlock the
278          * directory because we may need it again if a symbolic link
279          * is relative to the current directory.  Instead we save it
280          * unlocked as "saved_dir_node" XXX.  We must get the target
281          * node before unlocking
282          * the directory to insure that the node will not be removed
283          * before we get it.  We prevent deadlock by always fetching
284          * nodes from the root, moving down the directory tree. Thus
285          * when following backward pointers ".." we must unlock the
286          * parent directory before getting the requested directory.
287          * There is a potential race condition here if both the current
288          * and parent directories are removed before the lock for the
289          * node associated with ".." returns.  We hope that this occurs
290          * infrequently since we cannot avoid this race condition without
291          * implementing a sophisticated deadlock detection algorithm.
292          * Note also that this simple deadlock detection scheme will not
293          * work if the file system has any hard links other than ".."
294          * that point backwards in the directory structure.
295          */
296         if (flags & ISDOTDOT) {
297                 VOP_UNLOCK(dir_vnode, 0, p);    /* race to get the node */
298                 devfs_dntovn(new_node,result_vnode);
299                 if (lockparent && (flags & ISLASTCN))
300                         vn_lock(dir_vnode, LK_EXCLUSIVE | LK_RETRY, p);
301         } else if (dir_node == new_node) {
302                 VREF(dir_vnode);        /* we want ourself, ie "." */
303                 *result_vnode = dir_vnode;
304         } else {
305                 devfs_dntovn(new_node,result_vnode);
306                 if (!lockparent || (flags & ISLASTCN))
307                         VOP_UNLOCK(dir_vnode, 0, p);
308         }
309
310 DBPRINT(("GOT\n"));
311         return (0);
312 }
313
314 /*
315  */
316
317 static int
318 devfs_access(struct vop_access_args *ap)
319         /*struct vop_access_args  {
320                 struct vnode *a_vp;
321                 int  a_mode;
322                 struct ucred *a_cred;
323                 struct proc *a_p;
324         } */ 
325 {
326         /*
327          *  mode is filled with a combination of VREAD, VWRITE,
328          *  and/or VEXEC bits turned on.  In an octal number these
329          *  are the Y in 0Y00.
330          */
331         struct vnode *vp = ap->a_vp;
332         int mode = ap->a_mode;
333         struct ucred *cred = ap->a_cred;
334         dn_p    dnp;
335         int     error;
336         gid_t   *gp;
337         int     i;
338
339 DBPRINT(("access\n"));
340         if ((error = devfs_vntodn(vp,&dnp)) != 0)
341         {
342                 printf("devfs_vntodn returned %d ",error);
343                 return error;
344         }
345
346         /* 
347          * if we are not running as a process, we are in the 
348          * kernel and we DO have permission
349          */
350         if (ap->a_p == NULL)
351                 return 0;
352
353         /*
354          * Access check is based on only one of owner, group, public.
355          * If not owner, then check group. If not a member of the
356          * group, then check public access.
357          */
358         if (cred->cr_uid != dnp->uid)
359         {
360                 /* failing that.. try groups */
361                 mode >>= 3;
362                 gp = cred->cr_groups;
363                 for (i = 0; i < cred->cr_ngroups; i++, gp++)
364                 {
365                         if (dnp->gid == *gp)
366                         {
367                                 goto found;
368                         }
369                 }
370                 /* failing that.. try general access */
371                 mode >>= 3;
372 found:
373                 ;
374         }
375         if ((dnp->mode & mode) == mode)
376                 return (0);
377         /*
378          *  Root gets to do anything.
379          * but only use suser_xxx prives as a last resort
380          * (Use of super powers is recorded in ap->a_p->p_acflag)
381          */
382         if( suser_xxx(cred, ap->a_p, 0) == 0) /* XXX what if no proc? */
383                 return 0;
384         return (EACCES);
385 }
386
387 static int
388 devfs_getattr(struct vop_getattr_args *ap)
389         /*struct vop_getattr_args {
390                 struct vnode *a_vp;
391                 struct vattr *a_vap;
392                 struct ucred *a_cred;
393                 struct proc *a_p;
394         } */ 
395 {
396         struct vnode *vp = ap->a_vp;
397         struct vattr *vap = ap->a_vap;
398         dn_p    dnp;
399         int     error;
400
401 DBPRINT(("getattr\n"));
402         if ((error = devfs_vntodn(vp,&dnp)) != 0)
403         {
404                 printf("devfs_vntodn returned %d ",error);
405                 return error;
406         }
407         vap->va_rdev = 0;/* default value only */
408         vap->va_mode = dnp->mode;
409         switch (dnp->type)
410         {
411         case    DEV_DIR:
412                 vap->va_rdev = (udev_t)dnp->dvm;
413                 vap->va_mode |= (S_IFDIR);
414                 break;
415         case    DEV_CDEV:
416                 vap->va_rdev = dev2udev(vp->v_rdev);
417                 vap->va_mode |= (S_IFCHR);
418                 break;
419         case    DEV_BDEV:
420                 vap->va_rdev = dev2budev(vp->v_rdev);
421                 vap->va_mode |= (S_IFBLK);
422                 break;
423         case    DEV_SLNK:
424                 break;
425         }
426         vap->va_type = vp->v_type;
427         vap->va_nlink = dnp->links;
428         vap->va_uid = dnp->uid;
429         vap->va_gid = dnp->gid;
430         vap->va_fsid = (intptr_t)(void *)dnp->dvm;
431         vap->va_fileid = (intptr_t)(void *)dnp;
432         vap->va_size = dnp->len; /* now a u_quad_t */
433         vap->va_blocksize = 512;
434         /*
435          * XXX If the node times are in  Jan 1, 1970, then
436          * update them to the boot time.
437          * When we made the node, the date/time was not yet known.
438          */
439         if(dnp->ctime.tv_sec < (24 * 3600))
440         {
441                 TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->ctime));
442                 TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->mtime));
443                 TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->atime));
444         }
445         if (dnp->flags & IN_ACCESS) {
446                 nanotime(&dnp->atime);
447                 dnp->flags &= ~IN_ACCESS;
448         }
449         vap->va_ctime = dnp->ctime;
450         vap->va_mtime = dnp->mtime;
451         vap->va_atime = dnp->atime;
452         vap->va_gen = 0;
453         vap->va_flags = 0;
454         vap->va_bytes = dnp->len;               /* u_quad_t */
455         vap->va_filerev = 0; /* XXX */          /* u_quad_t */
456         vap->va_vaflags = 0; /* XXX */
457         return 0;
458 }
459
460 static int
461 devfs_setattr(struct vop_setattr_args *ap)
462         /*struct vop_setattr_args  {
463                 struct vnode *a_vp;
464                 struct vattr *a_vap;
465                 struct ucred *a_cred;
466                 struct proc *a_p;
467         } */ 
468 {
469         struct vnode *vp = ap->a_vp;
470         struct vattr *vap = ap->a_vap;
471         struct ucred *cred = ap->a_cred;
472         struct proc *p = ap->a_p;
473         int error = 0;
474         gid_t *gp;
475         int i;
476         dn_p    dnp;
477
478         if (vap->va_flags != VNOVAL)    /* XXX needs to be implemented */
479                 return (EOPNOTSUPP);
480
481         if ((error = devfs_vntodn(vp,&dnp)) != 0)
482         {
483                 printf("devfs_vntodn returned %d ",error);
484                 return error;
485         }
486 DBPRINT(("setattr\n"));
487         if ((vap->va_type != VNON)  ||
488             (vap->va_nlink != VNOVAL)  ||
489             (vap->va_fsid != VNOVAL)  ||
490             (vap->va_fileid != VNOVAL)  ||
491             (vap->va_blocksize != VNOVAL)  ||
492             (vap->va_rdev != VNOVAL)  ||
493             (vap->va_bytes != VNOVAL)  ||
494             (vap->va_gen != VNOVAL ))
495         {
496                 return EINVAL;
497         }
498
499
500         /* 
501          * Anyone can touch the files in such a way that the times are set
502          * to NOW (e.g. run 'touch') if they have write permissions
503          * however only the owner or root can set "un-natural times.
504          * They also don't need write permissions.
505          */
506         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
507 #if 0           /*
508                  * This next test is pointless under devfs for now..
509                  * as there is only one devfs hiding under potentially many
510                  * mountpoints and actual device node are really 'mounted' under
511                  * a FAKE mountpoint inside the kernel only, no matter where it
512                  * APPEARS they are mounted to the outside world..
513                  * A readonly devfs doesn't exist anyway.
514                  */
515                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
516                         return (EROFS);
517 #endif
518                 if (((vap->va_vaflags & VA_UTIMES_NULL) == 0) &&
519                     (cred->cr_uid != dnp->uid)  &&
520                     suser_xxx(cred, p, 0))
521                         return (EPERM);
522                     if(VOP_ACCESS(vp, VWRITE, cred, p))
523                         return (EACCES);
524                 dnp->atime = vap->va_atime;
525                 dnp->mtime = vap->va_mtime;
526                 nanotime(&dnp->ctime);
527                 return (0);
528         }
529
530         /*
531          * Change the permissions.. must be root or owner to do this.
532          */
533         if (vap->va_mode != (u_short)VNOVAL) {
534                 if ((cred->cr_uid != dnp->uid)
535                  && suser_xxx(cred, p, 0))
536                         return (EPERM);
537                 /* set drwxwxrwx stuff */
538                 dnp->mode &= ~07777;
539                 dnp->mode |= vap->va_mode & 07777;
540         }
541
542         /*
543          * Change the owner.. must be root to do this.
544          */
545         if (vap->va_uid != (uid_t)VNOVAL) {
546                 if (suser_xxx(cred, p, 0))
547                         return (EPERM);
548                 dnp->uid = vap->va_uid;
549         }
550
551         /*
552          * Change the group.. must be root or owner to do this.
553          * If we are the owner, we must be in the target group too.
554          * don't use suser_xxx() unless you have to as it reports
555          * whether you needed suser_xxx powers or not.
556          */
557         if (vap->va_gid != (gid_t)VNOVAL) {
558                 if (cred->cr_uid == dnp->uid){
559                         gp = cred->cr_groups;
560                         for (i = 0; i < cred->cr_ngroups; i++, gp++) {
561                                 if (vap->va_gid == *gp)
562                                         goto cando; 
563                         }
564                 }
565                 /*
566                  * we can't do it with normal privs,
567                  * do we have an ace up our sleeve?
568                  */
569                 if( suser_xxx(cred, p, 0))
570                         return (EPERM);
571 cando:
572                 dnp->gid = vap->va_gid;
573         }
574 #if 0
575         /*
576          * Copied from somewhere else
577          * but only kept as a marker and reminder of the fact that
578          * flags should be handled some day
579          */
580         if (vap->va_flags != VNOVAL) {
581                 if (error = suser_xxx(cred, p, 0))
582                         return error;
583                 if (cred->cr_uid == 0)
584                 ;
585                 else {
586                 }
587         }
588 #endif
589         return error;
590 }
591
592
593 static int
594 devfs_xread(struct vop_read_args *ap)
595         /*struct vop_read_args {
596                 struct vnode *a_vp;
597                 struct uio *a_uio;
598                 int  a_ioflag;
599                 struct ucred *a_cred;
600         } */
601 {
602         int     error = 0;
603         dn_p    dnp;
604         struct vnode *vp = ap->a_vp;
605
606 DBPRINT(("read\n"));
607         if ((error = devfs_vntodn(vp,&dnp)) != 0)
608         {
609                 printf("devfs_vntodn returned %d ",error);
610                 return error;
611         }
612
613
614         switch (vp->v_type) {
615         case VREG:
616                 return(EINVAL);
617         case VDIR:
618                 return VOP_READDIR(vp,ap->a_uio,ap->a_cred,
619                                         NULL,NULL,NULL);
620         case VCHR:
621         case VBLK:
622                 panic("devfs:  vnode methods");
623
624         default:
625                 panic("devfs_read(): bad file type");
626                 break;
627         }
628 }
629
630 /*
631  *  Write data to a file or directory.
632  */
633 static int
634 devfs_xwrite(struct vop_write_args *ap)
635         /*struct vop_write_args  {
636                 struct vnode *a_vp;
637                 struct uio *a_uio;
638                 int  a_ioflag;
639                 struct ucred *a_cred;
640         } */
641 {
642         struct vnode *vp = ap->a_vp;
643
644         switch (vp->v_type) {
645         case VREG:
646                 return(EINVAL);
647         case VDIR:
648                 return(EISDIR);
649         case VCHR:
650         case VBLK:
651                 panic("devfs:  vnode methods");
652         default:
653                 panic("devfs_xwrite(): bad file type");
654         }
655 }
656
657
658 static int
659 devfs_remove(struct vop_remove_args *ap)
660         /*struct vop_remove_args  {
661                 struct vnode *a_dvp;
662                 struct vnode *a_vp;
663                 struct componentname *a_cnp;
664         } */ 
665 {
666         struct vnode *vp = ap->a_vp;
667         struct vnode *dvp = ap->a_dvp;
668         struct componentname *cnp = ap->a_cnp;
669         dn_p  tp, tdp;
670         devnm_p tnp;
671         int doingdirectory = 0;
672         int error = 0;
673         uid_t ouruid = cnp->cn_cred->cr_uid;
674
675
676 DBPRINT(("remove\n"));
677         /*
678          * Lock our directories and get our name pointers
679          * assume that the names are null terminated as they
680          * are the end of the path. Get pointers to all our
681          * devfs structures.
682          */
683         if ((error = devfs_vntodn(dvp, &tdp)) != 0) {
684 abortit:
685                 VOP_ABORTOP(dvp, cnp); 
686                 return (error);
687         }
688         if ((error = devfs_vntodn(vp, &tp)) != 0) goto abortit;
689         /*
690          * Assuming we are atomic, dev_lookup left this for us
691          */
692         tnp = tp->last_lookup;
693         
694
695         /*
696          * Check we are doing legal things WRT the new flags
697          */
698         if ((tp->flags & (IMMUTABLE | APPEND))
699           || (tdp->flags & APPEND) /*XXX eh?*/ ) {
700                 error = EPERM;
701                 goto abortit;
702         }
703
704         /*
705          * Make sure that we don't try do something stupid
706          */
707         if ((tp->type) == DEV_DIR) {
708                 /*
709                  * Avoid ".", "..", and aliases of "." for obvious reasons.
710                  */
711                 if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') 
712                     || (cnp->cn_flags&ISDOTDOT) ) {
713                         error = EINVAL;
714                         goto abortit;
715                 }
716                 doingdirectory++;
717         }
718
719         /***********************************
720          * Start actually doing things.... *
721          ***********************************/
722         getnanotime(&(tdp->mtime));
723
724
725         /*
726          * own the parent directory, or the destination of the rename,
727          * otherwise the destination may not be changed (except by
728          * root). This implements append-only directories.
729          * XXX shoudn't this be in generic code? 
730          */
731         if ((tdp->mode & S_ISTXT)
732           && ouruid != 0
733           && ouruid != tdp->uid
734           && ouruid != tp->uid ) {
735                 error = EPERM;
736                 goto abortit;
737         }
738         /*
739          * Target must be empty if a directory and have no links
740          * to it. Also, ensure source and target are compatible
741          * (both directories, or both not directories).
742          */
743         if (( doingdirectory) && (tp->links > 2)) {
744                         printf("nlink = %d\n",tp->links); /*XXX*/
745                         error = ENOTEMPTY;
746                         goto abortit;
747         }
748         dev_free_name(tnp);
749         tp = NULL;
750         return (error);
751 }
752
753 /*
754  */
755 static int
756 devfs_link(struct vop_link_args *ap)
757         /*struct vop_link_args  {
758                 struct vnode *a_tdvp;
759                 struct vnode *a_vp;
760                 struct componentname *a_cnp;
761         } */ 
762 {
763         struct vnode *vp = ap->a_vp;
764         struct vnode *tdvp = ap->a_tdvp;
765         struct componentname *cnp = ap->a_cnp;
766         dn_p  fp, tdp;
767         devnm_p tnp;
768         int error = 0;
769
770 DBPRINT(("link\n"));
771         /*
772          * First catch an arbitrary restriction for this FS
773          */
774         if(cnp->cn_namelen > DEVMAXNAMESIZE) {
775                 error = ENAMETOOLONG;
776                 goto abortit;
777         }
778
779         /*
780          * Lock our directories and get our name pointers
781          * assume that the names are null terminated as they
782          * are the end of the path. Get pointers to all our
783          * devfs structures.
784          */
785         if ((error = devfs_vntodn(tdvp,&tdp)) != 0) goto abortit;
786         if ((error = devfs_vntodn(vp,&fp)) != 0) goto abortit;
787         
788         /*
789          * trying to move it out of devfs? (v_tag == VT_DEVFS)
790          */
791         if ( (vp->v_tag != VT_DEVFS)
792          || (vp->v_tag != tdvp->v_tag) ) {
793                 error = EXDEV;
794 abortit:
795                 VOP_ABORTOP(tdvp, cnp); 
796                 goto out;
797         }
798
799         /*
800          * Check we are doing legal things WRT the new flags
801          */
802         if (fp->flags & (IMMUTABLE | APPEND)) {
803                 error = EPERM;
804                 goto abortit;
805         }
806
807         /***********************************
808          * Start actually doing things.... *
809          ***********************************/
810         getnanotime(&(tdp->atime));
811         error = dev_add_name(cnp->cn_nameptr,
812                         tdp,
813                         NULL,
814                         fp,
815                         &tnp);
816 out:
817         return (error);
818
819 }
820
821 /*
822  * Rename system call. Seems overly complicated to me...
823  *      rename("foo", "bar");
824  * is essentially
825  *      unlink("bar");
826  *      link("foo", "bar");
827  *      unlink("foo");
828  * but ``atomically''.
829  *
830  * When the target exists, both the directory
831  * and target vnodes are locked.
832  * the source and source-parent vnodes are referenced
833  *
834  *
835  * Basic algorithm is:
836  *
837  * 1) Bump link count on source while we're linking it to the
838  *    target.  This also ensure the inode won't be deleted out
839  *    from underneath us while we work (it may be truncated by
840  *    a concurrent `trunc' or `open' for creation).
841  * 2) Link source to destination.  If destination already exists,
842  *    delete it first.
843  * 3) Unlink source reference to node if still around. If a
844  *    directory was moved and the parent of the destination
845  *    is different from the source, patch the ".." entry in the
846  *    directory.
847  */
848 static int
849 devfs_rename(struct vop_rename_args *ap)
850         /*struct vop_rename_args  {
851                 struct vnode *a_fdvp;
852                 struct vnode *a_fvp;
853                 struct componentname *a_fcnp;
854                 struct vnode *a_tdvp;
855                 struct vnode *a_tvp;
856                 struct componentname *a_tcnp;
857         } */
858 {
859         struct vnode *tvp = ap->a_tvp;
860         struct vnode *tdvp = ap->a_tdvp;
861         struct vnode *fvp = ap->a_fvp;
862         struct vnode *fdvp = ap->a_fdvp;
863         struct componentname *tcnp = ap->a_tcnp;
864         struct componentname *fcnp = ap->a_fcnp;
865         struct proc *p = fcnp->cn_proc;
866         dn_p fp, fdp, tp, tdp;
867         devnm_p fnp,tnp;
868         int doingdirectory = 0;
869         int error = 0;
870
871         /*
872          * First catch an arbitrary restriction for this FS
873          */
874         if(tcnp->cn_namelen > DEVMAXNAMESIZE) {
875                 error = ENAMETOOLONG;
876                 goto abortit;
877         }
878
879         /*
880          * Lock our directories and get our name pointers
881          * assume that the names are null terminated as they
882          * are the end of the path. Get pointers to all our
883          * devfs structures.
884          */
885         if ((error = devfs_vntodn(tdvp,&tdp)) != 0) goto abortit;
886         if ((error = devfs_vntodn(fdvp,&fdp)) != 0) goto abortit;
887         if ((error = devfs_vntodn(fvp,&fp)) != 0) goto abortit;
888         fnp = fp->last_lookup;
889         if (tvp) {
890                 if ((error = devfs_vntodn(tvp,&tp)) != 0) goto abortit;
891                 tnp = tp->last_lookup;
892         } else {
893                 tp = NULL;
894                 tnp = NULL;
895         }
896         
897         /*
898          * trying to move it out of devfs? (v_tag == VT_DEVFS)
899          * if we move a dir across mnt points. we need to fix all
900          * the mountpoint pointers! XXX
901          * so for now keep dirs within the same mount
902          */
903         if ( (fvp->v_tag != VT_DEVFS)
904          || (fvp->v_tag != tdvp->v_tag)
905          || (tvp && (fvp->v_tag != tvp->v_tag))
906          || ((fp->type == DEV_DIR) && (fp->dvm != tdp->dvm ))) {
907                 error = EXDEV;
908 abortit:
909                 VOP_ABORTOP(tdvp, tcnp); 
910                 if (tdvp == tvp) /* eh? */
911                         vrele(tdvp);
912                 else
913                         vput(tdvp);
914                 if (tvp)
915                         vput(tvp);
916                 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
917                 vrele(fdvp);
918                 vrele(fvp);
919                 return (error);
920         }
921
922         /*
923          * Check we are doing legal things WRT the new flags
924          */
925         if ((tp && (tp->flags & (IMMUTABLE | APPEND)))
926           || (fp->flags & (IMMUTABLE | APPEND))
927           || (fdp->flags & APPEND)) {
928                 error = EPERM;
929                 goto abortit;
930         }
931
932         /*
933          * Make sure that we don't try do something stupid
934          */
935         if ((fp->type) == DEV_DIR) {
936                 /*
937                  * Avoid ".", "..", and aliases of "." for obvious reasons.
938                  */
939                 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') 
940                     || (fcnp->cn_flags&ISDOTDOT) 
941                     || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.') 
942                     || (tcnp->cn_flags&ISDOTDOT) 
943                     || (tdp == fp )) {
944                         error = EINVAL;
945                         goto abortit;
946                 }
947                 doingdirectory++;
948         }
949
950         /*
951          * If ".." must be changed (ie the directory gets a new
952          * parent) then the source directory must not be in the
953          * directory heirarchy above the target, as this would
954          * orphan everything below the source directory. Also
955          * the user must have write permission in the source so
956          * as to be able to change "..". 
957          */
958         if (doingdirectory && (tdp != fdp)) {
959                 dn_p tmp,ntmp;
960                 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
961                 tmp = tdp;
962                 do {
963                         if(tmp == fp) {
964                                 /* XXX unlock stuff here probably */
965                                 error = EINVAL;
966                                 goto out;
967                         }
968                         ntmp = tmp;
969                 } while ((tmp = tmp->by.Dir.parent) != ntmp);
970         }
971
972         /***********************************
973          * Start actually doing things.... *
974          ***********************************/
975         getnanotime(&(fp->atime));
976         /*
977          * Check if just deleting a link name.
978          */
979         if (fvp == tvp) {
980                 if (fvp->v_type == VDIR) {
981                         error = EINVAL;
982                         goto abortit;
983                 }
984
985                 /* Release destination completely. */
986                 VOP_ABORTOP(tdvp, tcnp);
987                 vput(tdvp);
988                 vput(tvp);
989
990                 /* Delete source. */
991                 VOP_ABORTOP(fdvp, fcnp); /*XXX*/
992                 vrele(fdvp);
993                 vrele(fvp);
994                 dev_free_name(fnp);
995                 return 0;
996         }
997
998
999         /*
1000          * 1) Bump link count while we're moving stuff
1001          *    around.  If we crash somewhere before
1002          *    completing our work,  too bad :)
1003          */
1004         fp->links++;
1005         /*
1006          * If the target exists zap it (unless it's a non-empty directory)
1007          * We could do that as well but won't
1008          */
1009         if (tp) {
1010                 int ouruid = tcnp->cn_cred->cr_uid;
1011                 /*
1012                  * If the parent directory is "sticky", then the user must
1013                  * own the parent directory, or the destination of the rename,
1014                  * otherwise the destination may not be changed (except by
1015                  * root). This implements append-only directories.
1016                  * XXX shoudn't this be in generic code? 
1017                  */
1018                 if ((tdp->mode & S_ISTXT)
1019                   && ouruid != 0
1020                   && ouruid != tdp->uid
1021                   && ouruid != tp->uid ) {
1022                         error = EPERM;
1023                         goto bad;
1024                 }
1025                 /*
1026                  * Target must be empty if a directory and have no links
1027                  * to it. Also, ensure source and target are compatible
1028                  * (both directories, or both not directories).
1029                  */
1030                 if (( doingdirectory) && (tp->links > 2)) {
1031                                 printf("nlink = %d\n",tp->links); /*XXX*/
1032                                 error = ENOTEMPTY;
1033                                 goto bad;
1034                 }
1035                 dev_free_name(tnp);
1036                 tp = NULL;
1037         }
1038         dev_add_name(tcnp->cn_nameptr,tdp,fnp->as.front.realthing,fp,&tnp);
1039         fnp->dnp = NULL;
1040         fp->links--; /* one less link to it.. */
1041         dev_free_name(fnp);
1042         fp->links--; /* we added one earlier*/
1043         if (tdp)
1044                 vput(tdvp);
1045         if (tp)
1046                 vput(fvp);
1047         vrele(ap->a_fvp);
1048         return (error);
1049
1050 bad:
1051         if (tp)
1052                 vput(tvp);
1053         vput(tdvp);
1054 out:
1055         if (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) {
1056                 fp->links--; /* we added one earlier*/
1057                 vput(fvp);
1058         } else
1059                 vrele(fvp);
1060         return (error);
1061 }
1062
1063 static int
1064 devfs_symlink(struct vop_symlink_args *ap)
1065         /*struct vop_symlink_args {
1066                 struct vnode *a_dvp;
1067                 struct vnode **a_vpp;
1068                 struct componentname *a_cnp;
1069                 struct vattr *a_vap;
1070                 char *a_target;
1071         } */
1072 {
1073         struct vnode *vp;
1074         int error;
1075         dn_p dnp;
1076         union typeinfo by;
1077         devnm_p nm_p;
1078
1079 DBPRINT(("symlink\n"));
1080         if((error = devfs_vntodn(ap->a_dvp, &dnp)) != 0) {
1081                 return (error);
1082         }
1083                 
1084         by.Slnk.name = ap->a_target;
1085         by.Slnk.namelen = strlen(ap->a_target);
1086         dev_add_entry(ap->a_cnp->cn_nameptr, dnp, DEV_SLNK, &by,
1087                 NULL, NULL, &nm_p);
1088         if((error = devfs_dntovn(nm_p->dnp, &vp)) != 0) {
1089                 return (error);
1090         }
1091         VOP_SETATTR(vp, ap->a_vap, ap->a_cnp->cn_cred, ap->a_cnp->cn_proc);
1092         *ap->a_vpp = NULL;
1093         vput(vp);
1094         return 0;
1095 }
1096
1097 /*
1098  * Vnode op for readdir
1099  */
1100 static int
1101 devfs_readdir(struct vop_readdir_args *ap)
1102         /*struct vop_readdir_args {
1103                 struct vnode *a_vp;
1104                 struct uio *a_uio;
1105                 struct ucred *a_cred;
1106                 int *eofflag;
1107                 int *ncookies;
1108                 u_int **cookies;
1109         } */
1110 {
1111         struct vnode *vp = ap->a_vp;
1112         struct uio *uio = ap->a_uio;
1113         struct dirent dirent;
1114         dn_p dir_node;
1115         devnm_p name_node;
1116         char    *name;
1117         int error = 0;
1118         int reclen;
1119         int nodenumber;
1120         int     startpos,pos;
1121
1122 DBPRINT(("readdir\n"));
1123
1124 /*  set up refs to dir */
1125         if ((error = devfs_vntodn(vp,&dir_node)) != 0)
1126                 return error;
1127         if(dir_node->type != DEV_DIR)
1128                 return(ENOTDIR);
1129
1130         pos = 0;
1131         startpos = uio->uio_offset;
1132         name_node = dir_node->by.Dir.dirlist;
1133         nodenumber = 0;
1134         getnanotime(&(dir_node->atime));
1135
1136         while ((name_node || (nodenumber < 2)) && (uio->uio_resid > 0))
1137         {
1138                 switch(nodenumber)
1139                 {
1140                 case    0:
1141                         dirent.d_fileno = (uintptr_t)(void *)dir_node;
1142                         name = ".";
1143                         dirent.d_namlen = 1;
1144                         dirent.d_type = DT_DIR;
1145                         break;
1146                 case    1:
1147                         if(dir_node->by.Dir.parent)
1148                                 dirent.d_fileno
1149                                  = (uintptr_t)(void *)dir_node->by.Dir.parent;
1150                         else
1151                                 dirent.d_fileno = (uintptr_t)(void *)dir_node;
1152                         name = "..";
1153                         dirent.d_namlen = 2;
1154                         dirent.d_type = DT_DIR;
1155                         break;
1156                 default:
1157                         dirent.d_fileno = (uintptr_t)(void *)name_node->dnp;
1158                         dirent.d_namlen = strlen(name_node->name);
1159                         name = name_node->name;
1160                         switch(name_node->dnp->type) {
1161                         case DEV_BDEV:
1162                                 dirent.d_type = DT_BLK;
1163                                 break;
1164                         case DEV_CDEV:
1165                                 dirent.d_type = DT_CHR;
1166                                 break;
1167                         case DEV_DDEV:
1168                                 dirent.d_type = DT_SOCK; /*XXX*/
1169                                 break;
1170                         case DEV_DIR:
1171                                 dirent.d_type = DT_DIR;
1172                                 break;
1173                         case DEV_SLNK:
1174                                 dirent.d_type = DT_LNK;
1175                                 break;
1176                         default:
1177                                 dirent.d_type = DT_UNKNOWN;
1178                         }
1179                 }
1180
1181                 reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent);
1182
1183                 if(pos >= startpos)     /* made it to the offset yet? */
1184                 {
1185                         if (uio->uio_resid < reclen) /* will it fit? */
1186                                 break;
1187                         strcpy( dirent.d_name,name);
1188                         if ((error = uiomove ((caddr_t)&dirent,
1189                                         dirent.d_reclen, uio)) != 0)
1190                                 break;
1191                 }
1192                 pos += reclen;
1193                 if((nodenumber >1) && name_node)
1194                         name_node = name_node->next;
1195                 nodenumber++;
1196         }
1197         uio->uio_offset = pos;
1198
1199         return (error);
1200 }
1201
1202
1203 /*
1204  */
1205 static int
1206 devfs_readlink(struct vop_readlink_args *ap)
1207         /*struct vop_readlink_args {
1208                 struct vnode *a_vp;
1209                 struct uio *a_uio;
1210                 struct ucred *a_cred;
1211         } */
1212 {
1213         struct vnode *vp = ap->a_vp;
1214         struct uio *uio = ap->a_uio;
1215         dn_p lnk_node;
1216         int error = 0;
1217
1218
1219 DBPRINT(("readlink\n"));
1220 /*  set up refs to dir */
1221         if ((error = devfs_vntodn(vp,&lnk_node)) != 0)
1222                 return error;
1223         if(lnk_node->type != DEV_SLNK)
1224                 return(EINVAL);
1225         if ((error = VOP_ACCESS(vp, VREAD, ap->a_cred, NULL)) != 0) { /* XXX */
1226                 return error;
1227         }
1228         error = uiomove(lnk_node->by.Slnk.name, lnk_node->by.Slnk.namelen, uio);
1229         return error;
1230 }
1231
1232 #ifdef notyet
1233 static int
1234 devfs_abortop(struct vop_abortop_args *ap)
1235         /*struct vop_abortop_args {
1236                 struct vnode *a_dvp;
1237                 struct componentname *a_cnp;
1238         } */
1239 {
1240 DBPRINT(("abortop\n"));
1241         if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1242                 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1243         return 0;
1244 }
1245 #endif /* notyet */
1246
1247
1248 static int
1249 devfs_reclaim(struct vop_reclaim_args *ap)
1250         /*struct vop_reclaim_args {
1251                 struct vnode *a_vp;
1252         } */
1253 {
1254         dn_p    dnp = NULL;
1255         int     error;
1256         struct vnode *vp = ap->a_vp;
1257
1258 DBPRINT(("reclaim\n"));
1259         if ((error = devfs_vntodn(vp,&dnp)) != 0)
1260         {
1261                 printf("devfs_vntodn returned %d ",error);
1262                 return error;
1263         }
1264
1265         vp->v_data = NULL;
1266         if (dnp) {
1267                 dnp->vn = 0;
1268                 dnp->vn_id = 0;
1269         }
1270         return(0);
1271 }
1272
1273 /*
1274  * Print out the contents of a /devfs vnode.
1275  */
1276 static int
1277 devfs_print(struct vop_print_args *ap)
1278         /*struct vop_print_args {
1279                 struct vnode *a_vp;
1280         } */
1281 {
1282
1283         printf("tag VT_DEVFS, devfs vnode\n");
1284         return (0);
1285 }
1286
1287 /**************************************************************************\
1288 * pseudo ops *
1289 \**************************************************************************/
1290
1291 /*proto*/
1292 void
1293 devfs_dropvnode(dn_p dnp)
1294 {
1295         struct vnode *vn_p;
1296
1297 #ifdef PARANOID
1298         if(!dnp)
1299         {
1300                 printf("devfs: dn count dropped too early\n");
1301         }
1302 #endif
1303         vn_p = dnp->vn;
1304         /*
1305          * check if we have a vnode.......
1306          */
1307         if((vn_p) && ( dnp->vn_id == vn_p->v_id) && (dnp == (dn_p)vn_p->v_data))
1308         {
1309                 VOP_REVOKE(vn_p, REVOKEALL);
1310         }
1311         dnp->vn = NULL; /* be pedantic about this */
1312 }
1313
1314 /* struct vnode *speclisth[SPECHSZ];*/ /* till specfs goes away */
1315
1316 /*
1317  * Open a special file.
1318         struct vop_open_args {
1319                 struct vnode *a_vp;
1320                 int  a_mode;
1321                 struct ucred *a_cred;
1322                 struct proc *a_p;
1323         } *ap;
1324  */
1325 /* ARGSUSED */
1326 static int
1327 devfs_open( struct vop_open_args *ap)
1328 {
1329         struct proc *p = ap->a_p;
1330         struct vnode *vp = ap->a_vp;
1331         int error;
1332         dn_p    dnp;
1333         struct cdevsw *dsw;
1334         dev_t bdev, dev = vp->v_rdev;
1335         struct vnode *bvp;
1336
1337
1338         if ((error = devfs_vntodn(vp,&dnp)) != 0)
1339                 return error;
1340
1341         switch (vp->v_type) {
1342         case VCHR:
1343                 dsw = devsw(dev);
1344                 if ( (dsw == NULL) || (dsw->d_open == NULL))
1345                         return ENXIO;
1346                 if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
1347                         /*
1348                          * When running in very secure mode, do not allow
1349                          * opens for writing of any disk character devices.
1350                          */
1351                         if (securelevel >= 2
1352                             && dsw->d_bmaj != -1
1353                             && (dsw->d_flags & D_TYPEMASK) == D_DISK)
1354                                 return (EPERM);
1355                         /*
1356                          * When running in secure mode, do not allow opens
1357                          * for writing of /dev/mem, /dev/kmem, or character
1358                          * devices whose corresponding block devices are
1359                          * currently mounted.
1360                          */
1361                         if (securelevel >= 1) {
1362                                 if ((bdev = chrtoblk(dev)) != NODEV &&
1363                                     vfinddev(bdev, VBLK, &bvp) &&
1364                                     bvp->v_usecount > 0 &&
1365                                     (error = vfs_mountedon(bvp)))
1366                                         return (error);
1367                                 if (iskmemdev(dev))
1368                                         return (EPERM);
1369                         }
1370                 }
1371                 if ((dsw->d_flags & D_TYPEMASK) == D_TTY)
1372                         vp->v_flag |= VISTTY;
1373                 VOP_UNLOCK(vp, 0, p);
1374                 error = (*vp->v_rdev->si_devsw->d_open)(
1375                                         vp->v_rdev,
1376                                         ap->a_mode,
1377                                         S_IFCHR,
1378                                         p);
1379                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1380                 return (error);
1381                 /* NOT REACHED */
1382         case VBLK:
1383                 dsw = devsw(dev);
1384                 if ( (dsw == NULL) || (dsw->d_open == NULL))
1385                         return ENXIO;
1386                 /*
1387                  * When running in very secure mode, do not allow
1388                  * opens for writing of any disk block devices.
1389                  */
1390                 if (securelevel >= 2 && ap->a_cred != FSCRED &&
1391                     (ap->a_mode & FWRITE) &&
1392                     (dsw->d_flags & D_TYPEMASK) == D_DISK)
1393                         return (EPERM);
1394
1395                 /*
1396                  * Do not allow opens of block devices that are
1397                  * currently mounted.
1398                  */
1399                 error = vfs_mountedon(vp);
1400                 if (error)
1401                         return (error);
1402                 error = (*vp->v_rdev->si_devsw->d_open)(
1403                                         vp->v_rdev,
1404                                         ap->a_mode,
1405                                         S_IFBLK,
1406                                         p);
1407                 break;
1408         default:
1409                 break;
1410         }
1411         return (error);
1412 }
1413
1414 /* ARGSUSED */
1415 static int
1416 devfs_read( struct vop_read_args *ap)
1417 {
1418         int error;
1419
1420         error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap);
1421         return (error);
1422 }
1423
1424 /* ARGSUSED */
1425 static int
1426 devfs_write( struct vop_write_args *ap)
1427 {
1428         int error;
1429
1430         error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap);
1431         return (error);
1432 }
1433
1434 /*
1435  * Device ioctl operation.
1436         struct vop_ioctl_args {
1437                 struct vnode *a_vp;
1438                 int  a_command;
1439                 caddr_t  a_data;
1440                 int  a_fflag;
1441                 struct ucred *a_cred;
1442                 struct proc *a_p;
1443         }
1444  */
1445 /* ARGSUSED */
1446 static int
1447 devfs_ioctl(struct vop_ioctl_args *ap)
1448 {
1449         dn_p    dnp;
1450         int     error;
1451         struct vnode *vp = ap->a_vp;
1452
1453         if ((error = devfs_vntodn(vp,&dnp)) != 0)
1454                 return error;
1455
1456
1457         switch (vp->v_type) {
1458
1459         case VCHR:
1460                 return ((*vp->v_rdev->si_devsw->d_ioctl)(vp->v_rdev,
1461                                         ap->a_command,
1462                                         ap->a_data,
1463                                         ap->a_fflag,
1464                                         ap->a_p));
1465         case VBLK:
1466                 return ((*vp->v_rdev->si_devsw->d_ioctl)(vp->v_rdev,
1467                                         ap->a_command,
1468                                         ap->a_data,
1469                                         ap->a_fflag,
1470                                         ap->a_p));
1471         default:
1472                 panic("devfs_ioctl");
1473                 /* NOTREACHED */
1474         }
1475 }
1476
1477 /*
1478         struct vop_poll_args {
1479                 struct vnode *a_vp;
1480                 int  a_events;
1481                 struct ucred *a_cred;
1482                 struct proc *a_p;
1483         } *ap;
1484 */
1485 /* ARGSUSED */
1486 static int
1487 devfs_poll(struct vop_poll_args *ap)
1488 {
1489         dn_p    dnp;
1490         int     error;
1491         struct vnode *vp = ap->a_vp;
1492
1493         if ((error = devfs_vntodn(vp,&dnp)) != 0)
1494                 return error;
1495
1496
1497         switch (vp->v_type) {
1498
1499         case VCHR:
1500                 return (*vp->v_rdev->si_devsw->d_poll)(vp->v_rdev,
1501                                         ap->a_events,
1502                                         ap->a_p);
1503         default:
1504                 return (vop_defaultop((struct vop_generic_args *)ap));
1505
1506         }
1507 }
1508 /*
1509  * Synch buffers associated with a block device
1510         struct vop_fsync_args {
1511                 struct vnode *a_vp;
1512                 struct ucred *a_cred;
1513                 int  a_waitfor;
1514                 struct proc *a_p;
1515         } 
1516  */
1517 /* ARGSUSED */
1518 static int
1519 devfs_fsync(struct vop_fsync_args *ap)
1520 {
1521         struct vnode *vp = ap->a_vp;
1522         struct buf *bp;
1523         struct buf *nbp;
1524         int s;
1525         dn_p    dnp;
1526         int     error;
1527
1528         if ((error = devfs_vntodn(vp,&dnp)) != 0)
1529                 return error;
1530
1531
1532         if (vp->v_type == VCHR)
1533                 return (0);
1534         /*
1535          * Flush all dirty buffers associated with a block device.
1536          */
1537 loop:
1538         s = splbio();
1539         for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
1540                 nbp = TAILQ_NEXT(bp, b_vnbufs);
1541                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
1542                         continue;
1543                 if ((bp->b_flags & B_DELWRI) == 0)
1544                         panic("devfs_fsync: not dirty");
1545                 if ((vp->v_flag & VOBJBUF) && (bp->b_flags & B_CLUSTEROK)) {
1546                         BUF_UNLOCK(bp);
1547                         vfs_bio_awrite(bp);
1548                         splx(s);
1549                 } else {
1550                         bremfree(bp);
1551                         splx(s);
1552                         bawrite(bp);
1553                 }
1554                 goto loop;
1555         }
1556         if (ap->a_waitfor == MNT_WAIT) {
1557                 while (vp->v_numoutput) {
1558                         vp->v_flag |= VBWAIT;
1559                         (void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spfsyn", 0);
1560                 }
1561 #ifdef DIAGNOSTIC
1562                 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
1563                         vprint("devfs_fsync: dirty", vp);
1564                         splx(s);
1565                         goto loop;
1566                 }
1567 #endif
1568         }
1569         splx(s);
1570         return (0);
1571 }
1572 /*
1573  *
1574  *      struct vop_inactive_args {
1575  *              struct vnode *a_vp;
1576  *              struct proc *a_p;
1577  *      } 
1578  */
1579
1580 static int
1581 devfs_inactive(struct vop_inactive_args *ap)
1582 {
1583
1584         VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
1585         return (0);
1586 }
1587
1588 /*
1589  * Just call the device strategy routine
1590         struct vop_strategy_args {
1591                 struct vnode *a_vp;
1592                 struct buf *a_bp;
1593         }
1594  */
1595 static int
1596 devfs_strategy(struct vop_strategy_args *ap)
1597 {
1598         struct buf *bp = ap->a_bp;
1599         dn_p    dnp;
1600         int     error;
1601         struct vnode *vp = ap->a_vp;
1602
1603         if ((vp->v_type != VCHR)
1604         &&  (vp->v_type != VBLK))
1605                 panic ("devfs_strat:badvnode type");
1606         if ((error = devfs_vntodn(vp,&dnp)) != 0)
1607                 return error;
1608
1609
1610         if (((bp->b_flags & B_READ) == 0) &&
1611                 (LIST_FIRST(&bp->b_dep)) != NULL && bioops.io_start)
1612                 (*bioops.io_start)(bp);
1613         switch (vp->v_type) {
1614         case VCHR:
1615                 (*vp->v_rdev->si_devsw->d_strategy)(bp);
1616                 break;
1617         case VBLK:
1618                 (*vp->v_rdev->si_devsw->d_strategy)(bp);
1619                 break;
1620         default:
1621                 /* XXX set error code? */
1622                 break;
1623         }
1624         return (0);
1625 }
1626
1627 /*
1628  * I can't say I'm completely sure what this one is for.
1629  * it's copied from specfs.
1630         struct vop_freeblks_args {
1631                 struct vnode *a_vp;
1632                 daddr_t a_addr;
1633                 daddr_t a_length;
1634         };
1635  */
1636 static int
1637 devfs_freeblks(struct vop_freeblks_args *ap)
1638 {
1639         struct cdevsw *bsw;
1640         struct buf *bp;
1641         struct vnode *vp = ap->a_vp;
1642
1643         bsw = devsw(vp->v_rdev);
1644         if ((bsw->d_flags & D_CANFREE) == 0)
1645                 return (0);
1646         bp = geteblk(ap->a_length);
1647         bp->b_flags |= B_FREEBUF;
1648         bp->b_dev = vp->v_rdev;
1649         bp->b_blkno = ap->a_addr;
1650         bp->b_offset = dbtob(ap->a_addr);
1651         bp->b_bcount = ap->a_length;
1652         BUF_STRATEGY(bp, 0);
1653         return (0);
1654 }
1655
1656
1657 /*
1658  * This is a noop, simply returning what one has been given.
1659         struct vop_bmap_args  {
1660                 struct vnode *a_vp;
1661                 daddr_t  a_bn;
1662                 struct vnode **a_vpp;
1663                 daddr_t *a_bnp;
1664                 int *a_runp;
1665                 int *a_runb;
1666         }
1667  */
1668 static int
1669 devfs_bmap(struct vop_bmap_args *ap)
1670 {
1671
1672         if (ap->a_vpp != NULL)
1673                 *ap->a_vpp = ap->a_vp;
1674         if (ap->a_bnp != NULL)
1675                 *ap->a_bnp = ap->a_bn;
1676         if (ap->a_runp != NULL)
1677                 *ap->a_runp = 0;
1678         if (ap->a_runb != NULL)
1679                 *ap->a_runb = 0;
1680         return (0);
1681 }
1682
1683 /*
1684  * Device close routine
1685         struct vop_close_args {
1686                 struct vnode *a_vp;
1687                 int  a_fflag;
1688                 struct ucred *a_cred;
1689                 struct proc *a_p;
1690         }
1691  */
1692 /* ARGSUSED */
1693 static int
1694 devfs_close(struct vop_close_args *ap)
1695 {
1696         struct vnode *vp = ap->a_vp;
1697         dn_p dnp;
1698         struct cdevsw *devswp;
1699         dev_t dev;
1700         int mode, error;
1701
1702         if ((error = devfs_vntodn(vp,&dnp)) != 0)
1703                 return error;
1704
1705
1706         switch (vp->v_type) {
1707
1708         case VCHR:
1709                 devswp = vp->v_rdev->si_devsw;
1710                 dev = vp->v_rdev;
1711                 mode = S_IFCHR;
1712                 /*
1713                  * Hack: a tty device that is a controlling terminal
1714                  * has a reference from the session structure.
1715                  * We cannot easily tell that a character device is
1716                  * a controlling terminal, unless it is the closing
1717                  * process' controlling terminal.  In that case,
1718                  * if the reference count is 2 (this last descriptor
1719                  * plus the session), release the reference from the session.
1720                  */
1721                 if (vcount(vp) == 2 && ap->a_p &&
1722                     (vp->v_flag & VXLOCK) == 0 &&
1723                     vp == ap->a_p->p_session->s_ttyvp) {
1724                         vrele(vp);
1725                         ap->a_p->p_session->s_ttyvp = NULL;
1726                 }
1727                 if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
1728                         return (0);
1729
1730                 break;
1731
1732         case VBLK:
1733                 devswp = vp->v_rdev->si_devsw;
1734                 dev = vp->v_rdev;
1735                 mode = S_IFBLK;
1736                 /*
1737                  * On last close of a block device (that isn't mounted)
1738                  * we must invalidate any in core blocks, so that
1739                  * we can, for instance, change floppy disks.
1740                  */
1741                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
1742                 error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
1743                 VOP_UNLOCK(vp, 0, ap->a_p);
1744                 if (error)
1745                         return (error);
1746
1747                 break;
1748         default:
1749                 panic("devfs_close: not special");
1750         }
1751         /*
1752          * If the vnode is locked, then we are in the midst
1753          * of forcably closing the device, otherwise we would normally
1754          * only close on last reference.
1755          * We do not want to really close the device if it
1756          * is still in use unless we are trying to close it
1757          * forcibly. Since every use (buffer, vnode, swap, cmap)
1758          * holds a reference to the vnode, and because we mark
1759          * any other vnodes that alias this device, when the
1760          * sum of the reference counts on all the aliased
1761          * vnodes descends to one, we are on last close.
1762          * defeat this however if the device wants to be told of every 
1763          * close.
1764          */
1765         if ((vp->v_flag & VXLOCK)
1766         || (devswp->d_flags & D_TRACKCLOSE)
1767         || (vcount(vp) <= 1)) {
1768                 return ((*devswp->d_close)(dev, ap->a_fflag, mode, ap->a_p));
1769         }
1770         return (0);
1771 }
1772
1773 /*
1774  * Special device advisory byte-level locks.
1775         struct vop_advlock_args {
1776                 struct vnode *a_vp;
1777                 caddr_t  a_id;
1778                 int  a_op;
1779                 struct flock *a_fl;
1780                 int  a_flags;
1781         }
1782  */
1783 /* ARGSUSED */
1784 static int
1785 devfs_advlock(struct vop_advlock_args *ap)
1786 {
1787
1788         return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
1789 }
1790
1791 /*
1792  * Special device bad operation
1793  */
1794 static int
1795 devfs_badop(void)
1796 {
1797
1798         panic("devfs_badop called");
1799         /* NOTREACHED */
1800 }
1801
1802 static void
1803 devfs_getpages_iodone(struct buf *bp)
1804 {
1805
1806         bp->b_flags |= B_DONE;
1807         wakeup(bp);
1808 }
1809
1810 static int
1811 devfs_getpages(struct vop_getpages_args *ap)
1812 {
1813         vm_offset_t kva;
1814         int error;
1815         int i, pcount, size, s;
1816         daddr_t blkno;
1817         struct buf *bp;
1818         vm_page_t m;
1819         vm_ooffset_t offset;
1820         int toff, nextoff, nread;
1821         struct vnode *vp = ap->a_vp;
1822         int blksiz;
1823         int gotreqpage;
1824
1825         error = 0;
1826         pcount = round_page(ap->a_count) / PAGE_SIZE;
1827
1828         /*
1829          * Calculate the offset of the transfer and do sanity check.
1830          * FreeBSD currently only supports an 8 TB range due to b_blkno
1831          * being in DEV_BSIZE ( usually 512 ) byte chunks on call to
1832          * VOP_STRATEGY.  XXX
1833          */
1834         offset = IDX_TO_OFF(ap->a_m[0]->pindex) + ap->a_offset;
1835
1836 #define DADDR_T_BIT     (sizeof(daddr_t)*8)
1837 #define OFFSET_MAX      ((1LL << (DADDR_T_BIT + DEV_BSHIFT)) - 1)
1838
1839         if (offset < 0 || offset > OFFSET_MAX) {
1840                 /* XXX still no %q in kernel. */
1841                 printf("devfs_getpages: preposterous offset 0x%x%08x\n",
1842                        (u_int)((u_quad_t)offset >> 32),
1843                        (u_int)(offset & 0xffffffff));
1844                 return (VM_PAGER_ERROR);
1845         }
1846
1847         blkno = btodb(offset);
1848
1849         /*
1850          * Round up physical size for real devices.  We cannot round using
1851          * v_mount's block size data because v_mount has nothing to do with
1852          * the device.  i.e. it's usually '/dev'.  We need the physical block
1853          * size for the device itself.
1854          *
1855          * We can't use v_specmountpoint because it only exists when the
1856          * block device is mounted.  However, we can use v_rdev.
1857          */
1858
1859         if (vp->v_type == VBLK)
1860                 blksiz = vp->v_rdev->si_bsize_phys;
1861         else
1862                 blksiz = DEV_BSIZE;
1863
1864         size = (ap->a_count + blksiz - 1) & ~(blksiz - 1);
1865
1866         bp = getpbuf(NULL);
1867         kva = (vm_offset_t)bp->b_data;
1868
1869         /*
1870          * Map the pages to be read into the kva.
1871          */
1872         pmap_qenter(kva, ap->a_m, pcount);
1873
1874         /* Build a minimal buffer header. */
1875         bp->b_flags = B_READ | B_CALL;
1876         bp->b_iodone = devfs_getpages_iodone;
1877
1878         /* B_PHYS is not set, but it is nice to fill this in. */
1879         bp->b_rcred = bp->b_wcred = curproc->p_ucred;
1880         if (bp->b_rcred != NOCRED)
1881                 crhold(bp->b_rcred);
1882         if (bp->b_wcred != NOCRED)
1883                 crhold(bp->b_wcred);
1884         bp->b_blkno = blkno;
1885         bp->b_lblkno = blkno;
1886         pbgetvp(vp, bp);
1887         bp->b_bcount = size;
1888         bp->b_bufsize = size;
1889         bp->b_resid = 0;
1890
1891         cnt.v_vnodein++;
1892         cnt.v_vnodepgsin += pcount;
1893
1894         /* Do the input. */
1895         VOP_STRATEGY(bp->b_vp, bp);
1896
1897         s = splbio();
1898
1899         /* We definitely need to be at splbio here. */
1900         while ((bp->b_flags & B_DONE) == 0)
1901                 tsleep(bp, PVM, "spread", 0);
1902
1903         splx(s);
1904
1905         if ((bp->b_flags & B_ERROR) != 0) {
1906                 if (bp->b_error)
1907                         error = bp->b_error;
1908                 else
1909                         error = EIO;
1910         }
1911
1912         nread = size - bp->b_resid;
1913
1914         if (nread < ap->a_count) {
1915                 bzero((caddr_t)kva + nread,
1916                         ap->a_count - nread);
1917         }
1918         pmap_qremove(kva, pcount);
1919
1920
1921         gotreqpage = 0;
1922         for (i = 0, toff = 0; i < pcount; i++, toff = nextoff) {
1923                 nextoff = toff + PAGE_SIZE;
1924                 m = ap->a_m[i];
1925
1926                 m->flags &= ~PG_ZERO;
1927
1928                 if (nextoff <= nread) {
1929                         m->valid = VM_PAGE_BITS_ALL;
1930                         vm_page_undirty(m);
1931                 } else if (toff < nread) {
1932                         /*
1933                          * Since this is a VM request, we have to supply the
1934                          * unaligned offset to allow vm_page_set_validclean()
1935                          * to zero sub-DEV_BSIZE'd portions of the page.
1936                          */
1937                         vm_page_set_validclean(m, 0, nread - toff);
1938                 } else {
1939                         m->valid = 0;
1940                         vm_page_undirty(m);
1941                 }
1942
1943                 if (i != ap->a_reqpage) {
1944                         /*
1945                          * Just in case someone was asking for this page we
1946                          * now tell them that it is ok to use.
1947                          */
1948                         if (!error || (m->valid == VM_PAGE_BITS_ALL)) {
1949                                 if (m->valid) {
1950                                         if (m->flags & PG_WANTED) {
1951                                                 vm_page_activate(m);
1952                                         } else {
1953                                                 vm_page_deactivate(m);
1954                                         }
1955                                         vm_page_wakeup(m);
1956                                 } else {
1957                                         vm_page_free(m);
1958                                 }
1959                         } else {
1960                                 vm_page_free(m);
1961                         }
1962                 } else if (m->valid) {
1963                         gotreqpage = 1;
1964                         /*
1965                          * Since this is a VM request, we need to make the
1966                          * entire page presentable by zeroing invalid sections.
1967                          */
1968                         if (m->valid != VM_PAGE_BITS_ALL)
1969                                 vm_page_zero_invalid(m, FALSE);
1970                 }
1971         }
1972         if (!gotreqpage) {
1973                 m = ap->a_m[ap->a_reqpage];
1974 #ifndef MAX_PERF
1975                 printf("devfs_getpages: I/O read failure: (error code=%d)\n",
1976                                                                 error);
1977                 printf("               size: %d, resid:"
1978                         " %ld, a_count: %d, valid: 0x%x\n",
1979                                 size, bp->b_resid, ap->a_count, m->valid);
1980                 printf("               nread: %d, reqpage:"
1981                         " %d, pindex: %d, pcount: %d\n",
1982                                 nread, ap->a_reqpage, m->pindex, pcount);
1983 #endif
1984                 /*
1985                  * Free the buffer header back to the swap buffer pool.
1986                  */
1987                 relpbuf(bp, NULL);
1988                 return VM_PAGER_ERROR;
1989         }
1990         /*
1991          * Free the buffer header back to the swap buffer pool.
1992          */
1993         relpbuf(bp, NULL);
1994         return VM_PAGER_OK;
1995 }
1996
1997
1998
1999 /* These are the operations used by directories etc in a devfs */
2000
2001 vop_t **devfs_vnodeop_p;
2002 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
2003         { &vop_default_desc,            (vop_t *) vop_defaultop },
2004         { &vop_access_desc,             (vop_t *) devfs_access },
2005         { &vop_bmap_desc,               (vop_t *) devfs_badop },
2006         { &vop_getattr_desc,            (vop_t *) devfs_getattr },
2007         { &vop_inactive_desc,           (vop_t *) devfs_inactive },
2008         { &vop_link_desc,               (vop_t *) devfs_link },
2009         { &vop_lookup_desc,             (vop_t *) devfs_lookup },
2010         { &vop_pathconf_desc,           (vop_t *) vop_stdpathconf },
2011         { &vop_print_desc,              (vop_t *) devfs_print },
2012         { &vop_read_desc,               (vop_t *) devfs_xread },
2013         { &vop_readdir_desc,            (vop_t *) devfs_readdir },
2014         { &vop_readlink_desc,           (vop_t *) devfs_readlink },
2015         { &vop_reclaim_desc,            (vop_t *) devfs_reclaim },
2016         { &vop_remove_desc,             (vop_t *) devfs_remove },
2017         { &vop_rename_desc,             (vop_t *) devfs_rename },
2018         { &vop_setattr_desc,            (vop_t *) devfs_setattr },
2019         { &vop_symlink_desc,            (vop_t *) devfs_symlink },
2020         { &vop_write_desc,              (vop_t *) devfs_xwrite },
2021         { NULL, NULL }
2022 };
2023 static struct vnodeopv_desc devfs_vnodeop_opv_desc =
2024         { &devfs_vnodeop_p, devfs_vnodeop_entries };
2025
2026 VNODEOP_SET(devfs_vnodeop_opv_desc);
2027
2028
2029
2030 vop_t **devfs_spec_vnodeop_p;
2031 static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = {
2032         { &vop_default_desc,            (vop_t *) vop_defaultop },
2033         { &vop_access_desc,             (vop_t *) devfs_access },
2034         { &vop_advlock_desc,            (vop_t *) devfs_advlock },
2035         { &vop_bmap_desc,               (vop_t *) devfs_bmap },
2036         { &vop_close_desc,              (vop_t *) devfs_close },
2037         { &vop_create_desc,             (vop_t *) devfs_badop },
2038         { &vop_freeblks_desc,           (vop_t *) devfs_freeblks },
2039         { &vop_fsync_desc,              (vop_t *) devfs_fsync },
2040         { &vop_getattr_desc,            (vop_t *) devfs_getattr },
2041         { &vop_getpages_desc,           (vop_t *) devfs_getpages },
2042         { &vop_inactive_desc,           (vop_t *) devfs_inactive },
2043         { &vop_ioctl_desc,              (vop_t *) devfs_ioctl },
2044         { &vop_lease_desc,              (vop_t *) vop_null },
2045         { &vop_link_desc,               (vop_t *) devfs_badop },
2046         { &vop_lookup_desc,             (vop_t *) devfs_lookup },
2047         { &vop_mkdir_desc,              (vop_t *) devfs_badop },
2048         { &vop_mknod_desc,              (vop_t *) devfs_badop },
2049         { &vop_open_desc,               (vop_t *) devfs_open },
2050         { &vop_pathconf_desc,           (vop_t *) vop_stdpathconf },
2051         { &vop_poll_desc,               (vop_t *) devfs_poll },
2052         { &vop_print_desc,              (vop_t *) devfs_print },
2053         { &vop_read_desc,               (vop_t *) devfs_read },
2054         { &vop_readdir_desc,            (vop_t *) devfs_badop },
2055         { &vop_readlink_desc,           (vop_t *) devfs_badop },
2056         { &vop_reallocblks_desc,        (vop_t *) devfs_badop },
2057         { &vop_reclaim_desc,            (vop_t *) devfs_reclaim },
2058         { &vop_remove_desc,             (vop_t *) devfs_badop },
2059         { &vop_rename_desc,             (vop_t *) devfs_badop },
2060         { &vop_rmdir_desc,              (vop_t *) devfs_badop },
2061         { &vop_setattr_desc,            (vop_t *) devfs_setattr },
2062         { &vop_strategy_desc,           (vop_t *) devfs_strategy },
2063         { &vop_symlink_desc,            (vop_t *) devfs_symlink },
2064         { &vop_write_desc,              (vop_t *) devfs_write },
2065         { NULL, NULL }
2066 };
2067 static struct vnodeopv_desc devfs_spec_vnodeop_opv_desc =
2068         { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries };
2069
2070 VNODEOP_SET(devfs_spec_vnodeop_opv_desc);
2071