Fan-out defines how many file systems one module can interpose upon. Inside the kernel there is no limit. The interposed vnode pointers are stored inside the interposer's private data field, then accessed as described in Section sec-design-using and depicted in Figure fig-vnode-fanout.
3.8in
/* perform FOO operation on two interposed vnodes */ int vn_foo(vnode_t *vp, args) { vnode_t *hidden_vp1 = vp->v_data->hidden[0]; vnode_t *hidden_vp2 = vp->v_data->hidden[1]; int error; error = VN_FOO(hidden_vp1, args); if (error) return(error); error = VN_FOO(hidden_vp2, args); return(error); } |
This code is nice because it does not know about the type of the file systems it interposes upon. This is the result of having an abstract vnode interface in the first place. NFS is not an abstract interface like the vnode interface is. Therefore, an NFS module inside Amd would have to know what type of file system it is accessing:
The generated code must have some hooks that can probe an Amd server at run-time to see if the function it needs to call is local to the running process or not. This is a small complication to the generated code that may make it less clean. For example, the same vnode operation as in Figure fig-vnode-fanout, when generated for the NFS interface, would look much like the code in Figure fig-nfs-fanout.
4.2in
/* perform FOO operation on two interposed nodes */ int nfs_foo(fhandle_t *fhp, args) { fhandle_t *hidden_fhp1 = fhp->fh_data->hidden[0]; fhandle_t *hidden_fhp2 = fhp->fh_data->hidden[1]; int error; /* find type of first handle, and call it */ if (file_system_local_to_amd(fs_type_of(hidden_fhp1))) error = AMD_FOO(hidden_vhp1, args); else error = syscall(SYS_FOO, hidden_vhp1, args); if (error) return(error); /* find type of second handle, and call it */ if (file_system_local_to_amd(fs_type_of(hidden_fhp2))) error = AMD_FOO(hidden_vhp2, args); else error = syscall(SYS_FOO, hidden_vhp2, args); return(error); } |
Additional and detailed examples of using FiST are included in Appendix sec-appendix-example.