next up previous contents
Next: 10.3 Replicfs: A Persistent Up: 10. Extended Examples Using Previous: 10.1 Crossfs: A Stateless

   
10.2 Gzipfs: An In-Core File System


  
Figure: FiST Definition for Gzipfs

Figure: FiST Definition for Gzipfs


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

%fstype incore
%filter gzip $$ %vn_write {%name =~ "\.txt$"}
%filter gunzip $$ %vn_read {%name =~ "\.txt$"}

%%
  /* Empty FiST rules section */
%%
  /* No additional code needed */





3.3in


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

%fstype incore
%filter gzip $$ %vn_write {%name =~ "\.txt$"}
%filter gunzip $$ %vn_read {%name =~ "\.txt$"}

%%
  /* Empty FiST rules section */
%%
  /* No additional code needed */

Gzipfs is a compression file system based on my wrapper file system (Appendix sec-appendix-typical-in-core-wrapfs). Data gets compressed before written to stable media, and decompressed after having been read from such. For this example, I only wish to compress regular files that have a file extension .txt', since ASCII files yield better compression ratios. The example of Figure fig-fist-definition-gzipfs shows the FiST input for this file system.

The code automatically generated for Gzipfs will be similar to Wrapfs, with the two exceptions of the read and write functions. One possible code for these, for example the read() function, is shown in Figure fig-fist-definition-gzipfs-code.


  
Figure: Vnode Code Automatically Generated by FiST for Gzipfs

Figure: Vnode Code Automatically Generated by FiST for Gzipfs


static int
fist_gzipfs_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr)
{
  int error;
  vnode_t *interposed_vp;
  uio_t *new_uiop; /* for the decompressed bytes */

  /* find interposed vnode that is "hidden" inside this vnode */
  interposed_vp = vntofwn(vp)->fwn_vnodep;

  /* pass operation to interposed file system, and return status */
  if ((error = VOP_READ(interposed_vp, uiop, ioflag, cr)) != 0)
    return (error);

  /* Check for triggered events after reading */
  if (regexp_match(fist_get_file_name(vp), "\.txt$"))
    if (fist_filter_gunzip_data(&uiop, sizeof(uio_t), &new_uiop) < 0)
      return EIO; /* I/O error occurred */

  uiop = new_uiop; /* pass up decompressed data */
  return (error);
}





5in


static int
fist_gzipfs_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr)
{
  int error;
  vnode_t *interposed_vp;
  uio_t *new_uiop; /* for the decompressed bytes */

  /* find interposed vnode that is "hidden" inside this vnode */
  interposed_vp = vntofwn(vp)->fwn_vnodep;

  /* pass operation to interposed file system, and return status */
  if ((error = VOP_READ(interposed_vp, uiop, ioflag, cr)) != 0)
    return (error);

  /* Check for triggered events after reading */
  if (regexp_match(fist_get_file_name(vp), "\.txt$"))
    if (fist_filter_gunzip_data(&uiop, sizeof(uio_t), &new_uiop) < 0)
      return EIO; /* I/O error occurred */

  uiop = new_uiop; /* pass up decompressed data */
  return (error);
}

In this example, the routine decodes the ``hidden'' vnode pointer, and then passes the read operation to it. After the read had succeeded, we call the FiST filter function fist_filter_gzip_data(). This filter is used to decompress data in the uio. The filter function would make use of kernel functions that manipulate uio structures such as uiomove() to move blocks of bytes between one uio and another. Bytes will be read off of one uio structure, passed through a generic stream decompression function I pulled out of the GNU Zip package, and written to a new uio structure. Then the old uio structure is deallocated and replaced with the new one.

Figure fig-fist-definition-gzipfs-code-4nfs shows the code that would be generated for the NFS version of the same read operation.


  
Figure: NFS Code Automatically Generated by FiST for Gzipfs

Figure: NFS Code Automatically Generated by FiST for Gzipfs


int
nfsproc2_gzipfs_read(struct nfsreadargs *in,  struct nfsrdresult *out,
                     struct exportinfo *ex, struct svc_req *sr, cred_t *cr)
{
  int error NFS_OK;

  /* perform simple read */
  error = fist_gzipfs_read(in, out);
  if (error)
    return (error);

  /* check for triggered events after reading */
  if (regexp_match(fist_get_nfs_file_name(in->ra_fhandle), "\.txt$"))
    if (fist_filter_gunzip_nfs_data(in, out) < 0)
      return NFS_ERR;           /* I/O error occurred */

  return (error);
}





5.5in


int
nfsproc2_gzipfs_read(struct nfsreadargs *in,  struct nfsrdresult *out,
                     struct exportinfo *ex, struct svc_req *sr, cred_t *cr)
{
  int error NFS_OK;

  /* perform simple read */
  error = fist_gzipfs_read(in, out);
  if (error)
    return (error);

  /* check for triggered events after reading */
  if (regexp_match(fist_get_nfs_file_name(in->ra_fhandle), "\.txt$"))
    if (fist_filter_gunzip_nfs_data(in, out) < 0)
      return NFS_ERR;           /* I/O error occurred */

  return (error);
}


next up previous contents
Next: 10.3 Replicfs: A Persistent Up: 10. Extended Examples Using Previous: 10.1 Crossfs: A Stateless
Erez Zadok
1999-12-07