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);
}
|