xref: /freebsd/sys/tools/vnode_if.awk (revision 898496ee09ed2b7d25f6807edc4515628196ec0a)
1#!/usr/bin/awk -f
2
3#-
4# SPDX-License-Identifier: BSD-3-Clause
5#
6# Copyright (c) 1992, 1993
7#	The Regents of the University of California.  All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions
11# are met:
12# 1. Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14# 2. Redistributions in binary form must reproduce the above copyright
15#    notice, this list of conditions and the following disclaimer in the
16#    documentation and/or other materials provided with the distribution.
17# 3. Neither the name of the University nor the names of its contributors
18#    may be used to endorse or promote products derived from this software
19#    without specific prior written permission.
20#
21# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31# SUCH DAMAGE.
32
33#
34#	@(#)vnode_if.sh	8.1 (Berkeley) 6/10/93
35#
36# Script to produce VFS front-end sugar.
37#
38# usage: vnode_if.awk <srcfile> [-c | -h | -p | -q]
39#	(where <srcfile> is currently /sys/kern/vnode_if.src)
40#	The source file must have a .src extension
41#
42
43function usage()
44{
45	print "usage: vnode_if.awk <srcfile> [-c|-h|-p|-q]";
46	exit 1;
47}
48
49function die(msg, what)
50{
51	printf srcfile "(" fnr "): " > "/dev/stderr";
52	printf msg "\n", what > "/dev/stderr";
53	exit 1;
54}
55
56function t_spc(type)
57{
58	# Append a space if the type is not a pointer
59	return (type ~ /\*$/) ? type : type " ";
60}
61
62# These are just for convenience ...
63function printc(s) {print s > cfile;}
64function printh(s) {print s > hfile;}
65function printp(s) {print s > pfile;}
66function printq(s) {print s > qfile;}
67
68function add_debug_code(name, arg, pos, ind)
69{
70	if (arg == "vpp")
71		star = "*";
72	else
73		star = "";
74	if (lockdata[name, arg, pos] && (lockdata[name, arg, pos] != "-")) {
75		printc(ind"ASSERT_VI_UNLOCKED("star"a->a_"arg", \""uname" "pos" ("arg")\");");
76		# Add assertions for locking
77		if (lockdata[name, arg, pos] == "L")
78			printc(ind"ASSERT_VOP_LOCKED(" star "a->a_"arg", \""uname" "pos" ("arg")\");");
79		else if (lockdata[name, arg, pos] == "U")
80			printc(ind"ASSERT_VOP_UNLOCKED(" star "a->a_"arg", \""uname" "pos" ("arg")\");");
81		else if (lockdata[name, arg, pos] == "E")
82			printc(ind"ASSERT_VOP_ELOCKED(" star "a->a_"arg", \""uname" "pos" ("arg")\");");
83		else if (0) {
84			# XXX More checks!
85		}
86	}
87}
88
89function add_debugpre(name)
90{
91	if (lockdata[name, "debugpre"]) {
92		printc("#ifdef DEBUG_VFS_LOCKS");
93		printc("\t"lockdata[name, "debugpre"]"(a);");
94		printc("#endif");
95	}
96}
97
98function add_debugpost(name)
99{
100	if (lockdata[name, "debugpost"]) {
101		printc("#ifdef DEBUG_VFS_LOCKS");
102		printc("\t"lockdata[name, "debugpost"]"(a, rc);");
103		printc("#endif");
104	}
105}
106
107function add_pre(name)
108{
109	if (lockdata[name, "pre"]) {
110		printc("\t"lockdata[name, "pre"]"(a);");
111	}
112}
113
114function add_post(name)
115{
116	if (lockdata[name, "post"]) {
117		printc("\t"lockdata[name, "post"]"(a, rc);");
118	}
119}
120
121function can_inline(name)
122{
123	if (lockdata[name, "pre"])
124		return 0;
125	if (lockdata[name, "post"])
126		return 0;
127	return 1;
128}
129
130function find_arg_with_type (type)
131{
132	for (jj = 0; jj < numargs; jj++) {
133		if (types[jj] == type) {
134			return "VOPARG_OFFSETOF(struct " \
135			    name "_args,a_" args[jj] ")";
136		}
137	}
138
139	return "VDESC_NO_OFFSET";
140}
141
142BEGIN{
143
144# Process the command line
145for (i = 1; i < ARGC; i++) {
146	arg = ARGV[i];
147	if (arg !~ /^-[chpq]+$/ && arg !~ /\.src$/)
148		usage();
149	if (arg ~ /^-.*c/)
150		cfile = "vnode_if.c";
151	if (arg ~ /^-.*h/)
152		hfile = "vnode_if.h";
153	if (arg ~ /^-.*p/)
154		pfile = "vnode_if_newproto.h";
155	if (arg ~ /^-.*q/)
156		qfile = "vnode_if_typedef.h";
157	if (arg ~ /\.src$/)
158		srcfile = arg;
159}
160ARGC = 1;
161
162if (!cfile && !hfile && !pfile && !qfile)
163	exit 0;
164
165if (!srcfile)
166	usage();
167
168# Avoid a literal generated file tag here.
169generated = "@" "generated";
170
171common_head = \
172    "/*\n" \
173    " * This file is " generated " automatically.\n" \
174    " * Do not modify anything in here by hand.\n" \
175    " */\n" \
176    "\n";
177
178if (pfile) {
179	printp(common_head)
180	printp("struct vop_vector {")
181	printp("\tstruct vop_vector\t*vop_default;")
182	printp("\tvop_bypass_t\t*vop_bypass;")
183}
184
185if (qfile) {
186	printq(common_head)
187}
188
189if (hfile) {
190	printh(common_head "extern struct vnodeop_desc vop_default_desc;");
191	printh("#include \"vnode_if_typedef.h\"")
192	printh("#include \"vnode_if_newproto.h\"")
193}
194
195if (cfile) {
196	printc(common_head \
197	    "#include <sys/param.h>\n" \
198	    "#include <sys/event.h>\n" \
199	    "#include <sys/kernel.h>\n" \
200	    "#include <sys/mount.h>\n" \
201	    "#include <sys/sdt.h>\n" \
202	    "#include <sys/signalvar.h>\n" \
203	    "#include <sys/systm.h>\n" \
204	    "#include <sys/vnode.h>\n" \
205	    "\n" \
206	    "SDT_PROVIDER_DECLARE(vfs);\n" \
207	    "\n" \
208	    "struct vnodeop_desc vop_default_desc = {\n" \
209	    "	\"default\",\n" \
210	    "	0,\n" \
211	    "   0,\n" \
212	    "	(vop_bypass_t *)vop_panic,\n" \
213	    "	NULL,\n" \
214	    "	VDESC_NO_OFFSET,\n" \
215	    "	VDESC_NO_OFFSET,\n" \
216	    "	VDESC_NO_OFFSET,\n" \
217	    "	VDESC_NO_OFFSET,\n" \
218	    "};\n");
219}
220
221while ((getline < srcfile) > 0) {
222	fnr++;
223	if (NF == 0)
224		continue;
225	if ($1 ~ /^%%/) {
226		if (NF != 6 ||
227		    $2 !~ /^[a-z_]+$/  ||  $3 !~ /^[a-z]+$/  ||
228		    $4 !~ /^.$/  ||  $5 !~ /^.$/  ||  $6 !~ /^.$/) {
229			die("Invalid %s construction", "%%");
230			continue;
231		}
232		lockdata["vop_" $2, $3, "Entry"] = $4;
233		lockdata["vop_" $2, $3, "OK"]    = $5;
234		lockdata["vop_" $2, $3, "Error"] = $6;
235		continue;
236	}
237
238	if ($1 ~ /^%!/) {
239		if (NF != 4 ||
240		    ($3 != "pre" && $3 != "post" &&
241		     $3 != "debugpre" && $3 != "debugpost")) {
242			die("Invalid %s construction", "%!");
243			continue;
244		}
245		lockdata["vop_" $2, $3] = $4;
246		continue;
247	}
248	if ($1 ~ /^#/)
249		continue;
250
251	# Get the function name.
252	name = $1;
253	uname = toupper(name);
254
255	# Get the function arguments.
256	for (numargs = 0; ; ++numargs) {
257		if ((getline < srcfile) <= 0) {
258			die("Unable to read through the arguments for \"%s\"",
259			    name);
260		}
261		fnr++;
262		if ($1 ~ /^\};/)
263			break;
264
265		# Delete comments, if any.
266		gsub (/\/\*.*\*\//, "");
267
268		# Condense whitespace and delete leading/trailing space.
269		gsub(/[[:space:]]+/, " ");
270		sub(/^ /, "");
271		sub(/ $/, "");
272
273		# Pick off direction.
274		if ($1 != "INOUT" && $1 != "IN" && $1 != "OUT")
275			die("No IN/OUT direction for \"%s\".", $0);
276		dirs[numargs] = $1;
277		sub(/^[A-Z]* /, "");
278
279		if ((reles[numargs] = $1) == "WILLRELE")
280			sub(/^[A-Z]* /, "");
281		else
282			reles[numargs] = "WONTRELE";
283
284		# kill trailing ;
285		if (sub(/;$/, "") < 1)
286			die("Missing end-of-line ; in \"%s\".", $0);
287
288		# pick off variable name
289		if ((argp = match($0, /[A-Za-z0-9_]+$/)) < 1)
290			die("Missing var name \"a_foo\" in \"%s\".", $0);
291		args[numargs] = substr($0, argp);
292		$0 = substr($0, 1, argp - 1);
293
294		# what is left must be type
295		# remove trailing space (if any)
296		sub(/ $/, "");
297		types[numargs] = $0;
298	}
299	if (numargs > 4)
300		ctrargs = 4;
301	else
302		ctrargs = numargs;
303	ctrstr = ctrargs "(KTR_VOP, \"VOP\", \"" uname "\", (uintptr_t)a,\n\t    ";
304	ctrstr = ctrstr "\"" args[0] ":0x%jX\", (uintptr_t)a->a_" args[0];
305	for (i = 1; i < ctrargs; ++i)
306		ctrstr = ctrstr ", \"" args[i] ":0x%jX\", a->a_" args[i];
307	ctrstr = ctrstr ");";
308
309	if (pfile) {
310		printp("\t"name"_t\t*"name";")
311	}
312	if (qfile) {
313		printq("struct "name"_args;")
314		printq("typedef int "name"_t(struct "name"_args *);\n")
315	}
316
317	if (hfile) {
318		# Print out the vop_F_args structure.
319		printh("struct "name"_args {\n\tstruct vop_generic_args a_gen;");
320		for (i = 0; i < numargs; ++i)
321			printh("\t" t_spc(types[i]) "a_" args[i] ";");
322		printh("};");
323		printh("");
324
325		# Print out extern declaration.
326		printh("extern struct vnodeop_desc " name "_desc;");
327		printh("");
328
329		# Print out function prototypes.
330		printh("int " uname "_AP(struct " name "_args *);");
331		printh("int " uname "_APV(struct vop_vector *vop, struct " name "_args *);");
332		printh("");
333		printh("static __inline int " uname "(");
334		for (i = 0; i < numargs; ++i) {
335			printh("\t" t_spc(types[i]) args[i] \
336			    (i < numargs - 1 ? "," : ")"));
337		}
338		printh("{");
339		printh("\tstruct " name "_args a;");
340		printh("");
341		printh("\ta.a_gen.a_desc = &" name "_desc;");
342		for (i = 0; i < numargs; ++i)
343			printh("\ta.a_" args[i] " = " args[i] ";");
344		if (can_inline(name)) {
345			printh("\n#if !defined(DEBUG_VFS_LOCKS) && !defined(INVARIANTS) && !defined(KTR)");
346			printh("\tif (!SDT_PROBES_ENABLED())");
347			printh("\t\treturn (" args[0]"->v_op->"name"(&a));");
348			printh("\telse");
349			printh("\t\treturn (" uname "_APV("args[0]"->v_op, &a));");
350			printh("#else");
351		}
352		printh("\treturn (" uname "_APV("args[0]"->v_op, &a));");
353		if (can_inline(name))
354			printh("#endif");
355
356		printh("}");
357
358		printh("");
359	}
360
361	if (cfile) {
362		funcarr[name] = 1;
363		# Print out the vop_F_vp_offsets structure.  This all depends
364		# on naming conventions and nothing else.
365		printc("static int " name "_vp_offsets[] = {");
366		# as a side effect, figure out the releflags
367		releflags = "";
368		vpnum = 0;
369		for (i = 0; i < numargs; i++) {
370			if (types[i] == "struct vnode *") {
371				printc("\tVOPARG_OFFSETOF(struct " name \
372				    "_args,a_" args[i] "),");
373				if (reles[i] == "WILLRELE") {
374					releflags = releflags \
375					    "|VDESC_VP" vpnum "_WILLRELE";
376				}
377				vpnum++;
378			}
379		}
380
381		sub(/^\|/, "", releflags);
382		printc("\tVDESC_NO_OFFSET");
383		printc("};");
384
385		printc("\n");
386		printc("SDT_PROBE_DEFINE2(vfs, vop, " name ", entry, \"struct vnode *\", \"struct " name "_args *\");\n");
387		printc("SDT_PROBE_DEFINE3(vfs, vop, " name ", return, \"struct vnode *\", \"struct " name "_args *\", \"int\");\n");
388
389		# Print out function.
390		printc("\nint\n" uname "_AP(struct " name "_args *a)");
391		printc("{");
392		printc("");
393		printc("\treturn(" uname "_APV(a->a_" args[0] "->v_op, a));");
394		printc("}");
395		printc("\nint\n" uname "_APV(struct vop_vector *vop, struct " name "_args *a)");
396		printc("{");
397		printc("\tint rc;");
398		printc("");
399		printc("\tVNASSERT(a->a_gen.a_desc == &" name "_desc, a->a_" args[0]",");
400		printc("\t    (\"Wrong a_desc in " name "(%p, %p)\", a->a_" args[0]", a));");
401		printc("\tVNASSERT(vop != NULL, a->a_" args[0]", (\"No "name"(%p, %p)\", a->a_" args[0]", a));")
402		printc("\tKTR_START" ctrstr);
403		add_debugpre(name);
404		add_pre(name);
405		for (i = 0; i < numargs; ++i)
406			add_debug_code(name, args[i], "Entry", "\t");
407		printc("\tif (!SDT_PROBES_ENABLED()) {");
408		printc("\t\trc = vop->"name"(a);")
409		printc("\t} else {")
410		printc("\t\tSDT_PROBE2(vfs, vop, " name ", entry, a->a_" args[0] ", a);");
411		printc("\t\trc = vop->"name"(a);")
412		printc("\t\tSDT_PROBE3(vfs, vop, " name ", return, a->a_" args[0] ", a, rc);");
413		printc("\t}")
414		printc("\tif (rc == 0) {");
415		for (i = 0; i < numargs; ++i)
416			add_debug_code(name, args[i], "OK", "\t\t");
417		printc("\t} else {");
418		for (i = 0; i < numargs; ++i)
419			add_debug_code(name, args[i], "Error", "\t\t");
420		printc("\t}");
421		add_post(name);
422		add_debugpost(name);
423		printc("\tKTR_STOP" ctrstr);
424		printc("\treturn (rc);");
425		printc("}\n");
426
427		# Print out the vnodeop_desc structure.
428		printc("struct vnodeop_desc " name "_desc = {");
429		# printable name
430		printc("\t\"" name "\",");
431		# flags
432		vppwillrele = "";
433		for (i = 0; i < numargs; i++) {
434			if (types[i] == "struct vnode **" && \
435			    reles[i] == "WILLRELE") {
436				vppwillrele = "|VDESC_VPP_WILLRELE";
437			}
438		}
439
440		if (!releflags)
441			releflags = "0";
442		printc("\t" releflags vppwillrele ",");
443
444		# index in struct vop_vector
445		printc("\t__offsetof(struct vop_vector, " name "),");
446		# function to call
447		printc("\t(vop_bypass_t *)" uname "_AP,");
448		# vp offsets
449		printc("\t" name "_vp_offsets,");
450		# vpp (if any)
451		printc("\t" find_arg_with_type("struct vnode **") ",");
452		# cred (if any)
453		printc("\t" find_arg_with_type("struct ucred *") ",");
454		# thread (if any)
455		printc("\t" find_arg_with_type("struct thread *") ",");
456		# componentname
457		printc("\t" find_arg_with_type("struct componentname *") ",");
458		# transport layer information
459		printc("};\n");
460	}
461}
462
463if (cfile) {
464	printc("void");
465	printc("vfs_vector_op_register(struct vop_vector *orig_vop)");
466	printc("{");
467	printc("\tstruct vop_vector *vop;");
468	printc("");
469	printc("\tif (orig_vop->registered)");
470	printc("\t\tpanic(\"%s: vop_vector %p already registered\",")
471	printc("\t\t    __func__, orig_vop);");
472	printc("");
473	printc("\tcache_vop_vector_register(orig_vop);");
474	printc("");
475	for (name in funcarr) {
476		printc("\tvop = orig_vop;");
477		printc("\twhile (vop != NULL && \\");
478		printc("\t    vop->"name" == NULL && vop->vop_bypass == NULL)")
479		printc("\t\tvop = vop->vop_default;")
480		printc("\tif (vop != NULL)");
481		printc("\t\torig_vop->"name" = vop->"name";");
482		printc("");
483	}
484	printc("\tvop = orig_vop;");
485	printc("\twhile (vop != NULL && vop->vop_bypass == NULL)")
486	printc("\t\tvop = vop->vop_default;")
487	printc("\tif (vop != NULL)");
488	printc("\t\torig_vop->vop_bypass = vop->vop_bypass;");
489	printc("");
490	for (name in funcarr) {
491		printc("\tif (orig_vop->"name" == NULL)");
492		printc("\t\torig_vop->"name" = (void *)orig_vop->vop_bypass;");
493	}
494	printc("");
495	printc("\torig_vop->registered = true;");
496	printc("}")
497}
498
499if (hfile) {
500	printh("void vfs_vector_op_register(struct vop_vector *orig_vop);");
501}
502
503if (pfile) {
504	printp("\tbool\tregistered;")
505	printp("};")
506}
507
508if (hfile)
509	close(hfile);
510if (cfile)
511	close(cfile);
512if (pfile)
513	close(pfile);
514close(srcfile);
515
516exit 0;
517
518}
519