next up previous contents
Next: 11. Appendix: Wrapfs Mount Up: 10. Extended Examples Using Previous: 10.2 Gzipfs: An In-Core

   
10.3 Replicfs: A Persistent File System

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.


  
Figure: FiST Definition for Replicfs (top)

Figure: FiST Definition for Replicfs (top)


%{
#ifdef HAVE_AC_CONFIG_H
/* include Autoconf-generated header */
# include "config.h"
#endif
%}

%fstype persistent
%interposers 2

%%





2.9in


%{
#ifdef HAVE_AC_CONFIG_H
/* include Autoconf-generated header */
# include "config.h"
#endif
%}

%fstype persistent
%interposers 2

%%


  
Figure: FiST Definition for Replicfs (reading operations)

Figure: FiST Definition for Replicfs (reading operations)


/* 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.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;
  }
}


  
Figure: FiST Definition for Replicfs (writing operations)

Figure: FiST Definition for Replicfs (writing operations)


$$.%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 */





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).

  
Figure: Vnode Code Automatically Generated by FiST for replicfs (reading operation)

Figure: Vnode Code Automatically Generated by FiST for replicfs (reading operation)


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





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).


  
Figure: Vnode Code Automatically Generated by FiST for replicfs (writing operation)

Figure: Vnode Code Automatically Generated by FiST for replicfs (writing operation)


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





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


next up previous contents
Next: 11. Appendix: Wrapfs Mount Up: 10. Extended Examples Using Previous: 10.2 Gzipfs: An In-Core
Erez Zadok
1999-12-07