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. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
36 * $FreeBSD: src/sys/kern/vfs_default.c,v 1.28.2.7 2003/01/10 18:23:26 bde Exp $
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/buf.h>
42 #include <sys/conf.h>
43 #include <sys/fcntl.h>
44 #include <sys/file.h>
45 #include <sys/kernel.h>
46 #include <sys/lock.h>
47 #include <sys/malloc.h>
48 #include <sys/mount.h>
49 #include <sys/unistd.h>
50 #include <sys/vnode.h>
51 #include <sys/namei.h>
52 #include <sys/nlookup.h>
53 #include <sys/mountctl.h>
54 #include <sys/vfs_quota.h>
55
56 #include <machine/limits.h>
57
58 #include <vm/vm.h>
59 #include <vm/vm_object.h>
60 #include <vm/vm_page.h>
61 #include <vm/vm_pager.h>
62 #include <vm/vnode_pager.h>
63
64 static int vop_nolookup (struct vop_old_lookup_args *);
65 static int vop_nostrategy (struct vop_strategy_args *);
66
67 /*
68 * This vnode table stores what we want to do if the filesystem doesn't
69 * implement a particular VOP.
70 *
71 * If there is no specific entry here, we will return EOPNOTSUPP.
72 */
73 struct vop_ops default_vnode_vops = {
74 .vop_default = vop_eopnotsupp,
75 .vop_advlock = (void *)vop_einval,
76 .vop_fsync = (void *)vop_null,
77 .vop_ioctl = (void *)vop_enotty,
78 .vop_mmap = (void *)vop_einval,
79 .vop_old_lookup = vop_nolookup,
80 .vop_open = vop_stdopen,
81 .vop_close = vop_stdclose,
82 .vop_pathconf = vop_stdpathconf,
83 .vop_readlink = (void *)vop_einval,
84 .vop_reallocblks = (void *)vop_eopnotsupp,
85 .vop_strategy = vop_nostrategy,
86 .vop_getacl = (void *)vop_eopnotsupp,
87 .vop_setacl = (void *)vop_eopnotsupp,
88 .vop_aclcheck = (void *)vop_eopnotsupp,
89 .vop_getextattr = (void *)vop_eopnotsupp,
90 .vop_setextattr = (void *)vop_eopnotsupp,
91 .vop_markatime = vop_stdmarkatime,
92 .vop_nresolve = vop_compat_nresolve,
93 .vop_nlookupdotdot = vop_compat_nlookupdotdot,
94 .vop_ncreate = vop_compat_ncreate,
95 .vop_nmkdir = vop_compat_nmkdir,
96 .vop_nmknod = vop_compat_nmknod,
97 .vop_nlink = vop_compat_nlink,
98 .vop_nsymlink = vop_compat_nsymlink,
99 .vop_nwhiteout = vop_compat_nwhiteout,
100 .vop_nremove = vop_compat_nremove,
101 .vop_nrmdir = vop_compat_nrmdir,
102 .vop_nrename = vop_compat_nrename,
103 .vop_mountctl = vop_stdmountctl
104 };
105
106 VNODEOP_SET(default_vnode_vops);
107
108 int
109 vop_eopnotsupp(struct vop_generic_args *ap)
110 {
111 return (EOPNOTSUPP);
112 }
113
114 int
115 vop_ebadf(struct vop_generic_args *ap)
116 {
117 return (EBADF);
118 }
119
120 int
121 vop_enotty(struct vop_generic_args *ap)
122 {
123 return (ENOTTY);
124 }
125
126 int
127 vop_einval(struct vop_generic_args *ap)
128 {
129 return (EINVAL);
130 }
131
132 int
133 vop_stdmarkatime(struct vop_markatime_args *ap)
134 {
135 return (EOPNOTSUPP);
136 }
137
138 int
139 vop_null(struct vop_generic_args *ap)
140 {
141 return (0);
142 }
143
144 int
145 vop_defaultop(struct vop_generic_args *ap)
146 {
147 return (VOCALL(&default_vnode_vops, ap));
148 }
149
150 int
151 vop_panic(struct vop_generic_args *ap)
152 {
153 panic("filesystem goof: vop_panic[%s]", ap->a_desc->sd_name);
154 }
155
156 /*
157 * vop_compat_resolve { struct nchandle *a_nch, struct vnode *dvp }
158 * XXX STOPGAP FUNCTION
159 *
160 * XXX OLD API ROUTINE! WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE
161 * WILL BE REMOVED. This procedure exists for all VFSs which have not
162 * yet implemented VOP_NRESOLVE(). It converts VOP_NRESOLVE() into a
163 * vop_old_lookup() and does appropriate translations.
164 *
165 * Resolve a ncp for VFSs which do not support the VOP. Eventually all
166 * VFSs will support this VOP and this routine can be removed, since
167 * VOP_NRESOLVE() is far less complex then the older LOOKUP/CACHEDLOOKUP
168 * API.
169 *
170 * A locked ncp is passed in to be resolved. The NCP is resolved by
171 * figuring out the vnode (if any) and calling cache_setvp() to attach the
172 * vnode to the entry. If the entry represents a non-existant node then
173 * cache_setvp() is called with a NULL vnode to resolve the entry into a
174 * negative cache entry. No vnode locks are retained and the
175 * ncp is left locked on return.
176 *
177 * The ncp will NEVER represent "", "." or "..", or contain any slashes.
178 *
179 * There is a potential directory and vnode interlock. The lock order
180 * requirement is: namecache, governing directory, resolved vnode.
181 */
182 int
183 vop_compat_nresolve(struct vop_nresolve_args *ap)
184 {
185 int error;
186 struct vnode *dvp;
187 struct vnode *vp;
188 struct nchandle *nch;
189 struct namecache *ncp;
190 struct componentname cnp;
191
192 nch = ap->a_nch; /* locked namecache node */
193 ncp = nch->ncp;
194 dvp = ap->a_dvp;
195
196 /*
197 * UFS currently stores all sorts of side effects, including a loop
198 * variable, in the directory inode. That needs to be fixed and the
199 * other VFS's audited before we can switch to LK_SHARED.
200 */
201 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
202 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
203 ncp, ncp->nc_name);
204 return(EAGAIN);
205 }
206
207 bzero(&cnp, sizeof(cnp));
208 cnp.cn_nameiop = NAMEI_LOOKUP;
209 cnp.cn_flags = 0;
210 cnp.cn_nameptr = ncp->nc_name;
211 cnp.cn_namelen = ncp->nc_nlen;
212 cnp.cn_cred = ap->a_cred;
213 cnp.cn_td = curthread; /* XXX */
214
215 /*
216 * vop_old_lookup() always returns vp locked. dvp may or may not be
217 * left locked depending on CNP_PDIRUNLOCK.
218 */
219 error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
220 if (error == 0)
221 vn_unlock(vp);
222 if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
223 vn_unlock(dvp);
224 if ((ncp->nc_flag & NCF_UNRESOLVED) == 0) {
225 /* was resolved by another process while we were unlocked */
226 if (error == 0)
227 vrele(vp);
228 } else if (error == 0) {
229 KKASSERT(vp != NULL);
230 cache_setvp(nch, vp);
231 vrele(vp);
232 } else if (error == ENOENT) {
233 KKASSERT(vp == NULL);
234 if (cnp.cn_flags & CNP_ISWHITEOUT)
235 ncp->nc_flag |= NCF_WHITEOUT;
236 cache_setvp(nch, NULL);
237 }
238 vrele(dvp);
239 return (error);
240 }
241
242 /*
243 * vop_compat_nlookupdotdot { struct vnode *a_dvp,
244 * struct vnode **a_vpp,
245 * struct ucred *a_cred }
246 *
247 * Lookup the vnode representing the parent directory of the specified
248 * directory vnode. a_dvp should not be locked. If no error occurs *a_vpp
249 * will contained the parent vnode, locked and refd, else *a_vpp will be NULL.
250 *
251 * This function is designed to aid NFS server-side operations and is
252 * used by cache_fromdvp() to create a consistent, connected namecache
253 * topology.
254 *
255 * As part of the NEW API work, VFSs will first split their CNP_ISDOTDOT
256 * code out from their *_lookup() and create *_nlookupdotdot(). Then as time
257 * permits VFSs will implement the remaining *_n*() calls and finally get
258 * rid of their *_lookup() call.
259 */
260 int
261 vop_compat_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
262 {
263 struct componentname cnp;
264 int error;
265
266 /*
267 * UFS currently stores all sorts of side effects, including a loop
268 * variable, in the directory inode. That needs to be fixed and the
269 * other VFS's audited before we can switch to LK_SHARED.
270 */
271 *ap->a_vpp = NULL;
272 if ((error = vget(ap->a_dvp, LK_EXCLUSIVE)) != 0)
273 return (error);
274 if (ap->a_dvp->v_type != VDIR) {
275 vput(ap->a_dvp);
276 return (ENOTDIR);
277 }
278
279 bzero(&cnp, sizeof(cnp));
280 cnp.cn_nameiop = NAMEI_LOOKUP;
281 cnp.cn_flags = CNP_ISDOTDOT;
282 cnp.cn_nameptr = "..";
283 cnp.cn_namelen = 2;
284 cnp.cn_cred = ap->a_cred;
285 cnp.cn_td = curthread; /* XXX */
286
287 /*
288 * vop_old_lookup() always returns vp locked. dvp may or may not be
289 * left locked depending on CNP_PDIRUNLOCK.
290 *
291 * (*vpp) will be returned locked if no error occured, which is the
292 * state we want.
293 */
294 error = vop_old_lookup(ap->a_head.a_ops, ap->a_dvp, ap->a_vpp, &cnp);
295 if (cnp.cn_flags & CNP_PDIRUNLOCK)
296 vrele(ap->a_dvp);
297 else
298 vput(ap->a_dvp);
299 return (error);
300 }
301
302 /*
303 * vop_compat_ncreate { struct nchandle *a_nch, XXX STOPGAP FUNCTION
304 * struct vnode *a_dvp,
305 * struct vnode **a_vpp,
306 * struct ucred *a_cred,
307 * struct vattr *a_vap }
308 *
309 * Create a file as specified by a_vap. Compatibility requires us to issue
310 * the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_CREATE in order
311 * to setup the directory inode's i_offset and i_count (e.g. in UFS).
312 */
313 int
314 vop_compat_ncreate(struct vop_ncreate_args *ap)
315 {
316 struct thread *td = curthread;
317 struct componentname cnp;
318 struct nchandle *nch;
319 struct namecache *ncp;
320 struct vnode *dvp;
321 int error;
322
323 /*
324 * Sanity checks, get a locked directory vnode.
325 */
326 nch = ap->a_nch; /* locked namecache node */
327 dvp = ap->a_dvp;
328 ncp = nch->ncp;
329
330 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
331 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
332 ncp, ncp->nc_name);
333 return(EAGAIN);
334 }
335
336 /*
337 * Setup the cnp for a traditional vop_old_lookup() call. The lookup
338 * caches all information required to create the entry in the
339 * directory inode. We expect a return code of EJUSTRETURN for
340 * the CREATE case. The cnp must simulated a saved-name situation.
341 */
342 bzero(&cnp, sizeof(cnp));
343 cnp.cn_nameiop = NAMEI_CREATE;
344 cnp.cn_flags = CNP_LOCKPARENT;
345 cnp.cn_nameptr = ncp->nc_name;
346 cnp.cn_namelen = ncp->nc_nlen;
347 cnp.cn_cred = ap->a_cred;
348 cnp.cn_td = td;
349 *ap->a_vpp = NULL;
350
351 error = vop_old_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
352
353 /*
354 * EJUSTRETURN should be returned for this case, which means that
355 * the VFS has setup the directory inode for the create. The dvp we
356 * passed in is expected to remain in a locked state.
357 *
358 * If the VOP_OLD_CREATE is successful we are responsible for updating
359 * the cache state of the locked ncp that was passed to us.
360 */
361 if (error == EJUSTRETURN) {
362 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
363 error = VOP_OLD_CREATE(dvp, ap->a_vpp, &cnp, ap->a_vap);
364 if (error == 0) {
365 cache_setunresolved(nch);
366 cache_setvp(nch, *ap->a_vpp);
367 }
368 } else {
369 if (error == 0) {
370 vput(*ap->a_vpp);
371 *ap->a_vpp = NULL;
372 error = EEXIST;
373 }
374 KKASSERT(*ap->a_vpp == NULL);
375 }
376 if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
377 vn_unlock(dvp);
378 vrele(dvp);
379 return (error);
380 }
381
382 /*
383 * vop_compat_nmkdir { struct nchandle *a_nch, XXX STOPGAP FUNCTION
384 * struct vnode *a_dvp,
385 * struct vnode **a_vpp,
386 * struct ucred *a_cred,
387 * struct vattr *a_vap }
388 *
389 * Create a directory as specified by a_vap. Compatibility requires us to
390 * issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKDIR in
391 * order to setup the directory inode's i_offset and i_count (e.g. in UFS).
392 */
393 int
394 vop_compat_nmkdir(struct vop_nmkdir_args *ap)
395 {
396 struct thread *td = curthread;
397 struct componentname cnp;
398 struct nchandle *nch;
399 struct namecache *ncp;
400 struct vnode *dvp;
401 int error;
402
403 /*
404 * Sanity checks, get a locked directory vnode.
405 */
406 nch = ap->a_nch; /* locked namecache node */
407 ncp = nch->ncp;
408 dvp = ap->a_dvp;
409 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
410 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
411 ncp, ncp->nc_name);
412 return(EAGAIN);
413 }
414
415 /*
416 * Setup the cnp for a traditional vop_old_lookup() call. The lookup
417 * caches all information required to create the entry in the
418 * directory inode. We expect a return code of EJUSTRETURN for
419 * the CREATE case. The cnp must simulated a saved-name situation.
420 */
421 bzero(&cnp, sizeof(cnp));
422 cnp.cn_nameiop = NAMEI_CREATE;
423 cnp.cn_flags = CNP_LOCKPARENT;
424 cnp.cn_nameptr = ncp->nc_name;
425 cnp.cn_namelen = ncp->nc_nlen;
426 cnp.cn_cred = ap->a_cred;
427 cnp.cn_td = td;
428 *ap->a_vpp = NULL;
429
430 error = vop_old_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
431
432 /*
433 * EJUSTRETURN should be returned for this case, which means that
434 * the VFS has setup the directory inode for the create. The dvp we
435 * passed in is expected to remain in a locked state.
436 *
437 * If the VOP_OLD_MKDIR is successful we are responsible for updating
438 * the cache state of the locked ncp that was passed to us.
439 */
440 if (error == EJUSTRETURN) {
441 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
442 error = VOP_OLD_MKDIR(dvp, ap->a_vpp, &cnp, ap->a_vap);
443 if (error == 0) {
444 cache_setunresolved(nch);
445 cache_setvp(nch, *ap->a_vpp);
446 }
447 } else {
448 if (error == 0) {
449 vput(*ap->a_vpp);
450 *ap->a_vpp = NULL;
451 error = EEXIST;
452 }
453 KKASSERT(*ap->a_vpp == NULL);
454 }
455 if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
456 vn_unlock(dvp);
457 vrele(dvp);
458 return (error);
459 }
460
461 /*
462 * vop_compat_nmknod { struct nchandle *a_nch, XXX STOPGAP FUNCTION
463 * struct vnode *a_dvp,
464 * struct vnode **a_vpp,
465 * struct ucred *a_cred,
466 * struct vattr *a_vap }
467 *
468 * Create a device or fifo node as specified by a_vap. Compatibility requires
469 * us to issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKNOD
470 * in order to setup the directory inode's i_offset and i_count (e.g. in UFS).
471 */
472 int
473 vop_compat_nmknod(struct vop_nmknod_args *ap)
474 {
475 struct thread *td = curthread;
476 struct componentname cnp;
477 struct nchandle *nch;
478 struct namecache *ncp;
479 struct vnode *dvp;
480 int error;
481
482 /*
483 * Sanity checks, get a locked directory vnode.
484 */
485 nch = ap->a_nch; /* locked namecache node */
486 ncp = nch->ncp;
487 dvp = ap->a_dvp;
488
489 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
490 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
491 ncp, ncp->nc_name);
492 return(EAGAIN);
493 }
494
495 /*
496 * Setup the cnp for a traditional vop_old_lookup() call. The lookup
497 * caches all information required to create the entry in the
498 * directory inode. We expect a return code of EJUSTRETURN for
499 * the CREATE case. The cnp must simulated a saved-name situation.
500 */
501 bzero(&cnp, sizeof(cnp));
502 cnp.cn_nameiop = NAMEI_CREATE;
503 cnp.cn_flags = CNP_LOCKPARENT;
504 cnp.cn_nameptr = ncp->nc_name;
505 cnp.cn_namelen = ncp->nc_nlen;
506 cnp.cn_cred = ap->a_cred;
507 cnp.cn_td = td;
508 *ap->a_vpp = NULL;
509
510 error = vop_old_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp);
511
512 /*
513 * EJUSTRETURN should be returned for this case, which means that
514 * the VFS has setup the directory inode for the create. The dvp we
515 * passed in is expected to remain in a locked state.
516 *
517 * If the VOP_OLD_MKNOD is successful we are responsible for updating
518 * the cache state of the locked ncp that was passed to us.
519 */
520 if (error == EJUSTRETURN) {
521 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
522 error = VOP_OLD_MKNOD(dvp, ap->a_vpp, &cnp, ap->a_vap);
523 if (error == 0) {
524 cache_setunresolved(nch);
525 cache_setvp(nch, *ap->a_vpp);
526 }
527 } else {
528 if (error == 0) {
529 vput(*ap->a_vpp);
530 *ap->a_vpp = NULL;
531 error = EEXIST;
532 }
533 KKASSERT(*ap->a_vpp == NULL);
534 }
535 if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
536 vn_unlock(dvp);
537 vrele(dvp);
538 return (error);
539 }
540
541 /*
542 * vop_compat_nlink { struct nchandle *a_nch, XXX STOPGAP FUNCTION
543 * struct vnode *a_dvp,
544 * struct vnode *a_vp,
545 * struct ucred *a_cred }
546 *
547 * The passed vp is locked and represents the source. The passed ncp is
548 * locked and represents the target to create.
549 */
550 int
551 vop_compat_nlink(struct vop_nlink_args *ap)
552 {
553 struct thread *td = curthread;
554 struct componentname cnp;
555 struct nchandle *nch;
556 struct namecache *ncp;
557 struct vnode *dvp;
558 struct vnode *tvp;
559 int error;
560
561 /*
562 * Sanity checks, get a locked directory vnode.
563 */
564 nch = ap->a_nch; /* locked namecache node */
565 ncp = nch->ncp;
566 dvp = ap->a_dvp;
567
568 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
569 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
570 ncp, ncp->nc_name);
571 return(EAGAIN);
572 }
573
574 /*
575 * Setup the cnp for a traditional vop_old_lookup() call. The lookup
576 * caches all information required to create the entry in the
577 * directory inode. We expect a return code of EJUSTRETURN for
578 * the CREATE case. The cnp must simulated a saved-name situation.
579 *
580 * It should not be possible for there to be a vnode collision
581 * between the source vp and target (name lookup). However NFS
582 * clients racing each other can cause NFS to alias the same vnode
583 * across several names without the rest of the system knowing it.
584 * Use CNP_NOTVP to avoid a panic in this situation.
585 */
586 bzero(&cnp, sizeof(cnp));
587 cnp.cn_nameiop = NAMEI_CREATE;
588 cnp.cn_flags = CNP_LOCKPARENT | CNP_NOTVP;
589 cnp.cn_nameptr = ncp->nc_name;
590 cnp.cn_namelen = ncp->nc_nlen;
591 cnp.cn_cred = ap->a_cred;
592 cnp.cn_td = td;
593 cnp.cn_notvp = ap->a_vp;
594
595 tvp = NULL;
596 error = vop_old_lookup(ap->a_head.a_ops, dvp, &tvp, &cnp);
597
598 /*
599 * EJUSTRETURN should be returned for this case, which means that
600 * the VFS has setup the directory inode for the create. The dvp we
601 * passed in is expected to remain in a locked state.
602 *
603 * If the VOP_OLD_LINK is successful we are responsible for updating
604 * the cache state of the locked ncp that was passed to us.
605 */
606 if (error == EJUSTRETURN) {
607 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
608 error = VOP_OLD_LINK(dvp, ap->a_vp, &cnp);
609 if (error == 0) {
610 cache_setunresolved(nch);
611 cache_setvp(nch, ap->a_vp);
612 }
613 } else {
614 if (error == 0) {
615 vput(tvp);
616 error = EEXIST;
617 }
618 }
619 if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
620 vn_unlock(dvp);
621 vrele(dvp);
622 return (error);
623 }
624
625 int
626 vop_compat_nsymlink(struct vop_nsymlink_args *ap)
627 {
628 struct thread *td = curthread;
629 struct componentname cnp;
630 struct nchandle *nch;
631 struct namecache *ncp;
632 struct vnode *dvp;
633 struct vnode *vp;
634 int error;
635
636 /*
637 * Sanity checks, get a locked directory vnode.
638 */
639 *ap->a_vpp = NULL;
640 nch = ap->a_nch; /* locked namecache node */
641 ncp = nch->ncp;
642 dvp = ap->a_dvp;
643
644 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
645 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
646 ncp, ncp->nc_name);
647 return(EAGAIN);
648 }
649
650 /*
651 * Setup the cnp for a traditional vop_old_lookup() call. The lookup
652 * caches all information required to create the entry in the
653 * directory inode. We expect a return code of EJUSTRETURN for
654 * the CREATE case. The cnp must simulated a saved-name situation.
655 */
656 bzero(&cnp, sizeof(cnp));
657 cnp.cn_nameiop = NAMEI_CREATE;
658 cnp.cn_flags = CNP_LOCKPARENT;
659 cnp.cn_nameptr = ncp->nc_name;
660 cnp.cn_namelen = ncp->nc_nlen;
661 cnp.cn_cred = ap->a_cred;
662 cnp.cn_td = td;
663
664 vp = NULL;
665 error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
666
667 /*
668 * EJUSTRETURN should be returned for this case, which means that
669 * the VFS has setup the directory inode for the create. The dvp we
670 * passed in is expected to remain in a locked state.
671 *
672 * If the VOP_OLD_SYMLINK is successful we are responsible for updating
673 * the cache state of the locked ncp that was passed to us.
674 */
675 if (error == EJUSTRETURN) {
676 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
677 error = VOP_OLD_SYMLINK(dvp, &vp, &cnp, ap->a_vap, ap->a_target);
678 if (error == 0) {
679 cache_setunresolved(nch);
680 cache_setvp(nch, vp);
681 *ap->a_vpp = vp;
682 }
683 } else {
684 if (error == 0) {
685 vput(vp);
686 vp = NULL;
687 error = EEXIST;
688 }
689 KKASSERT(vp == NULL);
690 }
691 if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
692 vn_unlock(dvp);
693 vrele(dvp);
694 return (error);
695 }
696
697 /*
698 * vop_compat_nwhiteout { struct nchandle *a_nch, XXX STOPGAP FUNCTION
699 * struct vnode *a_dvp,
700 * struct ucred *a_cred,
701 * int a_flags }
702 *
703 * Issie a whiteout operation (create, lookup, or delete). Compatibility
704 * requires us to issue the appropriate VOP_OLD_LOOKUP before we issue
705 * VOP_OLD_WHITEOUT in order to setup the directory inode's i_offset and i_count
706 * (e.g. in UFS) for the NAMEI_CREATE and NAMEI_DELETE ops. For NAMEI_LOOKUP
707 * no lookup is necessary.
708 */
709 int
710 vop_compat_nwhiteout(struct vop_nwhiteout_args *ap)
711 {
712 struct thread *td = curthread;
713 struct componentname cnp;
714 struct nchandle *nch;
715 struct namecache *ncp;
716 struct vnode *dvp;
717 struct vnode *vp;
718 int error;
719
720 /*
721 * Sanity checks, get a locked directory vnode.
722 */
723 nch = ap->a_nch; /* locked namecache node */
724 ncp = nch->ncp;
725 dvp = ap->a_dvp;
726
727 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
728 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
729 ncp, ncp->nc_name);
730 return(EAGAIN);
731 }
732
733 /*
734 * Setup the cnp for a traditional vop_old_lookup() call. The lookup
735 * caches all information required to create the entry in the
736 * directory inode. We expect a return code of EJUSTRETURN for
737 * the CREATE case. The cnp must simulated a saved-name situation.
738 */
739 bzero(&cnp, sizeof(cnp));
740 cnp.cn_nameiop = ap->a_flags;
741 cnp.cn_flags = CNP_LOCKPARENT;
742 cnp.cn_nameptr = ncp->nc_name;
743 cnp.cn_namelen = ncp->nc_nlen;
744 cnp.cn_cred = ap->a_cred;
745 cnp.cn_td = td;
746
747 vp = NULL;
748
749 /*
750 * EJUSTRETURN should be returned for the CREATE or DELETE cases.
751 * The VFS has setup the directory inode for the create. The dvp we
752 * passed in is expected to remain in a locked state.
753 *
754 * If the VOP_OLD_WHITEOUT is successful we are responsible for updating
755 * the cache state of the locked ncp that was passed to us.
756 */
757 switch(ap->a_flags) {
758 case NAMEI_DELETE:
759 cnp.cn_flags |= CNP_DOWHITEOUT;
760 /* fall through */
761 case NAMEI_CREATE:
762 error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
763 if (error == EJUSTRETURN) {
764 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
765 error = VOP_OLD_WHITEOUT(dvp, &cnp, ap->a_flags);
766 if (error == 0)
767 cache_setunresolved(nch);
768 } else {
769 if (error == 0) {
770 vput(vp);
771 vp = NULL;
772 error = EEXIST;
773 }
774 KKASSERT(vp == NULL);
775 }
776 break;
777 case NAMEI_LOOKUP:
778 error = VOP_OLD_WHITEOUT(dvp, NULL, ap->a_flags);
779 break;
780 default:
781 error = EINVAL;
782 break;
783 }
784 if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0)
785 vn_unlock(dvp);
786 vrele(dvp);
787 return (error);
788 }
789
790
791 /*
792 * vop_compat_nremove { struct nchandle *a_nch, XXX STOPGAP FUNCTION
793 * struct vnode *a_dvp,
794 * struct ucred *a_cred }
795 */
796 int
797 vop_compat_nremove(struct vop_nremove_args *ap)
798 {
799 struct thread *td = curthread;
800 struct componentname cnp;
801 struct nchandle *nch;
802 struct namecache *ncp;
803 struct vnode *dvp;
804 struct vnode *vp;
805 int error;
806
807 /*
808 * Sanity checks, get a locked directory vnode.
809 */
810 nch = ap->a_nch; /* locked namecache node */
811 ncp = nch->ncp;
812 dvp = ap->a_dvp;
813
814 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
815 kprintf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n",
816 ncp, ncp->nc_name);
817 return(EAGAIN);
818 }
819
820 /*
821 * Setup the cnp for a traditional vop_old_lookup() call. The lookup
822 * caches all information required to delete the entry in the
823 * directory inode. We expect a return code of 0 for the DELETE
824 * case (meaning that a vp has been found). The cnp must simulated
825 * a saved-name situation.
826 */
827 bzero(&cnp, sizeof(cnp));
828 cnp.cn_nameiop = NAMEI_DELETE;
829 cnp.cn_flags = CNP_LOCKPARENT;
830 cnp.cn_nameptr = ncp->nc_name;
831 cnp.cn_namelen = ncp->nc_nlen;
832 cnp.cn_cred = ap->a_cred;
833 cnp.cn_td = td;
834
835 /*
836 * The vnode must be a directory and must not represent the
837 * current directory.
838 */
839 vp = NULL;
840 error = vop_old_lookup(ap->a_head.a_ops, dvp, &vp, &cnp);
841 if (error == 0 && vp->v_type == VDIR)
842 error = EPERM;
843 if (error == 0) {
844 KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0);
845 error = VOP_OLD_REMOVE(dvp, vp, &cnp);
846 if (error == 0)
847 cache_unlink(nch);
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 atomic_add_int(&vp->v_writecount, 1);
1187 KKASSERT(vp->v_opencount >= 0 && vp->v_opencount != INT_MAX);
1188 atomic_add_int(&vp->v_opencount, 1);
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",
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",
1210 vp, vp->v_writecount));
1211 atomic_add_int(&vp->v_writecount, -1);
1212 }
1213 atomic_add_int(&vp->v_opencount, -1);
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 7
1461
1462 static const char *accounting_fstypes[ACCOUNTING_NB_FSTYPES] = {
1463 "ext2fs", "hammer", "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 /* is mounted fs type one we want to do some accounting for ? */
1472 for (i=0; i<ACCOUNTING_NB_FSTYPES; i++) {
1473 fs_type = accounting_fstypes[i];
1474 if (strncmp(mp->mnt_stat.f_fstypename, fs_type,
1475 sizeof(mp->mnt_stat)) == 0) {
1476 fstype_ok = 1;
1477 break;
1478 }
1479 }
1480 if (fstype_ok == 0)
1481 return (0);
1482
1483 vq_init(mp);
1484 return (0);
1485 }
1486
1487 void
1488 vfs_stdac_done(struct mount *mp)
1489 {
1490 vq_done(mp);
1491 }
1492
1493 void
1494 vfs_stdncpgen_set(struct mount *mp, struct namecache *ncp)
1495 {
1496 }
1497
1498 int
1499 vfs_stdncpgen_test(struct mount *mp, struct namecache *ncp)
1500 {
1501 return 0;
1502 }
1503 /* end of vfs default ops */
Cache object: eabccc1b3fe72b4f77ca3ec71b9cd187
|