freebsd-nq/sys/kern/vnode_if.pl
David Greenman 083c109df6 The generated VCALL always uses the first vp which in the case of /link/
might not be handled by the same FS as the directory (e.g. special device
files)...so it must be special-cased. This bug is seen when doing
"ln /dev/console /dev/foo" or equivilent and first appeared after I fixed
the argument order of VOP_LINK.  YUCK! There really needs to be a way of
specifying what vp to use in the VCALL; doing this could fix the strategy
and bwrite special-cases, too.
1995-07-07 13:41:28 +00:00

473 lines
12 KiB
Bash

#!/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.2 1994/08/02 07:43:34 davidg 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 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/mount.h>
#include <sys/vnode.h>
struct vnodeop_desc vop_default_desc = {
0,
"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 ("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_strategy_args {
struct vnodeop_desc *a_desc;
struct buf *a_bp;
};
extern struct vnodeop_desc vop_strategy_desc;
static inline int VOP_STRATEGY(bp)
struct buf *bp;
{
struct vop_strategy_args a;
a.a_desc = VDESC(vop_strategy);
a.a_bp = bp;
return (VCALL((bp)->b_vp, VOFFSET(vop_strategy), &a));
}
struct vop_bwrite_args {
struct vnodeop_desc *a_desc;
struct buf *a_bp;
};
extern struct vnodeop_desc vop_bwrite_desc;
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));
}
struct vop_link_args {
struct vnodeop_desc *a_desc;
struct vnode *a_vp;
struct vnode *a_tdvp;
struct componentname *a_cnp;
};
extern struct vnodeop_desc vop_link_desc;
static inline int VOP_LINK(vp, tdvp, cnp)
struct vnode *vp;
struct vnode *tdvp;
struct componentname *cnp;
{
struct vop_link_args a;
a.a_desc = VDESC(vop_link);
a.a_vp = vp;
a.a_tdvp = tdvp;
a.a_cnp = cnp;
return (VCALL(tdvp, VOFFSET(vop_link), &a));
}
END_OF_SPECIAL_CASES
cat << END_OF_SPECIAL_CASES >> $CFILE
int vop_strategy_vp_offsets[] = {
VDESC_NO_OFFSET
};
struct vnodeop_desc vop_strategy_desc = {
0,
"vop_strategy",
0,
vop_strategy_vp_offsets,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
NULL,
};
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,
};
int vop_link_vp_offsets[] = {
VOPARG_OFFSETOF(struct vop_link_args,a_vp),
VOPARG_OFFSETOF(struct vop_link_args,a_tdvp),
VDESC_NO_OFFSET
};
struct vnodeop_desc vop_link_desc = {
0,
"vop_link",
VDESC_VP1_WILLRELE,
vop_link_vp_offsets,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VOPARG_OFFSETOF(struct vop_link_args,a_cnp),
NULL,
};
END_OF_SPECIAL_CASES
# Add the vfs_op_descs array to the C file.
$AWK '
BEGIN {
printf("\nstruct vnodeop_desc *vfs_op_descs[] = {\n");
printf("\t&vop_default_desc, /* MUST BE FIRST */\n");
printf("\t&vop_strategy_desc, /* XXX: SPECIAL CASE */\n");
printf("\t&vop_bwrite_desc, /* XXX: SPECIAL CASE */\n");
printf("\t&vop_link_desc, /* XXX: SPECIAL CASE */\n");
}
END {
printf("\tNULL\n};\n");
}
NF == 0 || $0 ~ "^#" {
next;
}
{
# Get the function name.
printf("\t&%s_desc,\n", $1);
# Skip the function arguments.
for (;;) {
if (getline <= 0)
exit
if ($0 ~ "^};")
break;
}
}' < $SRC >> $CFILE