#!/usr/bin/python # This script generates the boilerplate versions of most fops and cbks in the # server. This allows the details of leadership-status checking, sequencing # between leader and followers (including fan-out), and basic error checking # to be centralized one place, with per-operation code kept to a minimum. import sys import codegen type_re = "([a-z_0-9]+)" name_re = "\(\*fop_([a-z0-9]+)_t\)" full_re = type_re + " *" + name_re fop_cg = codegen.CodeGenerator() fop_cg.skip = 2 fop_cg.parse_decls(sys.argv[1],full_re) fop_cg.load_templates(sys.argv[2]) # Use the multi-template feature to generate multiple callbacks from the same # parsed declarations. type_re = "([a-z_0-9]+)" name_re = "\(\*fop_([a-z0-9]+)_cbk_t\)" full_re = type_re + " *" + name_re cbk_cg = codegen.CodeGenerator() cbk_cg.skip = 5 cbk_cg.parse_decls(sys.argv[1],full_re) cbk_cg.load_templates(sys.argv[2]) # This is a nasty little trick to handle the case where a generated fop needs # a set of default arguments for the corresponding callback. fop_cg.make_defaults = cbk_cg.make_defaults # We need two types of templates. The first, for pure read operations, just # needs to do a simple am-i-leader check (augmented to allow dirty reads). # The second, for pure writes, needs to do fan-out to followers between those # initial checks and local execution. There are other operations that don't # fit neatly into either category - e.g. lock ops or fsync - so we'll just have # to handle those manually. The table thus includes entries only for those we # can categorize. The special cases, plus any new operations we've never even # heard of, aren't in there. # # Various keywords can be used to define/undefine preprocessor symbols used # in the templates, on a per-function basis. For example, if the keyword here # is "fsync" (lowercase word or abbreviation) that will cause NSR_CG_FSYNC # (prefix plus uppercase version) to be defined above all of the generated code # for that fop. fop_table = { "access": "read", "create": "write", "discard": "write", # "entrylk": "read", "fallocate": "write", # "fentrylk": "read", "fgetxattr": "read", # "finodelk": "read", # "flush": "read", "fremovexattr": "write", "fsetattr": "write", "fsetxattr": "write", "fstat": "read", # "fsync": "read", # "fsyncdir": "read", "ftruncate": "write", "fxattrop": "write", "getxattr": "read", # "inodelk": "read", "link": "write", # "lk": "read", # "lookup": "read", "mkdir": "write", "mknod": "write", "open": "write", "opendir": "read", "rchecksum": "read", "readdir": "read", "readdirp": "read", "readlink": "read", "readv": "read", "removexattr": "write", "rename": "write", "rmdir": "write", "setattr": "write", "setxattr": "write", "stat": "read", "statfs": "read", "symlink": "write", "truncate": "write", "unlink": "write", "writev": "write,fsync,queue", "xattrop": "write", } fops_done = [] for x in sorted(fop_cg.decls.keys()): if x in fop_table.keys(): info = fop_table[x].split(",") kind = info[0] flags = info[1:] if ("fsync" in flags) or ("queue" in flags): flags.append("need_fd") for fname in flags: print "#define NSR_CG_%s" % fname.upper() cbk_cg.emit(x,kind+"-complete") fop_cg.emit(x,kind+"-continue") cbk_cg.emit(x,kind+"-fan-in") fop_cg.emit(x,kind+"-dispatch") fop_cg.emit(x,kind+"-fop") for fname in flags: print "#undef NSR_CG_%s" % fname.upper() fops_done.append(x) else: print("/* No code emitted for %s */"%x) print("") # Just for fun, emit the fops table too. print("struct xlator_fops fops = {") for x in fops_done: print(" .%s = nsr_%s,"%(x,x)) print("};")