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