xref: /netbsd-src/sys/kern/vnode_if.sh (revision 26784725eeed8e5fc5898ec384aab2af43e2e264)
1#!/bin/sh -
2copyright="\
3/*
4 * Copyright (c) 1992, 1993, 1994, 1995
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS \`\`AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31"
32SCRIPT_ID='$NetBSD: vnode_if.sh,v 1.77 2022/10/26 23:39:43 riastradh Exp $'
33
34# Script to produce VFS front-end sugar.
35#
36# usage: vnode_if.sh srcfile
37#	(where srcfile is currently /sys/kern/vnode_if.src)
38#
39
40if [ $# -ne 1 ] ; then
41	echo 'usage: vnode_if.sh srcfile'
42	exit 1
43fi
44
45# Name and revision of the source file.
46src=$1
47SRC_ID=`head -1 $src | sed -e 's/.*\$\(.*\)\$.*/\1/'`
48
49# Names of the created files.
50out_c=vnode_if.c
51out_rumpc=../rump/librump/rumpvfs/rumpvnode_if.c
52out_h=../sys/vnode_if.h
53out_rumph=../rump/include/rump/rumpvnode_if.h
54
55# generate VNODE_LOCKDEBUG checks (not fully functional)
56lockdebug=1
57
58# Awk program (must support nawk extensions)
59# Use "awk" at Berkeley, "nawk" or "gawk" elsewhere.
60awk=${AWK:-awk}
61
62# Does this awk have a "toupper" function? (i.e. is it GNU awk)
63isgawk=`$awk 'BEGIN { print toupper("true"); exit; }' 2>/dev/null`
64
65# If this awk does not define "toupper" then define our own.
66if [ "$isgawk" = TRUE ] ; then
67	# GNU awk provides it.
68	toupper=
69else
70	# Provide our own toupper()
71	toupper='
72function toupper(str) {
73	_toupper_cmd = "echo "str" |tr a-z A-Z"
74	_toupper_cmd | getline _toupper_str;
75	close(_toupper_cmd);
76	return _toupper_str;
77}'
78fi
79
80#
81# This is the common part of all awk programs that read $src
82# This parses the input for one function into the arrays:
83#	argdir, argtype, argname, willrele
84# and calls "doit()" to generate output for the function.
85#
86# Input to this parser is pre-processed slightly by sed
87# so this awk parser doesn't have to work so hard.  The
88# changes done by the sed pre-processing step are:
89#	insert a space between * and pointer name
90#	replace semicolons with spaces
91#
92sed_prep='s:\*\([^\*/]\):\* \1:g
93s/;/ /'
94awk_parser='
95# Comment line
96/^#/	{ next; }
97# First line of description
98/^vop_/	{
99	name=$1;
100	args_name=$1;
101	argc=0;
102	have_context=0;
103	is_context=0;
104	ncontext=0;
105	willmake=-1;
106	fstrans="";
107	do_pre="";
108	do_post="";
109	next;
110}
111# Last line of description
112/^}/	{
113	doit();
114	next;
115}
116# Middle lines of description
117{
118	if ($1 == "VERSION") {
119		args_name=args_name "_v" $2;
120		next;
121	} else if ($1 ~ "^FSTRANS=") {
122		fstrans = $1;
123		sub("FSTRANS=", "", fstrans);
124		next;
125	} else if ($1 ~ "^PRE=") {
126		do_pre = $1;
127		sub("PRE=", "", do_pre);
128		next;
129	} else if ($1 ~ "^POST=") {
130		do_post = $1;
131		sub("POST=", "", do_post);
132		next;
133	}
134
135	if ($1 == "CONTEXT") {
136		# CONTEXT require PRE and POST handlers.
137		if (do_pre == "" || do_post == "")
138			next;
139		is_context=1;
140		have_context=1;
141	} else {
142		if (have_context) {
143			# CONTEXT members must come at the end of
144			# the args structure, so everything else
145			# is ignored.
146			next;
147		}
148		argdir[argc] = $1;
149	}
150	i=2;
151
152	if (is_context == 0) {
153		if ($2 == "LOCKED=EXCL") {
154			lockstate[argc] = "elocked";
155			i++;
156		} else if ($2 == "LOCKED=YES") {
157			lockstate[argc] = "locked";
158			i++;
159		} else if ($2 == "LOCKED=NO") {
160			lockstate[argc] = "unlocked";
161			i++;
162		} else
163			lockstate[argc] = "";
164
165		if ($2 == "WILLRELE" ||
166		    $3 == "WILLRELE") {
167			willrele[argc] = 1;
168			i++;
169		} else if ($2 == "WILLPUT" ||
170			   $3 == "WILLPUT") {
171			willrele[argc] = 3;
172			i++;
173		} else
174			willrele[argc] = 0;
175
176		if ($2 == "WILLMAKE") {
177			willmake=argc;
178			i++;
179		}
180		if (argc == 0 && fstrans == "") {
181			if (lockstate[0] == "locked" ||
182			     lockstate[0] == "elocked")
183				fstrans = "NO";
184			else
185				fstrans = "YES";
186		}
187	}
188
189	# XXX: replace non-portable types for rump.  We should really
190	# nuke the types from the kernel, but that is a battle for
191	# another day.
192	at = $i;
193	if (rump) {
194		if (at == "vm_prot_t")
195			at = "int";
196		if (at == "voff_t")
197			at = "off_t";
198		if (at == "kauth_cred_t")
199			at = "struct kauth_cred *"
200		if (at == "daddr_t")
201			at = "int64_t"
202	}
203	argtype[argc + ncontext] = at;
204	i++;
205	while (i < NF) {
206		argtype[argc + ncontext] = argtype[argc + ncontext]" "$i;
207		i++;
208	}
209	argname[argc + ncontext] = $i;
210	if (is_context)
211		ncontext++;
212	else
213		argc++;
214	next;
215}
216'
217
218# This is put before the copyright on each generated file.
219warning="\
220/*	@NetBSD@	*/
221
222/*
223 * Warning: DO NOT EDIT! This file is automatically generated!
224 * (Modifications made here may easily be lost!)
225 *
226 * Created from the file:
227 *	${SRC_ID}
228 * by the script:
229 *	${SCRIPT_ID}
230 */
231"
232
233# This is to satisfy McKusick (get rid of evil spaces 8^)
234anal_retentive='s:\([^/]\*\) :\1:g'
235
236do_hfile () {
237#
238# Redirect stdout to the H file.
239#
240echo "$0: Creating $1" 1>&2
241exec > $1
242rump=$2
243
244# Begin stuff
245if [ -z "${rump}" ]; then
246	SYS='SYS_'
247else
248	SYS='RUMP_RUMP'
249fi
250echo -n "$warning" | sed -e 's/\$//g;s/@/\$/g;s/ $//'
251echo ""
252echo -n "$copyright"
253echo ''
254echo "#ifndef _${SYS}VNODE_IF_H_"
255echo "#define _${SYS}VNODE_IF_H_"
256[ -z "${rump}" ] && echo "
257extern const struct vnodeop_desc ${rump}vop_default_desc;"
258echo
259
260# Body stuff
261# This awk program needs toupper() so define it if necessary.
262sed -e "$sed_prep" $src | $awk -v rump=${rump} "$toupper"'
263function doit() {
264	name = rump name
265	# Declare arg struct, descriptor.
266	if (!rump) {
267		printf("\n#define %s_DESCOFFSET %d\n",
268		    toupper(name), vop_offset++);
269		printf("struct %s_args {\n", args_name);
270		printf("\tconst struct vnodeop_desc * a_desc;\n");
271		for (i=0; i<argc; i++) {
272			printf("\t%s a_%s;\n", argtype[i], argname[i]);
273		}
274		for (i=0; i<ncontext; i++) {
275			printf("\t%s ctx_%s;\n", argtype[argc+i], \
276			    argname[argc+i]);
277		}
278		printf("};\n");
279		printf("extern const struct vnodeop_desc %s_desc;\n", name);
280	}
281	# Prototype it.
282	protoarg = sprintf("int %s(", toupper(name));
283	protolen = length(protoarg);
284	printf("%s", protoarg);
285	for (i=0; i<argc; i++) {
286		protoarg = sprintf("%s", argtype[i]);
287		if (i < (argc-1)) protoarg = (protoarg ", ");
288		arglen = length(protoarg);
289		if ((protolen + arglen) > 77) {
290			protoarg = ("\n    " protoarg);
291			arglen += 4;
292			protolen = 0;
293		}
294		printf("%s", protoarg);
295		protolen += arglen;
296	}
297	printf(");\n");
298}
299BEGIN	{
300	vop_offset = 1; # start at 1, to count the 'default' op
301
302	printf("struct buf;\n");
303	if (rump) {
304		printf("struct flock;\n");
305		printf("struct knote;\n");
306		printf("struct vm_page;\n");
307		printf("struct acl;\n");
308		printf("\n#include <sys/acl.h>\n");
309	}
310	printf("\n#ifndef _KERNEL\n#include <stdbool.h>\n#endif\n");
311	if (rump)
312		printf("\n");
313}
314END	{
315	if (!rump) {
316		printf("\n#define VNODE_OPS_COUNT\t%d\n", vop_offset);
317	}
318}
319'"$awk_parser" | sed -e "$anal_retentive"
320
321# End stuff
322echo ''
323echo "#endif /* !_${SYS}VNODE_IF_H_ */"
324}
325do_hfile $out_h ''
326do_hfile $out_rumph 'rump_'
327
328do_cfile () {
329#
330# Redirect stdout to the C file.
331#
332echo "$0: Creating $1" 1>&2
333exec > $1
334rump=$2
335
336# Begin stuff
337echo -n "$warning" | sed -e 's/\$//g;s/@/\$/g;s/ $//'
338echo ""
339echo -n "$copyright"
340echo "
341#include <sys/cdefs.h>
342__KERNEL_RCSID(0, \"\$NetBSD\$\");"
343
344if [ -z "${rump}" -a ${lockdebug} -ne 0 ] ; then
345	echo ''
346	echo '#ifdef _KERNEL_OPT'
347	echo '#include "opt_vnode_lockdebug.h"'
348	echo '#endif /* _KERNEL_OPT */'
349fi
350
351echo '
352#include <sys/param.h>
353#include <sys/mount.h>
354#include <sys/buf.h>
355#include <sys/fcntl.h>
356#include <sys/vnode.h>
357#include <sys/lock.h>'
358[ -z "${rump}" ] && echo '#include <sys/fstrans.h>'
359[ ! -z "${rump}" ] && echo '#include <rump/rumpvnode_if.h>'		\
360	&& echo '#include <rump-sys/kern.h>'
361
362if [ -z "${rump}" ] ; then
363	echo "
364#include <miscfs/deadfs/deadfs.h>
365
366enum fst_op { FST_NO, FST_YES, FST_LAZY, FST_TRY };
367
368static inline int
369vop_pre(vnode_t *vp, struct mount **mp, bool *mpsafe, enum fst_op op)
370{
371	int error;
372
373	*mpsafe = (vp->v_vflag & VV_MPSAFE);
374
375	if (!*mpsafe) {
376		KERNEL_LOCK(1, curlwp);
377	}
378
379	if (op == FST_YES || op == FST_LAZY || op == FST_TRY) {
380		for (;;) {
381			*mp = vp->v_mount;
382			if (op == FST_TRY) {
383				error = fstrans_start_nowait(*mp);
384				if (error) {
385					if (!*mpsafe) {
386						KERNEL_UNLOCK_ONE(curlwp);
387					}
388					return error;
389				}
390			} else if (op == FST_LAZY) {
391				fstrans_start_lazy(*mp);
392			} else {
393				fstrans_start(*mp);
394			}
395			if (__predict_true(*mp == vp->v_mount))
396				break;
397			fstrans_done(*mp);
398		}
399	} else {
400		*mp = vp->v_mount;
401	}
402
403	return 0;
404}
405
406static inline u_quad_t
407vop_pre_get_size(struct vnode *vp)
408{
409	mutex_enter(vp->v_interlock);
410	KASSERT(vp->v_size != VSIZENOTSET);
411	u_quad_t rv = (u_quad_t)vp->v_size;
412	mutex_exit(vp->v_interlock);
413
414	return rv;
415}
416
417/*
418 * VOP_RMDIR(), VOP_REMOVE(), and VOP_RENAME() need special handling
419 * because they each drop the caller's references on one or more of
420 * their arguments.  While there must be an open file descriptor in
421 * associated with a vnode in order for knotes to be attached to it,
422 * that status could change during the course of the operation.  So,
423 * for the vnode arguments that are WILLRELE or WILLPUT, we check
424 * pre-op if there are registered knotes, take a hold count if so,
425 * and post-op release the hold after activating any knotes still
426 * associated with the vnode.
427 */
428
429#define	VOP_POST_KNOTE(thisvp, e, n)					\\
430do {									\\
431	if (__predict_true((e) == 0)) {					\\
432		/*							\\
433		 * VN_KNOTE() does the VN_KEVENT_INTEREST()		\\
434		 * check for us.					\\
435		 */							\\
436		VN_KNOTE((thisvp), (n));				\\
437	}								\\
438} while (/*CONSTCOND*/0)
439
440#define	VOP_POST_KNOTE_HELD(thisvp, e, n)				\\
441do {									\\
442	/*								\\
443	 * We don't perform a VN_KEVENT_INTEREST() check here; it	\\
444	 * was already performed when we did the pre-op work that	\\
445	 * caused the vnode to be held in the first place.		\\
446	 */								\\
447	mutex_enter((thisvp)->v_interlock);				\\
448	if (__predict_true((e) == 0)) {					\\
449		knote(&(thisvp)->v_klist->vk_klist, (n));		\\
450	}								\\
451	holdrelel((thisvp));						\\
452	mutex_exit((thisvp)->v_interlock);				\\
453	/*								\\
454	 * thisvp might be gone now!  Don't touch!			\\
455	 */								\\
456} while (/*CONSTCOND*/0)
457
458#define	vop_create_post(ap, e)						\\
459	VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE)
460
461#define	vop_mknod_post(ap, e)						\\
462	VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE)
463
464#define	vop_setattr_pre(ap)						\\
465	u_quad_t osize = 0;						\\
466	long vp_events =						\\
467	    VN_KEVENT_INTEREST((ap)->a_vp, NOTE_ATTRIB | NOTE_EXTEND)	\\
468	    ? NOTE_ATTRIB : 0;						\\
469	bool check_extend = false;					\\
470	if (__predict_false(vp_events != 0 &&				\\
471	    (ap)->a_vap->va_size != VNOVALSIZE)) {			\\
472		check_extend = true;					\\
473		osize = vop_pre_get_size((ap)->a_vp);			\\
474	}
475
476#define	vop_setattr_post(ap, e)						\\
477do {									\\
478	if (__predict_false(vp_events != 0)) {				\\
479		if (__predict_false(check_extend &&			\\
480		    (ap)->a_vap->va_size > osize)) {			\\
481			vp_events |= NOTE_EXTEND;			\\
482		}							\\
483		VOP_POST_KNOTE((ap)->a_vp, (e), vp_events);		\\
484	}								\\
485} while (/*CONSTCOND*/0)
486
487#define	vop_setacl_post(ap, e)						\\
488	VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_ATTRIB)
489
490#define	vop_link_post(ap, e)						\\
491do {									\\
492	VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE);			\\
493	VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_LINK);			\\
494} while (/*CONSTCOND*/0)
495
496#define	vop_mkdir_post(ap, e)						\\
497	VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE | NOTE_LINK)
498
499#define	vop_remove_pre_common(ap)					\\
500	bool post_event_vp =						\\
501	    VN_KEVENT_INTEREST((ap)->a_vp, NOTE_DELETE | NOTE_LINK);	\\
502	if (__predict_false(post_event_vp)) {				\\
503		vhold((ap)->a_vp);					\\
504	}
505
506#define	vop_remove_post_common(ap, e, dn, lc)				\\
507do {									\\
508	VOP_POST_KNOTE((ap)->a_dvp, (e), (dn));				\\
509	if (__predict_false(post_event_vp)) {				\\
510		VOP_POST_KNOTE_HELD((ap)->a_vp, (e),			\\
511		    (lc) ? NOTE_LINK : NOTE_DELETE);			\\
512	}								\\
513} while (/*CONSTCOND*/0)
514
515/*
516 * One could make the argument that VOP_REMOVE() should send NOTE_LINK
517 * on vp if the resulting link count is not zero, but that's not what
518 * the documentation says.
519 *
520 * We could change this easily by passing ap->ctx_vp_new_nlink to
521 * vop_remove_post_common().
522 */
523#define	vop_remove_pre(ap)						\\
524	vop_remove_pre_common((ap));					\\
525	/*								\\
526	 * We will assume that the file being removed is deleted unless	\\
527	 * the file system tells us otherwise by updating vp_new_nlink.	\\
528	 */								\\
529	(ap)->ctx_vp_new_nlink = 0;
530
531#define	vop_remove_post(ap, e)						\\
532	vop_remove_post_common((ap), (e), NOTE_WRITE, 0)
533
534#define	vop_rmdir_pre(ap)						\\
535	vop_remove_pre_common(ap)
536
537#define	vop_rmdir_post(ap, e)						\\
538	vop_remove_post_common((ap), (e), NOTE_WRITE | NOTE_LINK, 0)
539
540#define	vop_symlink_post(ap, e)						\\
541	VOP_POST_KNOTE((ap)->a_dvp, (e), NOTE_WRITE)
542
543#define	vop_open_post(ap, e)						\\
544	VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_OPEN)
545
546#define	vop_close_post(ap, e)						\\
547do {									\\
548	/* See the definition of VN_KNOTE() in <sys/vnode.h>. */	\\
549	if (__predict_false(VN_KEVENT_INTEREST((ap)->a_vp,		\\
550	    NOTE_CLOSE_WRITE | NOTE_CLOSE) && (e) == 0)) {		\\
551		struct vnode *thisvp = (ap)->a_vp;			\\
552		mutex_enter(thisvp->v_interlock);			\\
553		/*							\\
554		 * Don't send NOTE_CLOSE when closing a vnode that's	\\
555		 * been reclaimed or otherwise revoked; a NOTE_REVOKE	\\
556		 * has already been sent, and this close is effectively	\\
557		 * meaningless from the watcher's perspective.		\\
558		 */							\\
559		if (__predict_true(thisvp->v_op != dead_vnodeop_p)) {	\\
560			knote(&thisvp->v_klist->vk_klist,		\\
561			    ((ap)->a_fflag & FWRITE)			\\
562			    ? NOTE_CLOSE_WRITE : NOTE_CLOSE);		\\
563		}							\\
564		mutex_exit(thisvp->v_interlock);			\\
565	}								\\
566} while (/*CONSTCOND*/0)
567
568#define	vop_read_post(ap, e)						\\
569	VOP_POST_KNOTE((ap)->a_vp, (e), NOTE_READ)
570
571#define	vop_write_pre(ap)						\\
572	off_t ooffset = 0, noffset = 0;					\\
573	u_quad_t osize = 0;						\\
574	long vp_events =						\\
575	    VN_KEVENT_INTEREST((ap)->a_vp, NOTE_WRITE | NOTE_EXTEND)	\\
576	    ? NOTE_WRITE : 0;						\\
577	if (__predict_false(vp_events != 0)) {				\\
578		ooffset = (ap)->a_uio->uio_offset;			\\
579		osize = vop_pre_get_size((ap)->a_vp);			\\
580	}
581
582#define	vop_write_post(ap, e)						\\
583do {									\\
584	/*								\\
585	 * If any data was written, we'll post an event, even if	\\
586	 * there was an error.						\\
587	 */								\\
588	noffset = (ap)->a_uio->uio_offset;				\\
589	if (__predict_false(vp_events != 0 && noffset > ooffset)) {	\\
590		if (noffset > osize) {					\\
591			vp_events |= NOTE_EXTEND;			\\
592		}							\\
593		VN_KNOTE((ap)->a_vp, vp_events);			\\
594	}								\\
595} while (/*CONSTCOND*/0)
596
597static inline void
598vop_post(vnode_t *vp, struct mount *mp, bool mpsafe, enum fst_op op)
599{
600
601	if (op == FST_YES || op == FST_LAZY) {
602		fstrans_done(mp);
603	}
604
605	if (!mpsafe) {
606		KERNEL_UNLOCK_ONE(curlwp);
607	}
608}
609
610static inline void
611assert_vop_unlocked(vnode_t *vp, const char *str)
612{
613#if defined(VNODE_LOCKDEBUG)
614
615	if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
616		panic(\"%s: %p %d/%d is locked but should not be\",
617		    str, vp, vp->v_tag, vp->v_type);
618#endif
619}
620
621static inline void
622assert_vop_locked(vnode_t *vp, const char *str)
623{
624#if defined(VNODE_LOCKDEBUG)
625
626	if (VOP_ISLOCKED(vp) == LK_NONE)
627		panic(\"%s: %p %d/%d is not locked but should be\",
628		    str, vp, vp->v_tag, vp->v_type);
629#endif
630}
631
632static inline void
633assert_vop_elocked(vnode_t *vp, const char *str)
634{
635#if defined(VNODE_LOCKDEBUG)
636
637	if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE)
638		panic(\"%s: %p %d/%d is not exclusive locked but should be\",
639		    str, vp, vp->v_tag, vp->v_type);
640#endif
641}
642
643const struct vnodeop_desc vop_default_desc = {"
644echo '	0,
645	"default",
646	0,
647	NULL,
648	VDESC_NO_OFFSET,
649	VDESC_NO_OFFSET,
650	VDESC_NO_OFFSET,
651};
652'
653fi
654
655# Body stuff
656sed -e "$sed_prep" $src | $awk -v rump=${rump} -v lockdebug=${lockdebug} '
657function do_offset(typematch) {
658	for (i=0; i<argc; i++) {
659		if (argtype[i] == typematch) {
660			printf("\tVOPARG_OFFSETOF(struct %s_args, a_%s),\n",
661				args_name, argname[i]);
662			return i;
663		};
664	};
665	print "\tVDESC_NO_OFFSET,";
666	return -1;
667}
668
669function offsets() {
670	# Define offsets array
671	printf("const int %s_vp_offsets[] = {\n", name);
672	for (i=0; i<argc; i++) {
673		if (argtype[i] == "struct vnode *") {
674			printf ("\tVOPARG_OFFSETOF(struct %s_args,a_%s),\n",
675				args_name, argname[i]);
676		}
677	}
678	print "\tVDESC_NO_OFFSET";
679	print "};";
680	# Define F_desc
681	printf("const struct vnodeop_desc %s_desc = {\n", name);
682	# offset
683	printf ("\t%s_DESCOFFSET,\n", toupper(name));
684	# printable name
685	printf ("\t\"%s\",\n", name);
686	# flags
687	printf("\t0");
688	vpnum = 0;
689	for (i=0; i<argc; i++) {
690		if (willrele[i]) {
691			if (willrele[i] == 3) {
692				word = "PUT";
693			} else {
694				word = "RELE";
695			}
696			printf(" | VDESC_VP%s_WILL%s", vpnum, word);
697		}
698		if (argtype[i] == "struct vnode *")
699			vpnum++;
700	}
701	print ",";
702	# vp offsets
703	printf ("\t%s_vp_offsets,\n", name);
704	# vpp (if any)
705	do_offset("struct vnode **");
706	# cred (if any)
707	do_offset("kauth_cred_t");
708	# componentname
709	do_offset("struct componentname *");
710	printf ("};\n");
711}
712
713function bodyrump() {
714	printf("{\n\tint error;\n\n");
715	printf("\trump_schedule();\n");
716	printf("\terror = %s(", toupper(name));
717	for (i=0; i<argc; i++) {
718		printf("%s", argname[i]);
719		if (i < (argc-1)) printf(", ");
720	}
721	printf(");\n");
722	printf("\trump_unschedule();\n\n");
723	printf("\treturn error;\n}\n");
724}
725
726function bodynorm() {
727	printf("{\n\tint error;\n\tbool mpsafe;\n\tstruct %s_args a;\n",
728		args_name);
729	printf("\tstruct mount *mp;\n");
730	printf("\ta.a_desc = VDESC(%s);\n", name);
731	for (i=0; i<argc; i++) {
732		printf("\ta.a_%s = %s;\n", argname[i], argname[i]);
733	}
734	if (lockdebug) {
735		for (i=0; i<argc; i++) {
736			if (lockstate[i] == "")
737				continue;
738			printf("\tassert_vop_%s(%s, \"%s: %s\");\n",
739			    lockstate[i], argname[i], name, argname[i]);
740		}
741	}
742	# This is done before generic vop_pre() because we want
743	# to do any setup before beginning an fstrans.
744	if (do_pre != "")
745		printf("\t%s(&a);\n", do_pre);
746	if (fstrans == "LOCK")
747		printf("\terror = vop_pre(%s, &mp, &mpsafe, %s);\n",
748			argname[0], "(!(flags & (LK_SHARED|LK_EXCLUSIVE)) ? FST_NO : (flags & LK_NOWAIT ? FST_TRY : FST_YES))");
749	else if (fstrans == "UNLOCK")
750		printf("\terror = vop_pre(%s, &mp, &mpsafe, FST_%s);\n",
751			argname[0], "NO");
752	else
753		printf("\terror = vop_pre(%s, &mp, &mpsafe, FST_%s);\n",
754			argname[0], fstrans);
755	printf("\tif (error)\n\t\treturn error;\n");
756	printf("\terror = (VCALL(%s, VOFFSET(%s), &a));\n",
757		argname[0], name);
758	if (fstrans == "LOCK")
759		printf("\tvop_post(%s, mp, mpsafe, %s);\n",
760			argname[0], "(flags & (LK_UPGRADE|LK_DOWNGRADE) ? FST_NO : (error ? FST_YES : FST_NO))");
761	else if (fstrans == "UNLOCK")
762		printf("\tvop_post(%s, mp, mpsafe, FST_%s);\n",
763			argname[0], "YES");
764	else
765		printf("\tvop_post(%s, mp, mpsafe, FST_%s);\n",
766			argname[0], fstrans);
767	# This is done after generic vop_post() in order to minimize
768	# time spent with the KERNEL_LOCK held for file systems that
769	# still require it.
770	if (do_post != "")
771		printf("\t%s(&a, error);\n", do_post);
772	if (willmake != -1) {
773		printf("#ifdef DIAGNOSTIC\n");
774		printf("\tif (error == 0)\n"				\
775		    "\t\tKASSERT((*%s)->v_size != VSIZENOTSET\n"	\
776		    "\t\t    && (*%s)->v_writesize != VSIZENOTSET);\n",
777		    argname[willmake], argname[willmake]);
778		printf("#endif /* DIAGNOSTIC */\n");
779	}
780	printf("\treturn error;\n}\n");
781}
782
783function doit() {
784	printf("\n");
785	if (!rump)
786		offsets();
787
788	if (rump)
789		extname = "RUMP_" toupper(name);
790	else
791		extname = toupper(name);
792
793	# Define function.
794	printf("int\n%s(", extname);
795	for (i=0; i<argc; i++) {
796		printf("%s %s", argtype[i], argname[i]);
797		if (i < (argc-1)) printf(",\n    ");
798	}
799	printf(")\n");
800
801	if (rump)
802		bodyrump();
803	else
804		bodynorm();
805}
806BEGIN	{
807	# start from 1 (vop_default is at 0)
808	argc=1;
809}
810'"$awk_parser" | sed -e "$anal_retentive"
811
812# End stuff
813[ -n "${rump}" ] && return
814
815# Add the vfs_op_descs array to the C file.
816# Begin stuff
817echo "
818const struct vnodeop_desc * const ${rump}vfs_op_descs[] = {
819	&${rump}vop_default_desc,	/* MUST BE FIRST */
820"
821
822# Body stuff
823sed -e "$sed_prep" $src | $awk -v rump=${rump} '
824function doit() {
825	printf("\t&%s_desc,\n", name);
826}
827'"$awk_parser"
828
829# End stuff
830echo '	NULL
831};'
832}
833do_cfile $out_c ''
834do_cfile $out_rumpc 'rump_'
835
836exit 0
837
838# Local Variables:
839# tab-width: 4
840# End:
841