b2893284947de7093efce5ed3b3e7b08df18b961
[dragonfly.git] / sys / kern / vfs_default.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed
6  * to Berkeley by John Heidemann of the UCLA Ficus project.
7  *
8  * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *
39  * $FreeBSD: src/sys/kern/vfs_default.c,v 1.28.2.7 2003/01/10 18:23:26 bde Exp $
40  * $DragonFly: src/sys/kern/vfs_default.c,v 1.36 2006/05/05 16:35:00 dillon Exp $
41  */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/buf.h>
46 #include <sys/conf.h>
47 #include <sys/fcntl.h>
48 #include <sys/file.h>
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/malloc.h>
52 #include <sys/mount.h>
53 #include <sys/unistd.h>
54 #include <sys/vnode.h>
55 #include <sys/namei.h>
56 #include <sys/nlookup.h>
57 #include <sys/poll.h>
58 #include <sys/mountctl.h>
59
60 #include <machine/limits.h>
61
62 #include <vm/vm.h>
63 #include <vm/vm_object.h>
64 #include <vm/vm_page.h>
65 #include <vm/vm_pager.h>
66 #include <vm/vnode_pager.h>
67
68 static int      vop_nolookup (struct vop_old_lookup_args *);
69 static int      vop_nostrategy (struct vop_strategy_args *);
70
71 /*
72  * This vnode table stores what we want to do if the filesystem doesn't
73  * implement a particular VOP.
74  *
75  * If there is no specific entry here, we will return EOPNOTSUPP.
76  */
77 struct vop_ops *default_vnode_vops;
78 static struct vnodeopv_entry_desc default_vnodeop_entries[] = {
79         { &vop_default_desc,            vop_eopnotsupp },
80         { &vop_advlock_desc,            vop_einval },
81         { &vop_fsync_desc,              vop_null },
82         { &vop_ioctl_desc,              vop_enotty },
83         { &vop_islocked_desc,           (void *) vop_stdislocked },
84         { &vop_lock_desc,               (void *) vop_stdlock },
85         { &vop_mmap_desc,               vop_einval },
86         { &vop_old_lookup_desc,         (void *) vop_nolookup },
87         { &vop_open_desc,               (void *) vop_stdopen },
88         { &vop_close_desc,              (void *) vop_stdclose },
89         { &vop_pathconf_desc,           vop_einval },
90         { &vop_poll_desc,               (void *) vop_nopoll },
91         { &vop_readlink_desc,           vop_einval },
92         { &vop_reallocblks_desc,        vop_eopnotsupp },
93         { &vop_revoke_desc,             (void *) vop_stdrevoke },
94         { &vop_strategy_desc,           (void *) vop_nostrategy },
95         { &vop_unlock_desc,             (void *) vop_stdunlock },
96         { &vop_getacl_desc,             vop_eopnotsupp },
97         { &vop_setacl_desc,             vop_eopnotsupp },
98         { &vop_aclcheck_desc,           vop_eopnotsupp },
99         { &vop_getextattr_desc,         vop_eopnotsupp },
100         { &vop_setextattr_desc,         vop_eopnotsupp },
101         { &vop_nresolve_desc,           (void *) vop_compat_nresolve },
102         { &vop_nlookupdotdot_desc,      (void *) vop_compat_nlookupdotdot },
103         { &vop_ncreate_desc,            (void *) vop_compat_ncreate },
104         { &vop_nmkdir_desc,             (void *) vop_compat_nmkdir },
105         { &vop_nmknod_desc,             (void *) vop_compat_nmknod },
106         { &vop_nlink_desc,              (void *) vop_compat_nlink },
107         { &vop_nsymlink_desc,           (void *) vop_compat_nsymlink },
108         { &vop_nwhiteout_desc,          (void *) vop_compat_nwhiteout },
109         { &vop_nremove_desc,            (void *) vop_compat_nremove },
110         { &vop_nrmdir_desc,             (void *) vop_compat_nrmdir },
111         { &vop_nrename_desc,            (void *) vop_compat_nrename },
112         { &vop_mountctl_desc,           (void *) journal_mountctl },
113         { NULL, NULL }
114 };
115
116 static struct vnodeopv_desc default_vnodeop_opv_desc =
117         { &default_vnode_vops, default_vnodeop_entries, 0 };
118
119 VNODEOP_SET(default_vnodeop_opv_desc);
120
121 int
122 vop_eopnotsupp(struct vop_generic_args *ap)
123 {
124         return (EOPNOTSUPP);
125 }
126
127 int
128 vop_ebadf(struct vop_generic_args *ap)
129 {
130         return (EBADF);
131 }
132
133 int
134 vop_enotty(struct vop_generic_args *ap)
135 {
136         return (ENOTTY);
137 }
138
139 int
140 vop_einval(struct vop_generic_args *ap)
141 {
142         return (EINVAL);
143 }
144
145 int
146 vop_null(struct vop_generic_args *ap)
147 {
148         return (0);
149 }
150
151 int
152 vop_defaultop(struct vop_generic_args *ap)
153 {
154         return (VOCALL(default_vnode_vops, ap));
155 }
156
157 int
158 vop_panic(struct vop_generic_args *ap)
159 {
160
161         panic("filesystem goof: vop_panic[%s]", ap->a_desc->vdesc_name);
162 }
163
164 /*
165  * vop_compat_resolve { struct namecache *a_ncp }       XXX STOPGAP FUNCTION
166  *
167  * XXX OLD API ROUTINE!  WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE
168  * WILL BE REMOVED.  This procedure exists for all VFSs which have not
169  * yet implemented VOP_NRESOLVE().  It converts VOP_NRESOLVE() into a 
170  * vop_old_lookup() and does appropriate translations.
171  *
172  * Resolve a ncp for VFSs which do not support the VOP.  Eventually all
173  * VFSs will support this VOP and this routine can be removed, since
174  * VOP_NRESOLVE() is far less complex then the older LOOKUP/CACHEDLOOKUP
175  * API.
176  *
177  * A locked ncp is passed in to be resolved.  The NCP is resolved by
178  * figuring out the vnode (if any) and calling cache_setvp() to attach the
179  * vnode to the entry.  If the entry represents a non-existant node then
180  * cache_setvp() is called with a NULL vnode to resolve the entry into a
181  * negative cache entry.  No vnode locks are retained and the
182  * ncp is left locked on return.
183  *
184  * The ncp will NEVER represent "", "." or "..", or contain any slashes.
185  *
186  * There is a potential directory and vnode interlock.   The lock order
187  * requirement is: namecache, governing directory, resolved vnode.
188  */
189 int
190 vop_compat_nresolve(struct vop_nresolve_args *ap)
191 {
192         int error;
193         struct vnode *dvp;
194         struct vnode *vp;
195         struct namecache *ncp;
196         struct componentname cnp;
197
198         ncp = ap->a_ncp;        /* locked namecache node */
199         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
200                 return(EPERM);
201         if (ncp->nc_parent == NULL)
202                 return(EPERM);
203         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
204                 return(EPERM);
205
206         /*
207          * UFS currently stores all sorts of side effects, including a loop
208          * variable, in the directory inode.  That needs to be fixed and the
209          * other VFS's audited before we can switch to LK_SHARED.
210          */
211         if ((error = vget(dvp, LK_EXCLUSIVE, curthread)) != 0) {
212                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
213                         ncp, ncp->nc_name);
214                 return(EAGAIN);
215         }
216
217         bzero(&cnp, sizeof(cnp));
218         cnp.cn_nameiop = NAMEI_LOOKUP;
219         cnp.cn_flags = 0;
220         cnp.cn_nameptr = ncp->nc_name;
221         cnp.cn_namelen = ncp->nc_nlen;
222         cnp.cn_cred = ap->a_cred;
223         cnp.cn_td = curthread; /* XXX */
224
225         /*
226          * vop_old_lookup() always returns vp locked.  dvp may or may not be
227          * left locked depending on CNP_PDIRUNLOCK.
228          */
229         error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
230         if (error == 0)
231                 VOP_UNLOCK(vp, 0, curthread);
232         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
233                 VOP_UNLOCK(dvp, 0, curthread);
234         if ((ncp->nc_flag & NCF_UNRESOLVED) == 0) {
235                 /* was resolved by another process while we were unlocked */
236                 if (error == 0)
237                         vrele(vp);
238         } else if (error == 0) {
239                 KKASSERT(vp != NULL);
240                 cache_setvp(ncp, vp);
241                 vrele(vp);
242         } else if (error == ENOENT) {
243                 KKASSERT(vp == NULL);
244                 if (cnp.cn_flags & CNP_ISWHITEOUT)
245                         ncp->nc_flag |= NCF_WHITEOUT;
246                 cache_setvp(ncp, NULL);
247         }
248         vrele(dvp);
249         return (error);
250 }
251
252 /*
253  * vop_compat_nlookupdotdot { struct vnode *a_dvp,
254  *                      struct vnode **a_vpp,
255  *                      struct ucred *a_cred }
256  *
257  * Lookup the vnode representing the parent directory of the specified
258  * directory vnode.  a_dvp should not be locked.  If no error occurs *a_vpp
259  * will contained the parent vnode, locked and refd, else *a_vpp will be NULL.
260  *
261  * This function is designed to aid NFS server-side operations and is
262  * used by cache_fromdvp() to create a consistent, connected namecache
263  * topology.
264  *
265  * As part of the NEW API work, VFSs will first split their CNP_ISDOTDOT
266  * code out from their *_lookup() and create *_nlookupdotdot().  Then as time
267  * permits VFSs will implement the remaining *_n*() calls and finally get
268  * rid of their *_lookup() call.
269  */
270 int
271 vop_compat_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
272 {
273         struct componentname cnp;
274         int error;
275
276         /*
277          * UFS currently stores all sorts of side effects, including a loop
278          * variable, in the directory inode.  That needs to be fixed and the
279          * other VFS's audited before we can switch to LK_SHARED.
280          */
281         *ap->a_vpp = NULL;
282         if ((error = vget(ap->a_dvp, LK_EXCLUSIVE, curthread)) != 0)
283                 return (error);
284         if (ap->a_dvp->v_type != VDIR) {
285                 vput(ap->a_dvp);
286                 return (ENOTDIR);
287         }
288
289         bzero(&cnp, sizeof(cnp));
290         cnp.cn_nameiop = NAMEI_LOOKUP;
291         cnp.cn_flags = CNP_ISDOTDOT;
292         cnp.cn_nameptr = "..";
293         cnp.cn_namelen = 2;
294         cnp.cn_cred = ap->a_cred;
295         cnp.cn_td = curthread; /* XXX */
296
297         /*
298          * vop_old_lookup() always returns vp locked.  dvp may or may not be
299          * left locked depending on CNP_PDIRUNLOCK.
300          */
301         error = vop_old_lookup(ap->a_head.a_ops, ap->a_dvp, ap->a_vpp, &cnp);
302         if (error == 0)
303                 VOP_UNLOCK(*ap->a_vpp, 0, curthread);
304         if (cnp.cn_flags & CNP_PDIRUNLOCK)
305                 vrele(ap->a_dvp);
306         else
307                 vput(ap->a_dvp);
308         return (error);
309 }
310
311 /*
312  * vop_compat_ncreate { struct namecache *a_ncp,        XXX STOPGAP FUNCTION
313  *                      struct vnode *a_vpp,
314  *                      struct ucred *a_cred,
315  *                      struct vattr *a_vap }
316  *
317  * Create a file as specified by a_vap.  Compatibility requires us to issue
318  * the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_CREATE in order
319  * to setup the directory inode's i_offset and i_count (e.g. in UFS).
320  */
321 int
322 vop_compat_ncreate(struct vop_ncreate_args *ap)
323 {
324         struct thread *td = curthread;
325         struct componentname cnp;
326         struct namecache *ncp;
327         struct vnode *dvp;
328         int error;
329
330         /*
331          * Sanity checks, get a locked directory vnode.
332          */
333         ncp = ap->a_ncp;                /* locked namecache node */
334         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
335                 return(EPERM);
336         if (ncp->nc_parent == NULL)
337                 return(EPERM);
338         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
339                 return(EPERM);
340
341         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
342                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
343                         ncp, ncp->nc_name);
344                 return(EAGAIN);
345         }
346
347         /*
348          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
349          * caches all information required to create the entry in the
350          * directory inode.  We expect a return code of EJUSTRETURN for
351          * the CREATE case.  The cnp must simulated a saved-name situation.
352          */
353         bzero(&cnp, sizeof(cnp));
354         cnp.cn_nameiop = NAMEI_CREATE;
355         cnp.cn_flags = CNP_LOCKPARENT;
356         cnp.cn_nameptr = ncp->nc_name;
357         cnp.cn_namelen = ncp->nc_nlen;
358         cnp.cn_cred = ap->a_cred;
359         cnp.cn_td = td;
360         *ap->a_vpp = NULL;
361
362         error = vop_old_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
363
364         /*
365          * EJUSTRETURN should be returned for this case, which means that
366          * the VFS has setup the directory inode for the create.  The dvp we
367          * passed in is expected to remain in a locked state.
368          *
369          * If the VOP_OLD_CREATE is successful we are responsible for updating
370          * the cache state of the locked ncp that was passed to us.
371          */
372         if (error == EJUSTRETURN) {
373                 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
374                 error = VOP_OLD_CREATE(dvp, ap->a_vpp, &cnp, ap->a_vap);
375                 if (error == 0) {
376                         cache_setunresolved(ncp);
377                         cache_setvp(ncp, *ap->a_vpp);
378                 }
379         } else {
380                 if (error == 0) {
381                         vput(*ap->a_vpp);
382                         *ap->a_vpp = NULL;
383                         error = EEXIST;
384                 }
385                 KKASSERT(*ap->a_vpp == NULL);
386         }
387         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
388                 VOP_UNLOCK(dvp, 0, td);
389         vrele(dvp);
390         return (error);
391 }
392
393 /*
394  * vop_compat_nmkdir { struct namecache *a_ncp,         XXX STOPGAP FUNCTION
395  *                      struct vnode *a_vpp,
396  *                      struct ucred *a_cred,
397  *                      struct vattr *a_vap }
398  *
399  * Create a directory as specified by a_vap.  Compatibility requires us to
400  * issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKDIR in
401  * order to setup the directory inode's i_offset and i_count (e.g. in UFS).
402  */
403 int
404 vop_compat_nmkdir(struct vop_nmkdir_args *ap)
405 {
406         struct thread *td = curthread;
407         struct componentname cnp;
408         struct namecache *ncp;
409         struct vnode *dvp;
410         int error;
411
412         /*
413          * Sanity checks, get a locked directory vnode.
414          */
415         ncp = ap->a_ncp;                /* locked namecache node */
416         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
417                 return(EPERM);
418         if (ncp->nc_parent == NULL)
419                 return(EPERM);
420         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
421                 return(EPERM);
422
423         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
424                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
425                         ncp, ncp->nc_name);
426                 return(EAGAIN);
427         }
428
429         /*
430          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
431          * caches all information required to create the entry in the
432          * directory inode.  We expect a return code of EJUSTRETURN for
433          * the CREATE case.  The cnp must simulated a saved-name situation.
434          */
435         bzero(&cnp, sizeof(cnp));
436         cnp.cn_nameiop = NAMEI_CREATE;
437         cnp.cn_flags = CNP_LOCKPARENT;
438         cnp.cn_nameptr = ncp->nc_name;
439         cnp.cn_namelen = ncp->nc_nlen;
440         cnp.cn_cred = ap->a_cred;
441         cnp.cn_td = td;
442         *ap->a_vpp = NULL;
443
444         error = vop_old_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
445
446         /*
447          * EJUSTRETURN should be returned for this case, which means that
448          * the VFS has setup the directory inode for the create.  The dvp we
449          * passed in is expected to remain in a locked state.
450          *
451          * If the VOP_OLD_MKDIR is successful we are responsible for updating
452          * the cache state of the locked ncp that was passed to us.
453          */
454         if (error == EJUSTRETURN) {
455                 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
456                 error = VOP_OLD_MKDIR(dvp, ap->a_vpp, &cnp, ap->a_vap);
457                 if (error == 0) {
458                         cache_setunresolved(ncp);
459                         cache_setvp(ncp, *ap->a_vpp);
460                 }
461         } else {
462                 if (error == 0) {
463                         vput(*ap->a_vpp);
464                         *ap->a_vpp = NULL;
465                         error = EEXIST;
466                 }
467                 KKASSERT(*ap->a_vpp == NULL);
468         }
469         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
470                 VOP_UNLOCK(dvp, 0, td);
471         vrele(dvp);
472         return (error);
473 }
474
475 /*
476  * vop_compat_nmknod { struct namecache *a_ncp,         XXX STOPGAP FUNCTION
477  *                      struct vnode *a_vpp,
478  *                      struct ucred *a_cred,
479  *                      struct vattr *a_vap }
480  *
481  * Create a device or fifo node as specified by a_vap.  Compatibility requires
482  * us to issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKNOD
483  * in order to setup the directory inode's i_offset and i_count (e.g. in UFS).
484  */
485 int
486 vop_compat_nmknod(struct vop_nmknod_args *ap)
487 {
488         struct thread *td = curthread;
489         struct componentname cnp;
490         struct namecache *ncp;
491         struct vnode *dvp;
492         int error;
493
494         /*
495          * Sanity checks, get a locked directory vnode.
496          */
497         ncp = ap->a_ncp;                /* locked namecache node */
498         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
499                 return(EPERM);
500         if (ncp->nc_parent == NULL)
501                 return(EPERM);
502         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
503                 return(EPERM);
504
505         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
506                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
507                         ncp, ncp->nc_name);
508                 return(EAGAIN);
509         }
510
511         /*
512          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
513          * caches all information required to create the entry in the
514          * directory inode.  We expect a return code of EJUSTRETURN for
515          * the CREATE case.  The cnp must simulated a saved-name situation.
516          */
517         bzero(&cnp, sizeof(cnp));
518         cnp.cn_nameiop = NAMEI_CREATE;
519         cnp.cn_flags = CNP_LOCKPARENT;
520         cnp.cn_nameptr = ncp->nc_name;
521         cnp.cn_namelen = ncp->nc_nlen;
522         cnp.cn_cred = ap->a_cred;
523         cnp.cn_td = td;
524         *ap->a_vpp = NULL;
525
526         error = vop_old_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
527
528         /*
529          * EJUSTRETURN should be returned for this case, which means that
530          * the VFS has setup the directory inode for the create.  The dvp we
531          * passed in is expected to remain in a locked state.
532          *
533          * If the VOP_OLD_MKNOD is successful we are responsible for updating
534          * the cache state of the locked ncp that was passed to us.
535          */
536         if (error == EJUSTRETURN) {
537                 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
538                 error = VOP_OLD_MKNOD(dvp, ap->a_vpp, &cnp, ap->a_vap);
539                 if (error == 0) {
540                         cache_setunresolved(ncp);
541                         cache_setvp(ncp, *ap->a_vpp);
542                 }
543         } else {
544                 if (error == 0) {
545                         vput(*ap->a_vpp);
546                         *ap->a_vpp = NULL;
547                         error = EEXIST;
548                 }
549                 KKASSERT(*ap->a_vpp == NULL);
550         }
551         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
552                 VOP_UNLOCK(dvp, 0, td);
553         vrele(dvp);
554         return (error);
555 }
556
557 /*
558  * vop_compat_nlink { struct namecache *a_ncp,  XXX STOPGAP FUNCTION
559  *                      struct vnode *a_vp,
560  *                      struct ucred *a_cred }
561  *
562  * The passed vp is locked and represents the source.  The passed ncp is
563  * locked and represents the target to create.
564  */
565 int
566 vop_compat_nlink(struct vop_nlink_args *ap)
567 {
568         struct thread *td = curthread;
569         struct componentname cnp;
570         struct namecache *ncp;
571         struct vnode *dvp;
572         struct vnode *tvp;
573         int error;
574
575         /*
576          * Sanity checks, get a locked directory vnode.
577          */
578         ncp = ap->a_ncp;                /* locked namecache node */
579         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
580                 return(EPERM);
581         if (ncp->nc_parent == NULL)
582                 return(EPERM);
583         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
584                 return(EPERM);
585
586         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
587                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
588                         ncp, ncp->nc_name);
589                 return(EAGAIN);
590         }
591
592         /*
593          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
594          * caches all information required to create the entry in the
595          * directory inode.  We expect a return code of EJUSTRETURN for
596          * the CREATE case.  The cnp must simulated a saved-name situation.
597          */
598         bzero(&cnp, sizeof(cnp));
599         cnp.cn_nameiop = NAMEI_CREATE;
600         cnp.cn_flags = CNP_LOCKPARENT;
601         cnp.cn_nameptr = ncp->nc_name;
602         cnp.cn_namelen = ncp->nc_nlen;
603         cnp.cn_cred = ap->a_cred;
604         cnp.cn_td = td;
605
606         tvp = NULL;
607         error = vop_old_lookup(ap->a_head.a_ops, dvp, &tvp, &cnp);
608
609         /*
610          * EJUSTRETURN should be returned for this case, which means that
611          * the VFS has setup the directory inode for the create.  The dvp we
612          * passed in is expected to remain in a locked state.
613          *
614          * If the VOP_OLD_LINK is successful we are responsible for updating
615          * the cache state of the locked ncp that was passed to us.
616          */
617         if (error == EJUSTRETURN) {
618                 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
619                 error = VOP_OLD_LINK(dvp, ap->a_vp, &cnp);
620                 if (error == 0) {
621                         cache_setunresolved(ncp);
622                         cache_setvp(ncp, ap->a_vp);
623                 }
624         } else {
625                 if (error == 0) {
626                         vput(tvp);
627                         error = EEXIST;
628                 }
629         }
630         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
631                 VOP_UNLOCK(dvp, 0, td);
632         vrele(dvp);
633         return (error);
634 }
635
636 int
637 vop_compat_nsymlink(struct vop_nsymlink_args *ap)
638 {
639         struct thread *td = curthread;
640         struct componentname cnp;
641         struct namecache *ncp;
642         struct vnode *dvp;
643         struct vnode *vp;
644         int error;
645
646         /*
647          * Sanity checks, get a locked directory vnode.
648          */
649         *ap->a_vpp = NULL;
650         ncp = ap->a_ncp;                /* locked namecache node */
651         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
652                 return(EPERM);
653         if (ncp->nc_parent == NULL)
654                 return(EPERM);
655         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
656                 return(EPERM);
657
658         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
659                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
660                         ncp, ncp->nc_name);
661                 return(EAGAIN);
662         }
663
664         /*
665          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
666          * caches all information required to create the entry in the
667          * directory inode.  We expect a return code of EJUSTRETURN for
668          * the CREATE case.  The cnp must simulated a saved-name situation.
669          */
670         bzero(&cnp, sizeof(cnp));
671         cnp.cn_nameiop = NAMEI_CREATE;
672         cnp.cn_flags = CNP_LOCKPARENT;
673         cnp.cn_nameptr = ncp->nc_name;
674         cnp.cn_namelen = ncp->nc_nlen;
675         cnp.cn_cred = ap->a_cred;
676         cnp.cn_td = td;
677
678         vp = NULL;
679         error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
680
681         /*
682          * EJUSTRETURN should be returned for this case, which means that
683          * the VFS has setup the directory inode for the create.  The dvp we
684          * passed in is expected to remain in a locked state.
685          *
686          * If the VOP_OLD_SYMLINK is successful we are responsible for updating
687          * the cache state of the locked ncp that was passed to us.
688          */
689         if (error == EJUSTRETURN) {
690                 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
691                 error = VOP_OLD_SYMLINK(dvp, &vp, &cnp, ap->a_vap, ap->a_target);
692                 if (error == 0) {
693                         cache_setunresolved(ncp);
694                         cache_setvp(ncp, vp);
695                         *ap->a_vpp = vp;
696                 }
697         } else {
698                 if (error == 0) {
699                         vput(vp);
700                         vp = NULL;
701                         error = EEXIST;
702                 }
703                 KKASSERT(vp == NULL);
704         }
705         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
706                 VOP_UNLOCK(dvp, 0, td);
707         vrele(dvp);
708         return (error);
709 }
710
711 /*
712  * vop_compat_nwhiteout { struct namecache *a_ncp,      XXX STOPGAP FUNCTION
713  *                        struct ucred *a_cred,
714  *                        int a_flags }
715  *
716  * Issie a whiteout operation (create, lookup, or delete).  Compatibility 
717  * requires us to issue the appropriate VOP_OLD_LOOKUP before we issue 
718  * VOP_OLD_WHITEOUT in order to setup the directory inode's i_offset and i_count
719  * (e.g. in UFS) for the NAMEI_CREATE and NAMEI_DELETE ops.  For NAMEI_LOOKUP
720  * no lookup is necessary.
721  */
722 int
723 vop_compat_nwhiteout(struct vop_nwhiteout_args *ap)
724 {
725         struct thread *td = curthread;
726         struct componentname cnp;
727         struct namecache *ncp;
728         struct vnode *dvp;
729         struct vnode *vp;
730         int error;
731
732         /*
733          * Sanity checks, get a locked directory vnode.
734          */
735         ncp = ap->a_ncp;                /* locked namecache node */
736         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
737                 return(EPERM);
738         if (ncp->nc_parent == NULL)
739                 return(EPERM);
740         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
741                 return(EPERM);
742
743         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
744                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
745                         ncp, ncp->nc_name);
746                 return(EAGAIN);
747         }
748
749         /*
750          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
751          * caches all information required to create the entry in the
752          * directory inode.  We expect a return code of EJUSTRETURN for
753          * the CREATE case.  The cnp must simulated a saved-name situation.
754          */
755         bzero(&cnp, sizeof(cnp));
756         cnp.cn_nameiop = ap->a_flags;
757         cnp.cn_flags = CNP_LOCKPARENT;
758         cnp.cn_nameptr = ncp->nc_name;
759         cnp.cn_namelen = ncp->nc_nlen;
760         cnp.cn_cred = ap->a_cred;
761         cnp.cn_td = td;
762
763         vp = NULL;
764
765         /*
766          * EJUSTRETURN should be returned for the CREATE or DELETE cases.
767          * The VFS has setup the directory inode for the create.  The dvp we
768          * passed in is expected to remain in a locked state.
769          *
770          * If the VOP_OLD_WHITEOUT is successful we are responsible for updating
771          * the cache state of the locked ncp that was passed to us.
772          */
773         switch(ap->a_flags) {
774         case NAMEI_DELETE:
775                 cnp.cn_flags |= CNP_DOWHITEOUT;
776                 /* fall through */
777         case NAMEI_CREATE:
778                 error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
779                 if (error == EJUSTRETURN) {
780                         KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
781                         error = VOP_OLD_WHITEOUT(dvp, &cnp, ap->a_flags);
782                         if (error == 0)
783                                 cache_setunresolved(ncp);
784                 } else {
785                         if (error == 0) {
786                                 vput(vp);
787                                 vp = NULL;
788                                 error = EEXIST;
789                         }
790                         KKASSERT(vp == NULL);
791                 }
792                 break;
793         case NAMEI_LOOKUP:
794                 error = VOP_OLD_WHITEOUT(dvp, NULL, ap->a_flags);
795                 break;
796         default:
797                 error = EINVAL;
798                 break;
799         }
800         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
801                 VOP_UNLOCK(dvp, 0, td);
802         vrele(dvp);
803         return (error);
804 }
805
806
807 /*
808  * vop_compat_nremove { struct namecache *a_ncp,        XXX STOPGAP FUNCTION
809  *                        struct ucred *a_cred }
810  */
811 int
812 vop_compat_nremove(struct vop_nremove_args *ap)
813 {
814         struct thread *td = curthread;
815         struct componentname cnp;
816         struct namecache *ncp;
817         struct vnode *dvp;
818         struct vnode *vp;
819         int error;
820
821         /*
822          * Sanity checks, get a locked directory vnode.
823          */
824         ncp = ap->a_ncp;                /* locked namecache node */
825         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
826                 return(EPERM);
827         if (ncp->nc_parent == NULL)
828                 return(EPERM);
829         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
830                 return(EPERM);
831
832         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
833                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
834                         ncp, ncp->nc_name);
835                 return(EAGAIN);
836         }
837
838         /*
839          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
840          * caches all information required to delete the entry in the
841          * directory inode.  We expect a return code of 0 for the DELETE
842          * case (meaning that a vp has been found).  The cnp must simulated
843          * a saved-name situation.
844          */
845         bzero(&cnp, sizeof(cnp));
846         cnp.cn_nameiop = NAMEI_DELETE;
847         cnp.cn_flags = CNP_LOCKPARENT;
848         cnp.cn_nameptr = ncp->nc_name;
849         cnp.cn_namelen = ncp->nc_nlen;
850         cnp.cn_cred = ap->a_cred;
851         cnp.cn_td = td;
852
853         /*
854          * The vnode must be a directory and must not represent the
855          * current directory.
856          */
857         vp = NULL;
858         error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
859         if (error == 0 && vp->v_type == VDIR)
860                 error = EPERM;
861         if (error == 0) {
862                 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
863                 error = VOP_OLD_REMOVE(dvp, vp, &cnp);
864                 if (error == 0) {
865                         cache_setunresolved(ncp);
866                         cache_setvp(ncp, NULL);
867                 }
868         }
869         if (vp) {
870                 if (dvp == vp)
871                         vrele(vp);
872                 else    
873                         vput(vp);
874         }
875         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
876                 VOP_UNLOCK(dvp, 0, td);
877         vrele(dvp);
878         return (error);
879 }
880
881 /*
882  * vop_compat_nrmdir { struct namecache *a_ncp,         XXX STOPGAP FUNCTION
883  *                        struct ucred *a_cred }
884  */
885 int
886 vop_compat_nrmdir(struct vop_nrmdir_args *ap)
887 {
888         struct thread *td = curthread;
889         struct componentname cnp;
890         struct namecache *ncp;
891         struct vnode *dvp;
892         struct vnode *vp;
893         int error;
894
895         /*
896          * Sanity checks, get a locked directory vnode.
897          */
898         ncp = ap->a_ncp;                /* locked namecache node */
899         if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
900                 return(EPERM);
901         if (ncp->nc_parent == NULL)
902                 return(EPERM);
903         if ((dvp = ncp->nc_parent->nc_vp) == NULL)
904                 return(EPERM);
905
906         if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) {
907                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
908                         ncp, ncp->nc_name);
909                 return(EAGAIN);
910         }
911
912         /*
913          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
914          * caches all information required to delete the entry in the
915          * directory inode.  We expect a return code of 0 for the DELETE
916          * case (meaning that a vp has been found).  The cnp must simulated
917          * a saved-name situation.
918          */
919         bzero(&cnp, sizeof(cnp));
920         cnp.cn_nameiop = NAMEI_DELETE;
921         cnp.cn_flags = CNP_LOCKPARENT;
922         cnp.cn_nameptr = ncp->nc_name;
923         cnp.cn_namelen = ncp->nc_nlen;
924         cnp.cn_cred = ap->a_cred;
925         cnp.cn_td = td;
926
927         /*
928          * The vnode must be a directory and must not represent the
929          * current directory.
930          */
931         vp = NULL;
932         error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
933         if (error == 0 && vp->v_type != VDIR)
934                 error = ENOTDIR;
935         if (error == 0 && vp == dvp)
936                 error = EINVAL;
937         if (error == 0 && (vp->v_flag & VROOT))
938                 error = EBUSY;
939         if (error == 0) {
940                 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
941                 error = VOP_OLD_RMDIR(dvp, vp, &cnp);
942
943                 /*
944                  * Note that this invalidation will cause any process
945                  * currently CD'd into the directory being removed to be
946                  * disconnected from the topology and not be able to ".."
947                  * back out.
948                  */
949                 if (error == 0)
950                         cache_inval(ncp, CINV_DESTROY);
951         }
952         if (vp) {
953                 if (dvp == vp)
954                         vrele(vp);
955                 else    
956                         vput(vp);
957         }
958         if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
959                 VOP_UNLOCK(dvp, 0, td);
960         vrele(dvp);
961         return (error);
962 }
963
964 /*
965  * vop_compat_nrename { struct namecache *a_fncp,       XXX STOPGAP FUNCTION
966  *                      struct namecache *a_tncp,
967  *                      struct ucred *a_cred }
968  *
969  * This is a fairly difficult procedure.  The old VOP_OLD_RENAME requires that
970  * the source directory and vnode be unlocked and the target directory and
971  * vnode (if it exists) be locked.  All arguments will be vrele'd and 
972  * the targets will also be unlocked regardless of the return code.
973  */
974 int
975 vop_compat_nrename(struct vop_nrename_args *ap)
976 {
977         struct thread *td = curthread;
978         struct componentname fcnp;
979         struct componentname tcnp;
980         struct namecache *fncp;
981         struct namecache *tncp;
982         struct vnode *fdvp, *fvp;
983         struct vnode *tdvp, *tvp;
984         int error;
985
986         /*
987          * Sanity checks, get referenced vnodes representing the source.
988          */
989         fncp = ap->a_fncp;              /* locked namecache node */
990         if (fncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
991                 return(EPERM);
992         if (fncp->nc_parent == NULL)
993                 return(EPERM);
994         if ((fdvp = fncp->nc_parent->nc_vp) == NULL)
995                 return(EPERM);
996
997         /*
998          * Temporarily lock the source directory and lookup in DELETE mode to
999          * check permissions.  XXX delete permissions should have been
1000          * checked by nlookup(), we need to add NLC_DELETE for delete
1001          * checking.  It is unclear whether VFS's require the directory setup
1002          * info NAMEI_DELETE causes to be stored in the fdvp's inode, but
1003          * since it isn't locked and since UFS always does a relookup of
1004          * the source, it is believed that the only side effect that matters
1005          * is the permissions check.
1006          */
1007         if ((error = vget(fdvp, LK_EXCLUSIVE, td)) != 0) {
1008                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
1009                         fncp, fncp->nc_name);
1010                 return(EAGAIN);
1011         }
1012
1013         bzero(&fcnp, sizeof(fcnp));
1014         fcnp.cn_nameiop = NAMEI_DELETE;
1015         fcnp.cn_flags = CNP_LOCKPARENT;
1016         fcnp.cn_nameptr = fncp->nc_name;
1017         fcnp.cn_namelen = fncp->nc_nlen;
1018         fcnp.cn_cred = ap->a_cred;
1019         fcnp.cn_td = td;
1020
1021         /*
1022          * note: vop_old_lookup (i.e. VOP_OLD_LOOKUP) always returns a locked
1023          * fvp.
1024          */
1025         fvp = NULL;
1026         error = vop_old_lookup(ap->a_head.a_ops, fdvp, &fvp, &fcnp);
1027         if (error == 0 && (fvp->v_flag & VROOT)) {
1028                 vput(fvp);      /* as if vop_old_lookup had failed */
1029                 error = EBUSY;
1030         }
1031         if ((fcnp.cn_flags & CNP_PDIRUNLOCK) == 0) {
1032                 fcnp.cn_flags |= CNP_PDIRUNLOCK;
1033                 VOP_UNLOCK(fdvp, 0, td);
1034         }
1035         if (error) {
1036                 vrele(fdvp);
1037                 return (error);
1038         }
1039         VOP_UNLOCK(fvp, 0, td);
1040
1041         /*
1042          * fdvp and fvp are now referenced and unlocked.
1043          *
1044          * Get a locked directory vnode for the target and lookup the target
1045          * in CREATE mode so it places the required information in the
1046          * directory inode.
1047          */
1048         tncp = ap->a_tncp;              /* locked namecache node */
1049         if (tncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */
1050                 error = EPERM;
1051         if (tncp->nc_parent == NULL)
1052                 error = EPERM;
1053         if ((tdvp = tncp->nc_parent->nc_vp) == NULL)
1054                 error = EPERM;
1055         if (error) {
1056                 vrele(fdvp);
1057                 vrele(fvp);
1058                 return (error);
1059         }
1060         if ((error = vget(tdvp, LK_EXCLUSIVE, td)) != 0) {
1061                 printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
1062                         tncp, tncp->nc_name);
1063                 vrele(fdvp);
1064                 vrele(fvp);
1065                 return(EAGAIN);
1066         }
1067
1068         /*
1069          * Setup the cnp for a traditional vop_old_lookup() call.  The lookup
1070          * caches all information required to create the entry in the
1071          * target directory inode.
1072          */
1073         bzero(&tcnp, sizeof(tcnp));
1074         tcnp.cn_nameiop = NAMEI_RENAME;
1075         tcnp.cn_flags = CNP_LOCKPARENT;
1076         tcnp.cn_nameptr = tncp->nc_name;
1077         tcnp.cn_namelen = tncp->nc_nlen;
1078         tcnp.cn_cred = ap->a_cred;
1079         tcnp.cn_td = td;
1080
1081         tvp = NULL;
1082         error = vop_old_lookup(ap->a_head.a_ops, tdvp, &tvp, &tcnp);
1083
1084         if (error == EJUSTRETURN) {
1085                 /*
1086                  * Target does not exist.  tvp should be NULL.
1087                  */
1088                 KKASSERT(tvp == NULL);
1089                 KKASSERT((tcnp.cn_flags & CNP_PDIRUNLOCK) == 0);
1090                 error = VOP_OLD_RENAME(fdvp, fvp, &fcnp, tdvp, tvp, &tcnp);
1091                 if (error == 0) {
1092                         cache_rename(fncp, tncp);
1093                         cache_setvp(tncp, fvp);
1094                 }
1095         } else if (error == 0) {
1096                 /*
1097                  * Target exists.  VOP_OLD_RENAME should correctly delete the
1098                  * target.
1099                  */
1100                 KKASSERT((tcnp.cn_flags & CNP_PDIRUNLOCK) == 0);
1101                 error = VOP_OLD_RENAME(fdvp, fvp, &fcnp, tdvp, tvp, &tcnp);
1102                 if (error == 0) {
1103                         cache_rename(fncp, tncp);
1104                         cache_setvp(tncp, fvp);
1105                 }
1106         } else {
1107                 vrele(fdvp);
1108                 vrele(fvp);
1109                 if (tcnp.cn_flags & CNP_PDIRUNLOCK)
1110                         vrele(tdvp);
1111                 else
1112                         vput(tdvp);
1113         }
1114         return (error);
1115 }
1116
1117 static int
1118 vop_nolookup(ap)
1119         struct vop_old_lookup_args /* {
1120                 struct vnode *a_dvp;
1121                 struct vnode **a_vpp;
1122                 struct componentname *a_cnp;
1123         } */ *ap;
1124 {
1125
1126         *ap->a_vpp = NULL;
1127         return (ENOTDIR);
1128 }
1129
1130 /*
1131  *      vop_nostrategy:
1132  *
1133  *      Strategy routine for VFS devices that have none.
1134  *
1135  *      B_ERROR and B_INVAL must be cleared prior to calling any strategy
1136  *      routine.  Typically this is done for a BUF_CMD_READ strategy call.
1137  *      Typically B_INVAL is assumed to already be clear prior to a write
1138  *      and should not be cleared manually unless you just made the buffer
1139  *      invalid.  B_ERROR should be cleared either way.
1140  */
1141
1142 static int
1143 vop_nostrategy (struct vop_strategy_args *ap)
1144 {
1145         printf("No strategy for buffer at %p\n", ap->a_bio->bio_buf);
1146         vprint("", ap->a_vp);
1147         ap->a_bio->bio_buf->b_flags |= B_ERROR;
1148         ap->a_bio->bio_buf->b_error = EOPNOTSUPP;
1149         biodone(ap->a_bio);
1150         return (EOPNOTSUPP);
1151 }
1152
1153 int
1154 vop_stdpathconf(ap)
1155         struct vop_pathconf_args /* {
1156         struct vnode *a_vp;
1157         int a_name;
1158         int *a_retval;
1159         } */ *ap;
1160 {
1161
1162         switch (ap->a_name) {
1163                 case _PC_LINK_MAX:
1164                         *ap->a_retval = LINK_MAX;
1165                         return (0);
1166                 case _PC_MAX_CANON:
1167                         *ap->a_retval = MAX_CANON;
1168                         return (0);
1169                 case _PC_MAX_INPUT:
1170                         *ap->a_retval = MAX_INPUT;
1171                         return (0);
1172                 case _PC_PIPE_BUF:
1173                         *ap->a_retval = PIPE_BUF;
1174                         return (0);
1175                 case _PC_CHOWN_RESTRICTED:
1176                         *ap->a_retval = 1;
1177                         return (0);
1178                 case _PC_VDISABLE:
1179                         *ap->a_retval = _POSIX_VDISABLE;
1180                         return (0);
1181                 default:
1182                         return (EINVAL);
1183         }
1184         /* NOTREACHED */
1185 }
1186
1187 /*
1188  * Standard open.
1189  *
1190  * (struct vnode *a_vp, int a_mode, struct ucred *a_ucred, struct file *a_fp,
1191  *  struct thread *a_td)
1192  *
1193  * a_mode: note, 'F' modes, e.g. FREAD, FWRITE
1194  */
1195 int
1196 vop_stdopen(struct vop_open_args *ap)
1197 {
1198         struct vnode *vp = ap->a_vp;
1199         struct file *fp;
1200
1201         if ((fp = ap->a_fp) != NULL) {
1202                 switch(vp->v_type) {
1203                 case VFIFO:
1204                         fp->f_type = DTYPE_FIFO;
1205                         break;
1206                 default:
1207                         fp->f_type = DTYPE_VNODE;
1208                         break;
1209                 }
1210                 fp->f_flag = ap->a_mode & FMASK;
1211                 fp->f_ops = &vnode_fileops;
1212                 fp->f_data = vp;
1213                 vref(vp);
1214         }
1215         if (ap->a_mode & FWRITE)
1216                 ++vp->v_writecount;
1217         KKASSERT(vp->v_opencount >= 0 && vp->v_opencount != INT_MAX);
1218         ++vp->v_opencount;
1219         return (0);
1220 }
1221
1222 /*
1223  * Standard close.
1224  *
1225  * (struct vnode *a_vp, int a_fflag, struct thread *a_td)
1226  *
1227  * a_fflag: note, 'F' modes, e.g. FREAD, FWRITE.  same as a_mode in stdopen?
1228  */
1229 int
1230 vop_stdclose(struct vop_close_args *ap)
1231 {
1232         struct vnode *vp = ap->a_vp;
1233
1234         KASSERT(vp->v_opencount > 0,
1235                 ("VOP_STDCLOSE: BAD OPENCOUNT %p %d\n", vp, vp->v_opencount));
1236         if (ap->a_fflag & FWRITE) {
1237                 KASSERT(vp->v_writecount > 0,
1238                         ("VOP_STDCLOSE: BAD WRITECOUNT %p %d\n", 
1239                         vp, vp->v_writecount));
1240                 --vp->v_writecount;
1241         }
1242         --vp->v_opencount;
1243         return (0);
1244 }
1245
1246 /*
1247  * Standard lock.  The lock is recursive-capable only if the lock was
1248  * initialized with LK_CANRECURSE or that flag is passed in a_flags.
1249  */
1250 int
1251 vop_stdlock(ap)
1252         struct vop_lock_args /* {
1253                 struct vnode *a_vp;
1254                 int a_flags;
1255                 struct proc *a_p;
1256         } */ *ap;
1257 {               
1258         int error;
1259
1260 #ifndef DEBUG_LOCKS
1261         error = lockmgr(&ap->a_vp->v_lock, ap->a_flags, ap->a_td);
1262 #else
1263         error = debuglockmgr(&ap->a_vp->v_lock, ap->a_flags, ap->a_td,
1264                         "vop_stdlock", ap->a_vp->filename, ap->a_vp->line);
1265 #endif
1266         return(error);
1267 }
1268
1269 int
1270 vop_stdunlock(ap)
1271         struct vop_unlock_args /* {
1272                 struct vnode *a_vp;
1273                 int a_flags;
1274                 struct thread *a_td;
1275         } */ *ap;
1276 {
1277         int error;
1278
1279         error = lockmgr(&ap->a_vp->v_lock, ap->a_flags | LK_RELEASE, ap->a_td);
1280         return(error);
1281 }
1282
1283 int
1284 vop_stdislocked(ap)
1285         struct vop_islocked_args /* {
1286                 struct vnode *a_vp;
1287                 struct thread *a_td;
1288         } */ *ap;
1289 {
1290         return (lockstatus(&ap->a_vp->v_lock, ap->a_td));
1291 }
1292
1293 /*
1294  * Return true for select/poll.
1295  */
1296 int
1297 vop_nopoll(ap)
1298         struct vop_poll_args /* {
1299                 struct vnode *a_vp;
1300                 int  a_events;
1301                 struct ucred *a_cred;
1302                 struct proc *a_p;
1303         } */ *ap;
1304 {
1305         /*
1306          * Return true for read/write.  If the user asked for something
1307          * special, return POLLNVAL, so that clients have a way of
1308          * determining reliably whether or not the extended
1309          * functionality is present without hard-coding knowledge
1310          * of specific filesystem implementations.
1311          */
1312         if (ap->a_events & ~POLLSTANDARD)
1313                 return (POLLNVAL);
1314
1315         return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
1316 }
1317
1318 /*
1319  * Implement poll for local filesystems that support it.
1320  */
1321 int
1322 vop_stdpoll(ap)
1323         struct vop_poll_args /* {
1324                 struct vnode *a_vp;
1325                 int  a_events;
1326                 struct ucred *a_cred;
1327                 struct thread *a_td;
1328         } */ *ap;
1329 {
1330         if (ap->a_events & ~POLLSTANDARD)
1331                 return (vn_pollrecord(ap->a_vp, ap->a_td, ap->a_events));
1332         return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
1333 }
1334
1335 /* 
1336  * vfs default ops
1337  * used to fill the vfs fucntion table to get reasonable default return values.
1338  */
1339 int 
1340 vfs_stdmount(struct mount *mp, char *path, caddr_t data, struct thread *td)
1341 {
1342         return (0);
1343 }
1344
1345 int     
1346 vfs_stdunmount(struct mount *mp, int mntflags, struct thread *td)
1347 {
1348         return (0);
1349 }
1350
1351 int     
1352 vfs_stdroot(struct mount *mp, struct vnode **vpp)
1353 {
1354         return (EOPNOTSUPP);
1355 }
1356
1357 int     
1358 vfs_stdstatfs(struct mount *mp, struct statfs *sbp, struct thread *td)
1359 {
1360         return (EOPNOTSUPP);
1361 }
1362
1363 int
1364 vfs_stdvptofh(struct vnode *vp, struct fid *fhp)
1365 {
1366         return (EOPNOTSUPP);
1367 }
1368
1369 int     
1370 vfs_stdstart(struct mount *mp, int flags, struct thread *td)
1371 {
1372         return (0);
1373 }
1374
1375 int     
1376 vfs_stdquotactl(struct mount *mp, int cmds, uid_t uid,
1377         caddr_t arg, struct thread *td)
1378 {
1379         return (EOPNOTSUPP);
1380 }
1381
1382 int     
1383 vfs_stdsync(struct mount *mp, int waitfor, struct thread *td)
1384 {
1385         return (0);
1386 }
1387
1388 int
1389 vfs_stdnosync(struct mount *mp, int waitfor, struct thread *td)
1390 {
1391         return (EOPNOTSUPP);
1392 }
1393
1394 int     
1395 vfs_stdvget(struct mount *mp, ino_t ino, struct vnode **vpp)
1396 {
1397         return (EOPNOTSUPP);
1398 }
1399
1400 int     
1401 vfs_stdfhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1402 {
1403         return (EOPNOTSUPP);
1404 }
1405
1406 int 
1407 vfs_stdcheckexp(struct mount *mp, struct sockaddr *nam, int *extflagsp,
1408         struct ucred **credanonp)
1409 {
1410         return (EOPNOTSUPP);
1411 }
1412
1413 int
1414 vfs_stdinit(struct vfsconf *vfsp)
1415 {
1416         return (0);
1417 }
1418
1419 int
1420 vfs_stduninit(struct vfsconf *vfsp)
1421 {
1422         return(0);
1423 }
1424
1425 int
1426 vfs_stdextattrctl(struct mount *mp, int cmd, const char *attrname,
1427         caddr_t arg, struct thread *td)
1428 {
1429         return(EOPNOTSUPP);
1430 }
1431
1432 /* end of vfs default ops */