Replicfs is a persistent file system that replicates files among two copies, as described in Appendix sec-appendix-typical-persistent-replicfs. It uses an auxiliary state file system for storing which replica has the most up-to-date copy of each file. For the purpose of this example, I've set the following additional criteria:
Of course, these criteria can be changed by the file system's designer to result in different file system semantics. Figure fig-fist-definition-replicfs1 shows the top FiST definitions for Replicfs. Figure fig-fist-definition-replicfs2 shows the FiST rule section for reading operations, and Figure fig-fist-definition-replicfs3 shows the FiST rule section for writing operations.
2.9in
%{ #ifdef HAVE_AC_CONFIG_H /* include Autoconf-generated header */ # include "config.h" #endif %} %fstype persistent %interposers 2 %% |
3.6in
/* FiST Rules for read operations*/ $$.%vn_op_read.%variables: { int best_copy = 0; } $$.%vn_op_read.%in_state: { /* find who has the best copy */ best_copy = %state get, $$.%fid; }; $$.%vn_op_read.%action: { /* perform the operation on the "best" copy */ if (best_copy == 1) { /* first replica is most up-to-date */ error = $1.%vn_op_this; } else if (best_copy == 2) { /* second replica is most up-to-date */ error = $2.%vn_op_this; } else { /* both replicas are OK. pick one */ if (fist_random_int() & 0x1 == 0) error = $1.%vn_op_this; else error = $2.%vn_op_this; } } |
3.8in
$$.%vn_op_write.%action: { retval[1] = $1.%vn_op_this; retval[2] = $2.%vn_op_this; } $$.%vn_op_write.%error_action: { if (retval[1] != 0 && retval[2] != 0) { /* both actions failed */ error = retval[1]; } else if (retval[1] == 0 && retval[2] != 0) { /* replica 2 failed. save "1" in statefs */ %state add, $$.%vn_fid, 1; error = retval[1]; } else if (retval[1] != 0 && retval[2] == 0) { /* replica 1 failed. save "2" in statefs */ %state add, $$.%vn_fid, 2; error = retval[2]; } } $$.%vn_op_write.%out_state: { /* both actions succeeded. delete state if any */ %state del, $$.%vn_fid; } %% /* No additional code needed */ |
Figure fig-fist-definition-replicfs-code1 shows the code that will be
automatically generated by FiST for the reading operation vn_getattr
(get file attributes).
5in
static int fist_wrap_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr) int error = EPERM; vnode_t *interposed_vp1, *interposed_vp2; int best_copy = 0; /* lock the interposition chain (default action) */ fist_lock_interposition_chain(vp); /* find the interposed vnodes (default action) */ interposed_vp1 = vntofwn(vp)->fwn_vnodep1; interposed_vp2 = vntofwn(vp)->fwn_vnodep2; /* find who has the best copy */ best_copy = fist_state_get(vp, fist_get_fid(vp)); /* perform the operation on the "best" copy */ if (best_copy == 1) { /* first replica is most up-to-date */ error = VOP_GETATTR(interposed_vp1, vap, flags, cr); } else if (best_copy == 2) { /* second replica is most up-to-date */ error = VOP_GETATTR(interposed_vp2, vap, flags, cr); } else { /* both replicas are OK. pick one */ if (fist_random_int() & 0x1 == 0) error = VOP_GETATTR(interposed_vp1, vap, flags, cr); else error = VOP_GETATTR(interposed_vp2, vap, flags, cr); } /* unlock the interposition chain (default action) */ fist_unlock_interposition_chain(vp); /* return status code (default action) */ return (error); } |
Figure fig-fist-definition-replicfs-code2 shows the code that will be automatically generated by FiST for the writing operation vn_setattr (set file attributes).
5in
static int fist_wrap_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr) { int error = EPERM; vnode_t *interposed_vp1, *interposed_vp2; int retval[2]; /* lock the interposition chain (default action) */ fist_lock_interposition_chain(vp); /* find the interposed vnodes (default action) */ interposed_vp1 = vntofwn(vp)->fwn_vnodep1; interposed_vp2 = vntofwn(vp)->fwn_vnodep2; /* perform actions on interposed vnodes */ retval[1] = VOP_SETATTR(interposed_vp1, vap, flags, cr); retval[2] = VOP_SETATTR(interposed_vp2, vap, flags, cr); /* check if any errors occurred (default action) */ if (retval[1] != 0 || retval[2] != 0) { if (retval[1] != 0 && retval[2] != 0) { /* both actions failed */ error = retval[1]; } else if (retval[1] == 0 && retval[2] != 0) { /* replica 2 failed. save "1" in statefs */ fist_state_add(vp, fist_get_fid(vp), 1); error = retval[1]; } else if (retval[1] != 0 && retval[2] == 0) { /* replica 1 failed. save "2" in statefs */ fist_state_add(vp, fist_get_fid(vp), 2); error = retval[2]; } /* return status code (default action) */ return (error); } /* both actions succeeded. delete state if any */ fist_state_del(vp, fist_get_fid(vp)); /* unlock the interposition chain (default action) */ fist_unlock_interposition_chain(vp); /* return status code (default action) */ return (error); } |