freebsd-dev/sys/tools/vnode_if.awk
Peter Wemm 4e61198e8f Make the vnode opv vector construction fully dynamic. Previously we
leaked memory on each unload and were limited to items referenced in
the kernel copy of vnode_if.c.  Now a kernel module is free to create
it's own VOP_FOO() routines and the rest of the system will happily
deal with it, including passthrough layers like union/umap/etc.

Have VFS_SET() call a common vfs_modevent() handler rather than
inline duplicating the common code all over the place.

Have VNODEOP_SET() have the vnodeops removed at unload time (assuming a
module) so that the vop_t ** vector is reclaimed.

Slightly adjust the vop_t ** vectors so that calling slot 0 is a panic
rather than a page fault.  This could happen if VOP_something() was called
without *any* handlers being present anywhere (including in vfs_default.c).
slot 1 becomes the default vector for the vnodeop table.

TODO: reclaim zones on unload (eg: nfs code)
1998-11-10 09:04:09 +00:00

403 lines
10 KiB
Awk

#!/bin/sh -
#
# Copyright (c) 1992, 1993
# The Regents of the University of California. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)vnode_if.sh 8.1 (Berkeley) 6/10/93
# $Id: vnode_if.sh,v 1.15 1998/07/04 20:45:32 julian Exp $
#
# Script to produce VFS front-end sugar.
#
# usage: vnode_if.sh srcfile
# (where srcfile is currently /sys/kern/vnode_if.src)
#
# These awk scripts are not particularly well written, specifically they
# don't use arrays well and figure out the same information repeatedly.
# Please rewrite them if you actually understand how to use awk. Note,
# they use nawk extensions and gawk's toupper.
if [ $# -ne 1 ] ; then
echo 'usage: vnode_if.sh srcfile'
exit 1
fi
# Name of the source file.
SRC=$1
# Names of the created files.
CFILE=vnode_if.c
HEADER=vnode_if.h
# Awk program (must support nawk extensions and gawk's "toupper")
# Use "awk" at Berkeley, "gawk" elsewhere.
AWK=awk
# Print out header information for vnode_if.h.
cat << END_OF_LEADING_COMMENT > $HEADER
/*
* This file is produced automatically.
* Do not modify anything in here by hand.
*
* Created from @(#)vnode_if.sh 8.1 (Berkeley) 6/10/93
*/
extern struct vnodeop_desc vop_default_desc;
END_OF_LEADING_COMMENT
# Awk script to take vnode_if.src and turn it into vnode_if.h.
$AWK '
NF == 0 || $0 ~ "^#" {
next;
}
{
# Get the function name.
name = $1;
uname = toupper(name);
# Get the function arguments.
for (c1 = 0;; ++c1) {
if (getline <= 0)
exit
if ($0 ~ "^};")
break;
a[c1] = $0;
}
# Print out the vop_F_args structure.
printf("struct %s_args {\n\tstruct vnodeop_desc *a_desc;\n",
name);
for (c2 = 0; c2 < c1; ++c2) {
c3 = split(a[c2], t);
printf("\t");
if (t[2] ~ "WILLRELE")
c4 = 3;
else
c4 = 2;
for (; c4 < c3; ++c4)
printf("%s ", t[c4]);
beg = match(t[c3], "[^*]");
printf("%sa_%s\n",
substr(t[c4], 0, beg - 1), substr(t[c4], beg));
}
printf("};\n");
# Print out extern declaration.
printf("extern struct vnodeop_desc %s_desc;\n", name);
# Print out prototype.
printf("static int %s __P((\n", uname);
sep = ",\n";
for (c2 = 0; c2 < c1; ++c2) {
if (c2 == c1 - 1)
sep = "));\n";
c3 = split(a[c2], t);
printf("\t");
if (t[2] ~ "WILLRELE")
c4 = 3;
else
c4 = 2;
for (; c4 < c3; ++c4)
printf("%s ", t[c4]);
beg = match(t[c3], "[^*]");
end = match(t[c3], ";");
printf("%s%s%s",
substr(t[c4], 0, beg - 1),
substr(t[c4], beg, end - beg), sep);
}
# Print out inline struct.
printf("static __inline int %s(", uname);
sep = ", ";
for (c2 = 0; c2 < c1; ++c2) {
if (c2 == c1 - 1)
sep = ")\n";
c3 = split(a[c2], t);
beg = match(t[c3], "[^*]");
end = match(t[c3], ";");
printf("%s%s", substr(t[c3], beg, end - beg), sep);
}
for (c2 = 0; c2 < c1; ++c2) {
c3 = split(a[c2], t);
printf("\t");
if (t[2] ~ "WILLRELE")
c4 = 3;
else
c4 = 2;
for (; c4 < c3; ++c4)
printf("%s ", t[c4]);
beg = match(t[c3], "[^*]");
printf("%s%s\n",
substr(t[c4], 0, beg - 1), substr(t[c4], beg));
}
printf("{\n\tstruct %s_args a;\n\n", name);
printf("\ta.a_desc = VDESC(%s);\n", name);
for (c2 = 0; c2 < c1; ++c2) {
c3 = split(a[c2], t);
printf("\t");
beg = match(t[c3], "[^*]");
end = match(t[c3], ";");
printf("a.a_%s = %s\n",
substr(t[c3], beg, end - beg), substr(t[c3], beg));
}
c1 = split(a[0], t);
beg = match(t[c1], "[^*]");
end = match(t[c1], ";");
printf("\treturn (VCALL(%s, VOFFSET(%s), &a));\n}\n",
substr(t[c1], beg, end - beg), name);
}' < $SRC >> $HEADER
# Print out header information for vnode_if.c.
cat << END_OF_LEADING_COMMENT > $CFILE
/*
* This file is produced automatically.
* Do not modify anything in here by hand.
*
* Created from @(#)vnode_if.sh 8.1 (Berkeley) 6/10/93
*/
#include <sys/param.h>
#include <sys/vnode.h>
struct vnodeop_desc vop_default_desc = {
1, /* special case, vop_default => 1 */
"default",
0,
NULL,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
NULL,
};
END_OF_LEADING_COMMENT
# Awk script to take vnode_if.src and turn it into vnode_if.c.
$AWK 'function kill_surrounding_ws (s) {
sub (/^[ \t]*/, "", s);
sub (/[ \t]*$/, "", s);
return s;
}
function read_args() {
numargs = 0;
while (getline ln) {
if (ln ~ /}/) {
break;
};
# Delete comments, if any.
gsub (/\/\*.*\*\//, "", ln);
# Delete leading/trailing space.
ln = kill_surrounding_ws(ln);
# Pick off direction.
if (1 == sub(/^INOUT[ \t]+/, "", ln))
dir = "INOUT";
else if (1 == sub(/^IN[ \t]+/, "", ln))
dir = "IN";
else if (1 == sub(/^OUT[ \t]+/, "", ln))
dir = "OUT";
else
bail("No IN/OUT direction for \"" ln "\".");
# check for "WILLRELE"
if (1 == sub(/^WILLRELE[ \t]+/, "", ln)) {
rele = "WILLRELE";
} else {
rele = "WONTRELE";
};
# kill trailing ;
if (1 != sub (/;$/, "", ln)) {
bail("Missing end-of-line ; in \"" ln "\".");
};
# pick off variable name
if (!(i = match(ln, /[A-Za-z0-9_]+$/))) {
bail("Missing var name \"a_foo\" in \"" ln "\".");
};
arg = substr (ln, i);
# Want to <<substr(ln, i) = "";>>, but nawk cannot.
# Hack around this.
ln = substr(ln, 1, i-1);
# what is left must be type
# (put clean it up some)
type = ln;
gsub (/[ \t]+/, " ", type); # condense whitespace
type = kill_surrounding_ws(type);
# (boy this was easier in Perl)
numargs++;
dirs[numargs] = dir;
reles[numargs] = rele;
types[numargs] = type;
args[numargs] = arg;
};
}
function generate_operation_vp_offsets() {
printf ("static int %s_vp_offsets[] = {\n", name);
# as a side effect, figure out the releflags
releflags = "";
vpnum = 0;
for (i=1; i<=numargs; i++) {
if (types[i] == "struct vnode *") {
printf ("\tVOPARG_OFFSETOF(struct %s_args,a_%s),\n",
name, args[i]);
if (reles[i] == "WILLRELE") {
releflags = releflags "|VDESC_VP" vpnum "_WILLRELE";
};
vpnum++;
};
};
sub (/^\|/, "", releflags);
print "\tVDESC_NO_OFFSET";
print "};";
}
function find_arg_with_type (type) {
for (i=1; i<=numargs; i++) {
if (types[i] == type) {
return "VOPARG_OFFSETOF(struct " name "_args,a_" args[i] ")";
};
};
return "VDESC_NO_OFFSET";
}
function generate_operation_desc() {
printf ("struct vnodeop_desc %s_desc = {\n", name);
# offset
printf ("\t0,\n");
# printable name
printf ("\t\"%s\",\n", name);
# flags
vppwillrele = "";
for (i=1; i<=numargs; i++) {
if (types[i] == "struct vnode **" &&
(reles[i] == "WILLRELE")) {
vppwillrele = "|VDESC_VPP_WILLRELE";
};
};
if (releflags == "") {
printf ("\t0%s,\n", vppwillrele);
} else {
printf ("\t%s%s,\n", releflags, vppwillrele);
};
# vp offsets
printf ("\t%s_vp_offsets,\n", name);
# vpp (if any)
printf ("\t%s,\n", find_arg_with_type("struct vnode **"));
# cred (if any)
printf ("\t%s,\n", find_arg_with_type("struct ucred *"));
# proc (if any)
printf ("\t%s,\n", find_arg_with_type("struct proc *"));
# componentname
printf ("\t%s,\n", find_arg_with_type("struct componentname *"));
# transport layer information
printf ("\tNULL,\n};\n");
}
NF == 0 || $0 ~ "^#" {
next;
}
{
# get the function name
name = $1;
# get the function arguments
read_args();
# Print out the vop_F_vp_offsets structure. This all depends
# on naming conventions and nothing else.
generate_operation_vp_offsets();
# Print out the vnodeop_desc structure.
generate_operation_desc();
printf "\n";
}' < $SRC >> $CFILE
# THINGS THAT DON'T WORK RIGHT YET.
#
# Two existing BSD vnodeops (bwrite and strategy) don't take any vnodes as
# arguments. This means that these operations can't function successfully
# through a bypass routine.
#
# Bwrite and strategy will be replaced when the VM page/buffer cache
# integration happens.
#
# To get around this problem for now we handle these ops as special cases.
cat << END_OF_SPECIAL_CASES >> $HEADER
#include <sys/buf.h>
struct vop_bwrite_args {
struct vnodeop_desc *a_desc;
struct buf *a_bp;
};
extern struct vnodeop_desc vop_bwrite_desc;
static int VOP_BWRITE __P((
struct buf *bp));
static __inline int VOP_BWRITE(bp)
struct buf *bp;
{
struct vop_bwrite_args a;
a.a_desc = VDESC(vop_bwrite);
a.a_bp = bp;
return (VCALL((bp)->b_vp, VOFFSET(vop_bwrite), &a));
}
extern int vfs_opv_numops;
END_OF_SPECIAL_CASES
cat << END_OF_SPECIAL_CASES >> $CFILE
static int vop_bwrite_vp_offsets[] = {
VDESC_NO_OFFSET
};
struct vnodeop_desc vop_bwrite_desc = {
0,
"vop_bwrite",
0,
vop_bwrite_vp_offsets,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
NULL,
};
END_OF_SPECIAL_CASES