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.66 2017/06/04 08:03:26 hannken 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_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_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 { 346 fstrans_start(*mp); 347 } 348 if (__predict_true(*mp == vp->v_mount)) 349 break; 350 fstrans_done(*mp); 351 } 352 } else { 353 *mp = vp->v_mount; 354 } 355 356 return 0; 357} 358 359static inline void 360vop_post(vnode_t *vp, struct mount *mp, bool mpsafe, enum fst_op op) 361{ 362 363 if (op == FST_YES) { 364 fstrans_done(mp); 365 } 366 367 if (!mpsafe) { 368 KERNEL_UNLOCK_ONE(curlwp); 369 } 370} 371 372const struct vnodeop_desc vop_default_desc = {" 373echo ' 0, 374 "default", 375 0, 376 NULL, 377 VDESC_NO_OFFSET, 378 VDESC_NO_OFFSET, 379 VDESC_NO_OFFSET, 380}; 381' 382fi 383 384# Body stuff 385sed -e "$sed_prep" $src | $awk -v rump=${rump} -v lockdebug=${lockdebug} ' 386function do_offset(typematch) { 387 for (i=0; i<argc; i++) { 388 if (argtype[i] == typematch) { 389 printf("\tVOPARG_OFFSETOF(struct %s_args, a_%s),\n", 390 args_name, argname[i]); 391 return i; 392 }; 393 }; 394 print "\tVDESC_NO_OFFSET,"; 395 return -1; 396} 397 398function offsets() { 399 # Define offsets array 400 printf("const int %s_vp_offsets[] = {\n", name); 401 for (i=0; i<argc; i++) { 402 if (argtype[i] == "struct vnode *") { 403 printf ("\tVOPARG_OFFSETOF(struct %s_args,a_%s),\n", 404 args_name, argname[i]); 405 } 406 } 407 print "\tVDESC_NO_OFFSET"; 408 print "};"; 409 # Define F_desc 410 printf("const struct vnodeop_desc %s_desc = {\n", name); 411 # offset 412 printf ("\t%s_DESCOFFSET,\n", toupper(name)); 413 # printable name 414 printf ("\t\"%s\",\n", name); 415 # flags 416 printf("\t0"); 417 vpnum = 0; 418 for (i=0; i<argc; i++) { 419 if (willrele[i]) { 420 if (willrele[i] == 3) { 421 word = "PUT"; 422 } else { 423 word = "RELE"; 424 } 425 printf(" | VDESC_VP%s_WILL%s", vpnum, word); 426 } 427 if (argtype[i] == "struct vnode *") 428 vpnum++; 429 } 430 print ","; 431 # vp offsets 432 printf ("\t%s_vp_offsets,\n", name); 433 # vpp (if any) 434 do_offset("struct vnode **"); 435 # cred (if any) 436 do_offset("kauth_cred_t"); 437 # componentname 438 do_offset("struct componentname *"); 439 printf ("};\n"); 440} 441 442function bodyrump() { 443 printf("{\n\tint error;\n\n"); 444 printf("\trump_schedule();\n"); 445 printf("\terror = %s(", toupper(name)); 446 for (i=0; i<argc; i++) { 447 printf("%s", argname[i]); 448 if (i < (argc-1)) printf(", "); 449 } 450 printf(");\n"); 451 printf("\trump_unschedule();\n\n"); 452 printf("\treturn error;\n}\n"); 453} 454 455function bodynorm() { 456 printf("{\n\tint error;\n\tbool mpsafe;\n\tstruct %s_args a;\n", 457 args_name); 458 printf("\tstruct mount *mp;\n"); 459 if (lockdebug) { 460 printf("#ifdef VNODE_LOCKDEBUG\n"); 461 for (i=0; i<argc; i++) { 462 if (lockstate[i] != -1) 463 printf("\tint islocked_%s;\n", argname[i]); 464 } 465 printf("#endif\n"); 466 } 467 printf("\ta.a_desc = VDESC(%s);\n", name); 468 for (i=0; i<argc; i++) { 469 printf("\ta.a_%s = %s;\n", argname[i], argname[i]); 470 if (lockdebug && lockstate[i] != -1) { 471 printf("#ifdef VNODE_LOCKDEBUG\n"); 472 printf("\tislocked_%s = (%s->v_vflag & VV_LOCKSWORK) ? (VOP_ISLOCKED(%s) == LK_EXCLUSIVE) : %d;\n", 473 argname[i], argname[i], argname[i], lockstate[i]); 474 printf("\tif (islocked_%s != %d)\n", argname[i], 475 lockstate[i]); 476 printf("\t\tpanic(\"%s: %s: locked %%d, expected %%d\", islocked_%s, %d);\n", name, argname[i], argname[i], lockstate[i]); 477 printf("#endif\n"); 478 } 479 } 480 if (fstrans == "LOCK") 481 printf("\terror = vop_pre(%s, &mp, &mpsafe, %s);\n", 482 argname[0], "(flags & LK_NOWAIT ? FST_TRY : FST_YES)"); 483 else if (fstrans == "UNLOCK") 484 printf("\terror = vop_pre(%s, &mp, &mpsafe, FST_%s);\n", 485 argname[0], "NO"); 486 else 487 printf("\terror = vop_pre(%s, &mp, &mpsafe, FST_%s);\n", 488 argname[0], fstrans); 489 printf("\tif (error)\n\t\treturn error;\n"); 490 printf("\terror = (VCALL(%s, VOFFSET(%s), &a));\n", 491 argname[0], name); 492 if (fstrans == "LOCK") 493 printf("\tvop_post(%s, mp, mpsafe, %s);\n", 494 argname[0], "(error ? FST_YES : FST_NO)"); 495 else if (fstrans == "UNLOCK") 496 printf("\tvop_post(%s, mp, mpsafe, FST_%s);\n", 497 argname[0], "YES"); 498 else 499 printf("\tvop_post(%s, mp, mpsafe, FST_%s);\n", 500 argname[0], fstrans); 501 if (willmake != -1) { 502 printf("#ifdef DIAGNOSTIC\n"); 503 printf("\tif (error == 0)\n" \ 504 "\t\tKASSERT((*%s)->v_size != VSIZENOTSET\n" \ 505 "\t\t && (*%s)->v_writesize != VSIZENOTSET);\n", 506 argname[willmake], argname[willmake]); 507 printf("#endif /* DIAGNOSTIC */\n"); 508 } 509 printf("\treturn error;\n}\n"); 510} 511 512function doit() { 513 printf("\n"); 514 if (!rump) 515 offsets(); 516 517 if (rump) 518 extname = "RUMP_" toupper(name); 519 else 520 extname = toupper(name); 521 522 # Define function. 523 printf("int\n%s(", extname); 524 for (i=0; i<argc; i++) { 525 printf("%s %s", argtype[i], argname[i]); 526 if (i < (argc-1)) printf(",\n "); 527 } 528 printf(")\n"); 529 530 if (rump) 531 bodyrump(); 532 else 533 bodynorm(); 534} 535BEGIN { 536 # start from 1 (vop_default is at 0) 537 argc=1; 538} 539'"$awk_parser" | sed -e "$anal_retentive" 540 541# End stuff 542[ -n "${rump}" ] && return 543 544# Add the vfs_op_descs array to the C file. 545# Begin stuff 546echo " 547const struct vnodeop_desc * const ${rump}vfs_op_descs[] = { 548 &${rump}vop_default_desc, /* MUST BE FIRST */ 549" 550 551# Body stuff 552sed -e "$sed_prep" $src | $awk -v rump=${rump} ' 553function doit() { 554 printf("\t&%s_desc,\n", name); 555} 556'"$awk_parser" 557 558# End stuff 559echo ' NULL 560};' 561} 562do_cfile $out_c '' 563do_cfile $out_rumpc 'rump_' 564 565exit 0 566 567# Local Variables: 568# tab-width: 4 569# End: 570