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.69 2020/02/23 22:14:04 ad 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=0 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 beween * 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 willmake=-1; 103 fstrans=""; 104 next; 105} 106# Last line of description 107/^}/ { 108 doit(); 109 next; 110} 111# Middle lines of description 112{ 113 if ($1 == "VERSION") { 114 args_name=args_name "_v" $2; 115 next; 116 } else if ($1 ~ "^FSTRANS=") { 117 fstrans = $1; 118 sub("FSTRANS=", "", fstrans); 119 next; 120 } 121 122 argdir[argc] = $1; i=2; 123 124 if ($2 == "LOCKED=YES") { 125 lockstate[argc] = 1; 126 i++; 127 } else if ($2 == "LOCKED=NO") { 128 lockstate[argc] = 0; 129 i++; 130 } else 131 lockstate[argc] = -1; 132 133 if ($2 == "WILLRELE" || 134 $3 == "WILLRELE") { 135 willrele[argc] = 1; 136 i++; 137 } else if ($2 == "WILLPUT" || 138 $3 == "WILLPUT") { 139 willrele[argc] = 3; 140 i++; 141 } else 142 willrele[argc] = 0; 143 144 if ($2 == "WILLMAKE") { 145 willmake=argc; 146 i++; 147 } 148 if (argc == 0 && fstrans == "") { 149 if (lockstate[0] == 1) 150 fstrans = "NO"; 151 else 152 fstrans = "YES"; 153 } 154 155 # XXX: replace non-portable types for rump. We should really 156 # nuke the types from the kernel, but that is a battle for 157 # another day. 158 at = $i; 159 if (rump) { 160 if (at == "vm_prot_t") 161 at = "int"; 162 if (at == "voff_t") 163 at = "off_t"; 164 if (at == "kauth_cred_t") 165 at = "struct kauth_cred *" 166 if (at == "daddr_t") 167 at = "int64_t" 168 } 169 argtype[argc] = at; 170 i++; 171 while (i < NF) { 172 argtype[argc] = argtype[argc]" "$i; 173 i++; 174 } 175 argname[argc] = $i; 176 argc++; 177 next; 178} 179' 180 181# This is put before the copyright on each generated file. 182warning="\ 183/* @NetBSD@ */ 184 185/* 186 * Warning: DO NOT EDIT! This file is automatically generated! 187 * (Modifications made here may easily be lost!) 188 * 189 * Created from the file: 190 * ${SRC_ID} 191 * by the script: 192 * ${SCRIPT_ID} 193 */ 194" 195 196# This is to satisfy McKusick (get rid of evil spaces 8^) 197anal_retentive='s:\([^/]\*\) :\1:g' 198 199do_hfile () { 200# 201# Redirect stdout to the H file. 202# 203echo "$0: Creating $1" 1>&2 204exec > $1 205rump=$2 206 207# Begin stuff 208if [ -z "${rump}" ]; then 209 SYS='SYS_' 210else 211 SYS='RUMP_RUMP' 212fi 213echo -n "$warning" | sed -e 's/\$//g;s/@/\$/g;s/ $//' 214echo "" 215echo -n "$copyright" 216echo '' 217echo "#ifndef _${SYS}VNODE_IF_H_" 218echo "#define _${SYS}VNODE_IF_H_" 219if [ ${lockdebug} -ne 0 ] ; then 220 echo '' 221 echo '#ifdef _KERNEL_OPT' 222 echo '#include "opt_vnode_lockdebug.h"' 223 echo '#endif /* _KERNEL_OPT */' 224fi 225[ -z "${rump}" ] && echo " 226extern const struct vnodeop_desc ${rump}vop_default_desc;" 227echo 228 229# Body stuff 230# This awk program needs toupper() so define it if necessary. 231sed -e "$sed_prep" $src | $awk -v rump=${rump} "$toupper"' 232function doit() { 233 name = rump name 234 # Declare arg struct, descriptor. 235 if (!rump) { 236 printf("\n#define %s_DESCOFFSET %d\n", 237 toupper(name), vop_offset++); 238 printf("struct %s_args {\n", args_name); 239 printf("\tconst struct vnodeop_desc * a_desc;\n"); 240 for (i=0; i<argc; i++) { 241 printf("\t%s a_%s;\n", argtype[i], argname[i]); 242 } 243 printf("};\n"); 244 printf("extern const struct vnodeop_desc %s_desc;\n", name); 245 } 246 # Prototype it. 247 protoarg = sprintf("int %s(", toupper(name)); 248 protolen = length(protoarg); 249 printf("%s", protoarg); 250 for (i=0; i<argc; i++) { 251 protoarg = sprintf("%s", argtype[i]); 252 if (i < (argc-1)) protoarg = (protoarg ", "); 253 arglen = length(protoarg); 254 if ((protolen + arglen) > 77) { 255 protoarg = ("\n " protoarg); 256 arglen += 4; 257 protolen = 0; 258 } 259 printf("%s", protoarg); 260 protolen += arglen; 261 } 262 printf(");\n"); 263} 264BEGIN { 265 vop_offset = 1; # start at 1, to count the 'default' op 266 267 printf("struct buf;\n"); 268 if (rump) { 269 printf("struct flock;\n"); 270 printf("struct knote;\n"); 271 printf("struct vm_page;\n"); 272 } 273 printf("\n#ifndef _KERNEL\n#include <stdbool.h>\n#endif\n"); 274 if (rump) 275 printf("\n"); 276} 277END { 278 if (!rump) { 279 printf("\n#define VNODE_OPS_COUNT\t%d\n", vop_offset); 280 } 281} 282'"$awk_parser" | sed -e "$anal_retentive" 283 284# End stuff 285echo '' 286echo "#endif /* !_${SYS}VNODE_IF_H_ */" 287} 288do_hfile $out_h '' 289do_hfile $out_rumph 'rump_' 290 291do_cfile () { 292# 293# Redirect stdout to the C file. 294# 295echo "$0: Creating $1" 1>&2 296exec > $1 297rump=$2 298 299# Begin stuff 300echo -n "$warning" | sed -e 's/\$//g;s/@/\$/g;s/ $//' 301echo "" 302echo -n "$copyright" 303echo " 304#include <sys/cdefs.h> 305__KERNEL_RCSID(0, \"\$NetBSD\$\");" 306 307[ ${lockdebug} -ne 0 ] && echo && echo '#include "opt_vnode_lockdebug.h"' 308 309echo ' 310#include <sys/param.h> 311#include <sys/mount.h> 312#include <sys/buf.h> 313#include <sys/vnode.h> 314#include <sys/lock.h>' 315[ -z "${rump}" ] && echo '#include <sys/fstrans.h>' 316[ ! -z "${rump}" ] && echo '#include <rump/rumpvnode_if.h>' \ 317 && echo '#include <rump-sys/kern.h>' 318 319if [ -z "${rump}" ] ; then 320 echo " 321enum fst_op { FST_NO, FST_YES, FST_LAZY, FST_TRY }; 322 323static inline int 324vop_pre(vnode_t *vp, struct mount **mp, bool *mpsafe, enum fst_op op) 325{ 326 int error; 327 328 *mpsafe = (vp->v_vflag & VV_MPSAFE); 329 330 if (!*mpsafe) { 331 KERNEL_LOCK(1, curlwp); 332 } 333 334 if (op == FST_YES || op == FST_LAZY || op == FST_TRY) { 335 for (;;) { 336 *mp = vp->v_mount; 337 if (op == FST_TRY) { 338 error = fstrans_start_nowait(*mp); 339 if (error) { 340 if (!*mpsafe) { 341 KERNEL_UNLOCK_ONE(curlwp); 342 } 343 return error; 344 } 345 } else if (op == FST_LAZY) { 346 fstrans_start_lazy(*mp); 347 } else { 348 fstrans_start(*mp); 349 } 350 if (__predict_true(*mp == vp->v_mount)) 351 break; 352 fstrans_done(*mp); 353 } 354 } else { 355 *mp = vp->v_mount; 356 } 357 358 return 0; 359} 360 361static inline void 362vop_post(vnode_t *vp, struct mount *mp, bool mpsafe, enum fst_op op) 363{ 364 365 if (op == FST_YES || op == FST_LAZY) { 366 fstrans_done(mp); 367 } 368 369 if (!mpsafe) { 370 KERNEL_UNLOCK_ONE(curlwp); 371 } 372} 373 374const struct vnodeop_desc vop_default_desc = {" 375echo ' 0, 376 "default", 377 0, 378 NULL, 379 VDESC_NO_OFFSET, 380 VDESC_NO_OFFSET, 381 VDESC_NO_OFFSET, 382}; 383' 384fi 385 386# Body stuff 387sed -e "$sed_prep" $src | $awk -v rump=${rump} -v lockdebug=${lockdebug} ' 388function do_offset(typematch) { 389 for (i=0; i<argc; i++) { 390 if (argtype[i] == typematch) { 391 printf("\tVOPARG_OFFSETOF(struct %s_args, a_%s),\n", 392 args_name, argname[i]); 393 return i; 394 }; 395 }; 396 print "\tVDESC_NO_OFFSET,"; 397 return -1; 398} 399 400function offsets() { 401 # Define offsets array 402 printf("const int %s_vp_offsets[] = {\n", name); 403 for (i=0; i<argc; i++) { 404 if (argtype[i] == "struct vnode *") { 405 printf ("\tVOPARG_OFFSETOF(struct %s_args,a_%s),\n", 406 args_name, argname[i]); 407 } 408 } 409 print "\tVDESC_NO_OFFSET"; 410 print "};"; 411 # Define F_desc 412 printf("const struct vnodeop_desc %s_desc = {\n", name); 413 # offset 414 printf ("\t%s_DESCOFFSET,\n", toupper(name)); 415 # printable name 416 printf ("\t\"%s\",\n", name); 417 # flags 418 printf("\t0"); 419 vpnum = 0; 420 for (i=0; i<argc; i++) { 421 if (willrele[i]) { 422 if (willrele[i] == 3) { 423 word = "PUT"; 424 } else { 425 word = "RELE"; 426 } 427 printf(" | VDESC_VP%s_WILL%s", vpnum, word); 428 } 429 if (argtype[i] == "struct vnode *") 430 vpnum++; 431 } 432 print ","; 433 # vp offsets 434 printf ("\t%s_vp_offsets,\n", name); 435 # vpp (if any) 436 do_offset("struct vnode **"); 437 # cred (if any) 438 do_offset("kauth_cred_t"); 439 # componentname 440 do_offset("struct componentname *"); 441 printf ("};\n"); 442} 443 444function bodyrump() { 445 printf("{\n\tint error;\n\n"); 446 printf("\trump_schedule();\n"); 447 printf("\terror = %s(", toupper(name)); 448 for (i=0; i<argc; i++) { 449 printf("%s", argname[i]); 450 if (i < (argc-1)) printf(", "); 451 } 452 printf(");\n"); 453 printf("\trump_unschedule();\n\n"); 454 printf("\treturn error;\n}\n"); 455} 456 457function bodynorm() { 458 printf("{\n\tint error;\n\tbool mpsafe;\n\tstruct %s_args a;\n", 459 args_name); 460 printf("\tstruct mount *mp;\n"); 461 if (lockdebug) { 462 printf("#ifdef VNODE_LOCKDEBUG\n"); 463 for (i=0; i<argc; i++) { 464 if (lockstate[i] != -1) 465 printf("\tint islocked_%s;\n", argname[i]); 466 } 467 printf("#endif\n"); 468 } 469 printf("\ta.a_desc = VDESC(%s);\n", name); 470 for (i=0; i<argc; i++) { 471 printf("\ta.a_%s = %s;\n", argname[i], argname[i]); 472 if (lockdebug && lockstate[i] != -1) { 473 printf("#ifdef VNODE_LOCKDEBUG\n"); 474 printf("\tislocked_%s = (%s->v_vflag & VV_LOCKSWORK) ? (VOP_ISLOCKED(%s) == LK_EXCLUSIVE) : %d;\n", 475 argname[i], argname[i], argname[i], lockstate[i]); 476 printf("\tif (islocked_%s != %d)\n", argname[i], 477 lockstate[i]); 478 printf("\t\tpanic(\"%s: %s: locked %%d, expected %%d\", islocked_%s, %d);\n", name, argname[i], argname[i], lockstate[i]); 479 printf("#endif\n"); 480 } 481 } 482 if (fstrans == "LOCK") 483 printf("\terror = vop_pre(%s, &mp, &mpsafe, %s);\n", 484 argname[0], "(!(flags & (LK_SHARED|LK_EXCLUSIVE)) ? FST_NO : (flags & LK_NOWAIT ? FST_TRY : FST_YES))"); 485 else if (fstrans == "UNLOCK") 486 printf("\terror = vop_pre(%s, &mp, &mpsafe, FST_%s);\n", 487 argname[0], "NO"); 488 else 489 printf("\terror = vop_pre(%s, &mp, &mpsafe, FST_%s);\n", 490 argname[0], fstrans); 491 printf("\tif (error)\n\t\treturn error;\n"); 492 printf("\terror = (VCALL(%s, VOFFSET(%s), &a));\n", 493 argname[0], name); 494 if (fstrans == "LOCK") 495 printf("\tvop_post(%s, mp, mpsafe, %s);\n", 496 argname[0], "(flags & (LK_UPGRADE|LK_DOWNGRADE) ? FST_NO : (error ? FST_YES : FST_NO))"); 497 else if (fstrans == "UNLOCK") 498 printf("\tvop_post(%s, mp, mpsafe, FST_%s);\n", 499 argname[0], "YES"); 500 else 501 printf("\tvop_post(%s, mp, mpsafe, FST_%s);\n", 502 argname[0], fstrans); 503 if (willmake != -1) { 504 printf("#ifdef DIAGNOSTIC\n"); 505 printf("\tif (error == 0)\n" \ 506 "\t\tKASSERT((*%s)->v_size != VSIZENOTSET\n" \ 507 "\t\t && (*%s)->v_writesize != VSIZENOTSET);\n", 508 argname[willmake], argname[willmake]); 509 printf("#endif /* DIAGNOSTIC */\n"); 510 } 511 printf("\treturn error;\n}\n"); 512} 513 514function doit() { 515 printf("\n"); 516 if (!rump) 517 offsets(); 518 519 if (rump) 520 extname = "RUMP_" toupper(name); 521 else 522 extname = toupper(name); 523 524 # Define function. 525 printf("int\n%s(", extname); 526 for (i=0; i<argc; i++) { 527 printf("%s %s", argtype[i], argname[i]); 528 if (i < (argc-1)) printf(",\n "); 529 } 530 printf(")\n"); 531 532 if (rump) 533 bodyrump(); 534 else 535 bodynorm(); 536} 537BEGIN { 538 # start from 1 (vop_default is at 0) 539 argc=1; 540} 541'"$awk_parser" | sed -e "$anal_retentive" 542 543# End stuff 544[ -n "${rump}" ] && return 545 546# Add the vfs_op_descs array to the C file. 547# Begin stuff 548echo " 549const struct vnodeop_desc * const ${rump}vfs_op_descs[] = { 550 &${rump}vop_default_desc, /* MUST BE FIRST */ 551" 552 553# Body stuff 554sed -e "$sed_prep" $src | $awk -v rump=${rump} ' 555function doit() { 556 printf("\t&%s_desc,\n", name); 557} 558'"$awk_parser" 559 560# End stuff 561echo ' NULL 562};' 563} 564do_cfile $out_c '' 565do_cfile $out_rumpc 'rump_' 566 567exit 0 568 569# Local Variables: 570# tab-width: 4 571# End: 572