| We're adding the plan 9 file system to akaros.We're bringing in the | 
 | name space interface, including the ability to do binds, union mounts, | 
 | and the like. We will extend it to support things we might need, | 
 | in particular mmap.  We will use it to add things to Akaros we  | 
 | need, such as virtio drivers, ethernet drivers, and TCP. | 
 |  | 
 | By bringing this model in, we can make the Akaros interface more powerful, | 
 | yet simpler. We can remove a number of system calls right away  | 
 | and yet still have the functions they provide, for example.  | 
 |  | 
 | This is not a from scratch effort but a code translation. The Plan 9 code | 
 | deals with very subtle situations and has been hardened over time. No need | 
 | to relearn what they learned from scratch. | 
 |  | 
 | Currently we have a lot of the code in and are testing a first device --  | 
 | the regression device from NxM. | 
 |  | 
 | Issues. | 
 |  | 
 | The biggest issue so far is implementing the Plan 9 error handling. | 
 | In Plan 9, errors are managed via a longjmp-like mechanism. For example, | 
 | in a call chain such as: | 
 | a() | 
 |  b() | 
 |   c() | 
 |    d() | 
 |  | 
 | It is possible for 'd' to invoke an error that returns to 'a' directly.  | 
 | This model has many advantages over the standard model, which looks like | 
 | this: | 
 | a{ b();} | 
 |  b{ if c() return OK; else return -1;} | 
 |   c{ if d() return OK; else return -1;} | 
 |    d{ if something return OK; else return -1;} | 
 |  | 
 | In Plan 9 it can look like this: | 
 |  | 
 | a{ b();} | 
 |  b{ c(); something else();} | 
 |   c{ d(); other thing();} | 
 |    d{ if something return OK; else error("bad");} | 
 |  | 
 | Note that the intermediate functions can be written as though nothing | 
 | went wrong, since anything that goes wrong gets bounced to the first level | 
 | error handler.  | 
 |  | 
 | The handling is implemented via something called waserror(). | 
 | In a() we do this: | 
 |  | 
 | a(){ | 
 |    if (waserror())  { handle error; poperror();} | 
 |    b(); | 
 |    poperror(); | 
 | } | 
 |  | 
 | and in d we might have this: | 
 | d(){ | 
 |    do something;  | 
 |    if (bad) error("bad"); | 
 |    return 0; | 
 | } | 
 |  | 
 | What if there's more than one error? There can be multiple invocations | 
 | of waserror in one function: | 
 | a(){ | 
 |    if (waserror()){ printf("b failed"); poperror(); return -2;} | 
 |    b(); | 
 |    if (waserror()) { printf("z failed"); nexterror(); } | 
 |    z(); | 
 |    poperror(); | 
 |    poperror(); | 
 | } | 
 |  | 
 | Every waserror needs a matching poperror or nexterror in the same function as | 
 | the waserror, covering every exit from the function.  nexterror is like | 
 | to poperror() then error("str"), but without resetting errstr. | 
 |  | 
 | Note that the error could have been anywhere in the call chain; | 
 | we don't care. From the point of view of a(), something failed, and we only | 
 | know about b() or z(), so we blame them. We also show in this example | 
 | nexterror(). Nexterror() pops back to the next error in the error stack, | 
 | which might be in this function or somewhere up the call chain. | 
 |  | 
 | How do we find out the ultimate blame? Recall that error takes a string, | 
 | and that can be anything. We can tell from that.  | 
 |  | 
 | Where does the string in error() go? | 
 | In Plan 9, it goes into the proc struct; in Akaros, | 
 | it's copied to a user-mode buffer via set_errstr().  | 
 |  | 
 | waserror()/error()/nexterror() manipulate an error call stack, similar to | 
 | the function call stack. In Plan 9, this stack is maintained in the proc | 
 | struct. This is cheap in Plan 9, since the compiler has caller-save, and | 
 | hence each stack entry is a stack and a PC. In a callee-save world, the | 
 | stack entries are much, much larger; so large that maintaining the stack | 
 | in the proc struct is impractical. | 
 |  | 
 | Hence, we've had to make changes that add a bit of inconvenience but | 
 | leave the code mostly intact. The error code in Akaros is tested in every | 
 | circumstance at this point due to all the bugs we had in our port | 
 | of the Plan 9 file system code. | 
 |  | 
 | So, we'll go from the easiest case to the hardest. | 
 |  | 
 | Case 1: You're a leaf function that does not use error(). No change. | 
 |  | 
 | Case 2: You're a leaf function that needs error().  Just call error(). | 
 |  | 
 | Case 3: You're an intermediate function that calls functions that use error(), | 
 | even though you do not.  No change. | 
 |  | 
 | Those are in some sense the easier cases. Now it starts to get a | 
 | bit harder. | 
 |  | 
 | Case 4: you're a leaf or intermediate function that uses waserror().  You need | 
 | to use a macro which creates an array of errbuf structs as automatics. The | 
 | waserror() usage does not change.  The macro is ERRSTACK(x), where x is the | 
 | number of calls to waserror() in your function. See kern/sys/chan.c.  Every call | 
 | to waserror needs to have a matching poperror.  You cannot call nexterror or | 
 | poperror unless you are in the same scope as an ERRSTACK that had a waserror | 
 | call. | 
 |  | 
 | Case 5: you're a root node, i.e. you're the start of a chain of calls | 
 | via syscall that must do the "root" errbuf setup, so that all error | 
 | calls eventually return to you. In this case, you need to start the error | 
 | stack.  This uses the same macro as case 4 (ERRSTACK(x)), for now. | 
 |  | 
 | Finally, if, in a waserror, you are finished and want to pop out to the | 
 | next error in the chain, either in the same function or up the call stack, | 
 | just call nexterror(). | 
 |  | 
 | This can be handy for debugging: in any function that supports error(), i.e. | 
 | called from a function that called waserror(), simply call error and it bails | 
 | you out of wherever you are, doing appropriate cleanup on the way out.  No need | 
 | to add return value processing to intermediate functions; if you try this out | 
 | you will likely find it is extremely handy. I really miss it on Linux. It made a | 
 | lot of the port debugging to Akaros a lot easier. | 
 |  | 
 | There is error checking in error()/waserror()/nexterror(). | 
 | If you overflow or underflow the error stack the kernel will panic. | 
 | The implementation is in kern/src/error.c, the macros are in | 
 | kern/include/plan9.h. | 
 |  | 
 |  | 
 | For info on the format of Ms (which are part of the kernel interface): | 
 | 	http://9p.cat-v.org/documentation/rfc/  |