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