/*
 *
 *        Name: cmsfsvfs.c (C program source)
 *              CMS FS VFS interface routines
 *        Date: 2000-Sep-14 (Thu)
 *
 *    See also: cmsfsusa.c
 *
 *              This source contains the routines and structures
 *              required when CMS FS is built as a driver.
 *              It interfaces between CMS FS' own structures,
 *              which read the CMS EDF format,  and Linux VFS.
 *
 *
 *
 *
 */
 
#define         __KERNEL__
#define         MODULE
 
#include        <linux/module.h>
#include        <linux/version.h>
 
#include        <linux/fs.h>
#include        <linux/mm.h>
 
#include        <linux/slab.h>
 
#include        <linux/locks.h>
 
#include        <asm/param.h>
#include        <linux/types.h>
 
#include        "cmsfs.h"
 
/*  The following two should be def'd in linux/locks.h.
    Why they are not is something I have not yet figured out.  */
inline void lock_super(struct super_block * sb)
{
        if (sb->s_lock)
                __wait_on_super(sb);
        sb->s_lock = 1;
}
 
inline void unlock_super(struct super_block * sb)
{
        sb->s_lock = 0;
        wake_up(&sb->s_wait);
}
 
/* --------------------------------------------------------- CMSFS_ERROR
 *  Generally a printk() operation, not really perror() function.
 */
void cmsfs_error(unsigned char * string)
  {
    (void) printk("CMSFS: %s\n",string);
  }
 
/* --------------------------------------------------------- CMSFS_BREAD
 *  The "b" here means "block", not "buffer".  Do not confuse this with
 *  Linux VFS bread() function.   This is CMS FS "block read" function.
 */
int cmsfs_bread(struct CMSSUPER *vol,void *buf,int block,int blocksize)
  {
    struct buffer_head * bh;
    struct super_block * sb;
    unsigned char ts[256];
    int         ratio;
 
    /*  announce this function  */
    (void) sprintf(ts,"cmsfs_bread(-,%d,%d)",block,blocksize);
    cmsfs_error(ts);
 
    /*  for the moment,  we only deal with fractional blocks  */
    if (blocksize > vol->pbksz)
      {
        (void) sprintf(ts,
                "logical blocksize %d too large for physical %d",
                blocksize,vol->pbksz);
        cmsfs_error(ts);
        return -1;
      }
    /*  We could maybe handle that case by breaking-up this call into
        multiple bread() calls, but that'll be a later driver rev.  */
 
    ratio = vol->pbksz / blocksize;
    sb = (struct super_block *) vol->vfssuper;
 
    /*  does this help?  */
/*  set_blocksize(sb->s_dev,blocksize);  */
    /*  not really  */
 
    /*  announce and call the system-level bread()  */
    (void) sprintf(ts,"bread('%s',%d,%d)",
                kdevname(sb->s_dev),block,blocksize);
    cmsfs_error(ts);
/* FIX THIS
    bh = bread(sb->s_dev,block,blocksize);
 */
    bh = bread(sb->s_dev,0,4096);
    if (bh == NULL)
      {
        cmsfs_error("looks like bread() failed");
        return -1;
      }
    if (bh)
      {
        cmsfs_error("looks like bread() worked");
        return -1;
      }
 
    /*  copy the data part,  then release the VFS buffer  */
/*  (void) memcpy(buf,bh->b_data,blocksize);  */
    (void) memmove(buf,bh->b_data,blocksize);
/*  (void) brelse(bh);  */
 
/*
I'm having problems here!
6-out-of-10 times I call bread() the kernel crashes.
(Doesn't even successfully panic;  just locks up!)
 
buffer_head.b_data;     ** pointer to data block (1024 bytes) **
((bh)->b_data)
 */
 
/*
    (void) sprintf(ts,"bread(%s,%d,%d) ratio %d",
                kdevname(sb->s_dev),block/ratio,vol->pbksz,ratio);
    cmsfs_error(ts);
    bh = bread(sb->s_dev,block/ratio,vol->pbksz);
    if (bh == NULL) return -1;
 */
 
    return blocksize;
  }
 
/* -------------------------------------------------------- CMSFS_MALLOC
 */
void * cmsfs_malloc(int size)
  {
    return kmalloc(size, GFP_KERNEL);
  }
 
/* ---------------------------------------------------------- CMSFS_FREE
 */
void cmsfs_free(void * buffer)
  {
    kfree(buffer);
    return;
  }
 
#define  memcpy(b,d,l)  memmove(b,d,l)
time_t mktime() { return 0; }
#include        "cmsfsany.c"
#include        "aecs.c"
 
/*  I learned of this requirement from Neale's "cpint" code.  */
char kernel_version [] = UTS_RELEASE;
 
 
 
/* ---------------------------------------------------- CMSFS_READ_INODE
 *  routines required when CMS FS is built as a driver
 *
 *  CMS FS inode numbers are base-zero index into the directory.
 *  CMS FS (EDF) is flat, no sub-directories, so there is
 *  only one such directory into which we index.
 */
void cmsfs_read_inode(struct inode * in)
  {
    cmsfs_error("cmsfs_read_inode() ... N/A");
    return;
  }
 
/* ----------------------------------------------------- CMSFS_PUT_SUPER
 */
void cmsfs_put_super(struct super_block * sb)
  {
    cmsfs_error("cmsfs_put_super() ... N/A");
    return;
  }
 
/* ------------------------------------------------- CMSFS_NOTIFY_CHANGE
 */
void cmsfs_notify_change(struct dentry * de,struct iattr * ia)
  {
    cmsfs_error("cmsfs_notify_change() ... N/A");
    return;
  }
 
/* -------------------------------------------------------- CMSFS_STATFS
 */
int cmsfs_statfs(struct super_block * sb,struct statfs *st,int stl)
  {
    /*  EXT2 allocates a temporary statfs structure
        and then copies the contents,  limitting at stl  */
 
    cmsfs_error("cmsfs_statfs() ... N/A");
 
/*
    st->f_bsize = cmssuper->blksz;
    st->f_blocks = cmssuper->blocks;
    st->f_bfree = cmssuper->bkfree;
    st->f_bavail = cmssuper->bkfree;
    st->f_files = cmssuper->files;
 
    st->f_ffree = cmssuper->ffree;
 */
 
    return 0;
  }
 
/* ------------------------------------------------------- CMSFS_REMOUNT
 */
int cmsfs_remount(struct super_block * sb,int *flags,char *data)
  {
    cmsfs_error("cmsfs_remount() ... N/A");
    return 0;
  }
 
/* --------------------------------------------------- CMSFS_CLEAR_INODE
 */
void cmsfs_clear_inode(struct inode * in)
  {
    cmsfs_error("cmsfs_clear_inode() ... N/A");
    return;
  }
 
/* -------------------------------------------------------- CMSFS_UMOUNT
 *  This is called technically to "begin umount".
 *  We will ultimately use it to free some CMS-specific buffers.
 *  There is a CMS FS structure which goes with the superblock.
 *  There is a CMS FS structure which goes with the root inode.
 */
void cmsfs_umount(struct super_block * sb)
  {
    CMSSUPER  *cmssuper;
 
    /*  annonce that we're here  */
    cmsfs_error("cmsfs_umount() ... ");
 
    cmssuper = sb->u.generic_sbp;
 
    /*  free the CMSINODE struct and mark it freed  */
    cmsfs_free(cmssuper->cmsrooti);
    cmssuper->cmsrooti = NULL;
 
    /*  free the CMSSUPER struct and mark it freed  */
    cmsfs_free(cmssuper);  /*  cmssuper == sb->u.generic_sbp  */
    sb->u.generic_sbp == NULL;
 
    /*  one less instance of this driver  */
    MOD_DEC_USE_COUNT;
 
    return;
  }
 
/* ------------------------------------------------------------------ */
static
struct file_operations cmsfs_file_operations = {
        NULL,   /* llseek */
        NULL,   /* read */
        NULL,   /* write */
        NULL,   /* readdir */
        NULL,   /* poll */
        NULL,   /* ioctl */
        NULL,   /* mmap */
        NULL,   /* open */
        NULL,   /* flush */
        NULL,   /* release */
        NULL,   /* fsync */
        NULL,   /* fasync */
        NULL,   /* check_media_change */
        NULL,   /* revalidate */
        NULL    /* lock */
};
 
static
struct inode_operations cmsfs_inode_operations = {
        &cmsfs_file_operations,
        NULL,   /* create */
        NULL,   /* lookup */
        NULL,   /* link */
        NULL,   /* unlink */
        NULL,   /* symlink */
        NULL,   /* mkdir */
        NULL,   /* rmdir */
        NULL,   /* mknod */
        NULL,   /* rename */
        NULL,   /* readlink */
        NULL,   /* follow_link */
        NULL,   /* readpage */
        NULL,   /* writepage */
        NULL,   /* bmap */
        NULL,   /* truncate */
        NULL,   /* permission */
        NULL,   /* smap */
        NULL,   /* updatepage */
        NULL    /* revalidate */
};
 
static
struct super_operations cmsfs_super_operations = {
        cmsfs_read_inode,
        NULL,   /* cmsfs_write_inode, */
        NULL,   /* cmsfs_put_inode, */
        NULL,   /* cmsfs_delete_inode, */
        cmsfs_notify_change,
        cmsfs_put_super,
        NULL,   /* cmsfs_write_super, */
        cmsfs_statfs,
        cmsfs_remount,
        cmsfs_clear_inode,
        cmsfs_umount
  };
/*  mimic ISO, which is also read-only media  */
/*  mimic MS-DOS, which has similar short names (8x3)  */
 
/* --------------------------------------------------------- CMSFS_MOUNT
 */
struct super_block *
cmsfs_mount(struct super_block * sb, void * data, int silent)
  {
    struct buffer_head * bh;
    struct  CMSSUPER  *cmssuper;
    unsigned char ts[256];
    int         rc;
    struct  inode  *vfsrooti;
 
    /*  the kernel has supplied us with a virgin superblock  */
    cmsfs_error("cmsfs_mount()");
 
    /*  let the kernel know we're busy ... for the moment  */
    MOD_INC_USE_COUNT;
    lock_super(sb);
 
    (void) sprintf(ts,"sb=%08X, data=%08X, silent=%d",sb,data,silent);
    cmsfs_error(ts);
    (void) sprintf(ts,"s_dev=%s (%04X)",kdevname(sb->s_dev),sb->s_dev);
    cmsfs_error(ts);
    (void) sprintf(ts,"s_blocksize=%d",sb->s_blocksize);
    cmsfs_error(ts);
 
    (void) sprintf(ts,"s_type=0x%08X",sb->s_type);
    cmsfs_error(ts);
    (void) sprintf(ts,"s_op=0x%08X",sb->s_op);
    cmsfs_error(ts);
    (void) sprintf(ts,"s_flags=0x%08X",sb->s_flags);
    cmsfs_error(ts);
    (void) sprintf(ts,"s_magic=0x%08X",sb->s_magic);
    cmsfs_error(ts);
    (void) sprintf(ts,"s_time=0x%08X",sb->s_time);
    cmsfs_error(ts);
    (void) sprintf(ts,"s_root=0x%08X",sb->s_root);
    cmsfs_error(ts);
 
    (void) sprintf(ts,"u.generic_sbp=0x%08X",sb->u.generic_sbp);
    cmsfs_error(ts);
 
/* set device read-only (0 = read-write) */
/* BLKROSET */
/* re-read partition table */
/* BLKRRPART */
/* return device size */
/* BLKGETSIZE */
 
    /* -------------------------------------------------------------- *
     *  Fill-out the VFS superblock and allocate a CMS superblock.    *
     * -------------------------------------------------------------- */
    cmssuper = cmsfs_malloc(sizeof(struct CMSSUPER));
    if (cmssuper == NULL)
      {
        cmsfs_error("cannot allocate CMS superblock");
        sb->s_dev = 0;  /*  why?  */
        unlock_super (sb);
        MOD_DEC_USE_COUNT;
        return NULL;
      }
 
    /*  cross-reference CMS superblock and VFS superblock  */
    sb->u.generic_sbp = cmssuper;       /*  VFS to ref CMS  */
    cmssuper->vfssuper = sb;            /*  CMS to ref VFS  */
    cmsfs_error("VFS and CMS superblocks allocated and linked");
 
    cmssuper->cmsrooti = NULL;
 
    cmssuper->pbksz = get_hardblocksize(sb->s_dev);
    (void) sprintf(ts,"hw blocksize=%d",cmssuper->pbksz);
    cmsfs_error(ts);
    /*  This may be redundant.  */
    set_blocksize(sb->s_dev,cmssuper->pbksz);
    /*  Got the following suggestion from Alan Cox.  */
    sb->s_blocksize_bits = 12;
 
    /*  careful! this is not cleared before we get called  */
    sb->s_op = &cmsfs_super_operations;
    /*  we're overwriting something;  it may just be dirty storage  */
    (void) sprintf(ts,"s_op=%08X (corrected)",sb->s_op);
    cmsfs_error(ts);
 
    if (sb->s_blocksize != cmssuper->pbksz)
      {
        /*  set filesystem blocksize to device blocksize  */
        sb->s_blocksize = get_hardblocksize(sb->s_dev);
        (void) sprintf(ts,"s_blocksize=%d (corrected)",sb->s_blocksize);
        cmsfs_error(ts);
      }
    /*  (logical blocksize MIGHT STILL BE DIFFERENT)  */
 
    /*  mark this as "cms"  */
/*
    sb->s_type = &cms_fs_type;
    (void) sprintf(ts,"s_type=%s (corrected)",sb->s_type);
    cmsfs_error(ts);
 */
    /*  isn't this automatic??  handled by the kernel??  */
 
    /* -------------------------------------------------------------- *
     *  Prepare for I/O.                                              *
     * -------------------------------------------------------------- */
 
    /* -------------------------------------------------------------- *
     *  Map the CMS volume (ADT) to CMS superblock.                   *
     * -------------------------------------------------------------- */
    rc = cmsfs_map_ADT(cmssuper);
    if (rc != 0)
      {
        sprintf(ts,"cmsfs_map_ADT() returned %d",rc);
        cmsfs_error(ts);
        cmsfs_free(cmssuper);
        sb->s_dev = 0;  /*  why?  */
        unlock_super (sb);
        MOD_DEC_USE_COUNT;
        return NULL;
      }
    cmsfs_error("ADT mapped into CMS flavor superblock");
 
    /* -------------------------------------------------------------- *
     *  Allocate a CMS root inode.                                    *
     *  This will be called "root" for this filesystem,               *
     *  even though there will be no other directories.               *
     *  This will be inode zero,  and is always the first FST.        *
     * -------------------------------------------------------------- */
    if (cmssuper->cmsrooti == NULL)
      {
        cmsfs_error("supplemental root inode allocation");
        cmssuper->cmsrooti = cmsfs_malloc(sizeof(struct CMSINODE));
        cmsfs_error("cmsfs_map_ADT() should have done this already!");
      }
    if (cmssuper->cmsrooti == NULL)
      {
        cmsfs_error("cannot allocate CMS root inode");
        cmsfs_free(cmssuper);   /*  cmssuper == sb->u.generic_sbp  */
        sb->u.generic_sbp = NULL;
        sb->s_dev = 0;  /*  why?  */
        unlock_super (sb);
        MOD_DEC_USE_COUNT;
        return NULL;
      }
 
    /* -------------------------------------------------------------- *
     *  Allocate and flesh-out a VFS inode for the directory.         *
     *  This will be called "root" for this filesystem,               *
     *  even though there will be no other directories.               *
     *  This will be inode zero,  and is always the first FST.        *
     * -------------------------------------------------------------- */
    cmssuper->cmsrooti->vfsinode = (void*) iget(sb,0);
    if (cmssuper->cmsrooti->vfsinode == NULL)
      {
        cmsfs_error("cannot get directory (root) inode");
        cmsfs_free(cmssuper);   /*  cmssuper == sb->u.generic_sbp  */
        sb->u.generic_sbp = NULL;
        sb->s_dev = 0;  /*  why?  */
        unlock_super (sb);
        MOD_DEC_USE_COUNT;
        return NULL;
      }
 
    /*  cross-reference CMS inode and VFS inode  */
    vfsrooti->u.generic_ip = cmssuper->cmsrooti;  /*  VFS to ref CMS  */
    vfsrooti = cmssuper->cmsrooti->vfsinode;    /*  CMS to ref VFS  */
    cmsfs_error("VFS and CMS root inodes allocated and linked");
 
    vfsrooti->i_sb = sb;
    vfsrooti->i_dev = sb->s_dev;
    vfsrooti->i_ino = 0;
    vfsrooti->i_nlink = 2;
 
    /*  copy the time stamp of the directory  */
/*
    vfsrooti->i_mtime =
    vfsrooti->i_atime =
    vfsrooti->i_ctime = 0;
 */
    /*  the volume also has a time stamp, just FYI  */
 
/*
    vfsrooti->i_op =
 */
/*  inode operations for the directory  */
 
    /* -------------------------------------------------------------- *
     *  Allocate and flesh-out a directory entry (VFS).               *
     * -------------------------------------------------------------- */
    sb->s_root = d_alloc_root(cmssuper->cmsrooti->vfsinode,NULL);
    if (sb->s_root == NULL)
      {
        cmsfs_error("cannot allocate VFS directory structure");
        cmsfs_free(cmssuper->cmsrooti->vfsinode);
        cmsfs_free(cmssuper->cmsrooti);
        cmssuper->cmsrooti = NULL;
        cmsfs_free(cmssuper);   /*  cmssuper == sb->u.generic_sbp  */
        sb->u.generic_sbp = NULL;
        sb->s_dev = 0;  /*  why?  */
        unlock_super (sb);
        MOD_DEC_USE_COUNT;
        return NULL;
      }
 
    sb->s_root->d_op = NULL;  /*  &minix_dentry_operations;  */
 
    /* -------------------------------------------------------------- *
     *  Map the CMS directory (FST) ...                               *
     * -------------------------------------------------------------- */
 
    /*  CMS FS mounts are always read-only to Linux  */
    sb->s_flags |= MS_RDONLY ;
    sb->s_flags |= MS_NOSUID ;
 
    unlock_super (sb);
    return sb;
  }
 
/* ------------------------------------------------------------------ */
static
struct file_system_type cms_fs_type = {
        "cms" ,
        FS_REQUIRES_DEV | FS_NO_DCACHE | FS_NO_PRELIM ,
        cmsfs_mount ,
        NULL
        } ;
 
/* ---------------------------------------------------------- CMSFS_INIT
 *  filesystem init, especially useful for module init
 */
int cmsfs_init()
  {
    unsigned char ts[256];
    cmsfs_error("cmsfs_init()");
    (void) sprintf(ts,"%s %s",CMSFS_DESCRIPTION,CMSFS_VERSION);
    cmsfs_error(ts);
#ifdef  CONFIG_PROC_FS
        rpc_register_sysctl();
        rpc_proc_init();
/*
        rpc_proc_register(&cmsfs_rpcstat);
 */
#endif
    return register_filesystem(&cms_fs_type);
  }
 
/* ------------------------------------------------------- CMSFS_CLEANUP
 *  filesystem cleanup & shut down for module extraction
 */
void cmsfs_cleanup()
  {
    cmsfs_error("cmsfs_cleanup()");
#ifdef  CONFIG_PROC_FS
        rpc_proc_unregister("cms");
#endif
    unregister_filesystem(&cms_fs_type);
  }
 
 
/* -------------------------------------------------------- CMSFS_MODULE
 *  additional routines required when CMS FS is built as a module
 */
 
#ifdef  MODULE
 
MODULE_AUTHOR(CMSFS_AUTHOR);
MODULE_DESCRIPTION(CMSFS_DESCRIPTION);
/*
MODULE_SUPPORTED_DEVICE(name)
MODULE_PARM(var,type)
MODULE_PARM_DESC(var,desc)
 */
 
EXPORT_NO_SYMBOLS;
 
int init_module() { return cmsfs_init(); }
void cleanup_module() { cmsfs_cleanup(); }
 
/*  {
module.name = "cmsfs";
module.init = &cmsfs_init();
module.cleanup = &cmsfs_cleanup();
    }  */
 
#endif  /* MODULE */
 
 
 
/*
struct inode {
        struct list_head        i_hash;
        struct list_head        i_list;
        struct list_head        i_dentry;
 
        unsigned long           i_ino;
        unsigned int            i_count;
        kdev_t                  i_dev;
        umode_t                 i_mode;
        nlink_t                 i_nlink;
        uid_t                   i_uid;
        gid_t                   i_gid;
        kdev_t                  i_rdev;
        off_t                   i_size;
        time_t                  i_atime;
        time_t                  i_mtime;
        time_t                  i_ctime;
        unsigned long           i_blksize;
        unsigned long           i_blocks;
        unsigned long           i_version;
        unsigned long           i_nrpages;
        struct semaphore        i_sem;
        struct semaphore        i_atomic_write;
        struct inode_operations *i_op;
        struct super_block      *i_sb;
        struct wait_queue       *i_wait;
        struct file_lock        *i_flock;
        struct vm_area_struct   *i_mmap;
        struct page             *i_pages;
        struct dquot            *i_dquot[MAXQUOTAS];
 
        unsigned long           i_state;
 
        unsigned int            i_flags;
        unsigned char           i_pipe;
        unsigned char           i_sock;
 
        int                     i_writecount;
        unsigned int            i_attr_flags;
        __u32                   i_generation;
        union {
                struct pipe_inode_info          pipe_i;
                struct minix_inode_info         minix_i;
                struct ext2_inode_info          ext2_i;
                struct hpfs_inode_info          hpfs_i;
                struct ntfs_inode_info          ntfs_i;
                struct msdos_inode_info         msdos_i;
                struct umsdos_inode_info        umsdos_i;
                struct iso_inode_info           isofs_i;
                struct nfs_inode_info           nfs_i;
                struct sysv_inode_info          sysv_i;
                struct affs_inode_info          affs_i;
                struct ufs_inode_info           ufs_i;
                struct efs_inode_info           efs_i;
                struct romfs_inode_info         romfs_i;
                struct coda_inode_info          coda_i;
                struct smb_inode_info           smbfs_i;
                struct hfs_inode_info           hfs_i;
                struct adfs_inode_info          adfs_i;
                struct qnx4_inode_info          qnx4_i;
                struct reiserfs_inode_info      reiserfs_i;
                struct socket                   socket_i;
                void                            *generic_ip;
        } u;
};
 */
 
 
 
/*
struct file {
        struct file             *f_next, **f_pprev;
        struct dentry           *f_dentry;
        struct file_operations  *f_op;
        mode_t                  f_mode;
        loff_t                  f_pos;
        unsigned int            f_count, f_flags;
        unsigned long           f_reada, f_ramax, f_raend, f_ralen, f_rawin;
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
        int                     f_error;
 
        unsigned long           f_version;
 
        void                    *private_data;
};
 */
 
 
 
/* previous end-of-file */
 
 
/*
From: Alan Cox [alan@lxorguk.ukuu.org.uk]
Sent: Friday, October 27, 2000 12:34 PM
To: Rick Troth
Cc: Alan Cox
Subject: Re: FW: radio amateur too?
 
> To make a CMS volume  "mountable",  I know I've got to fill-in
> a superblock that the kernel hands to me.   It appears that I
> also need to allocate a  "dnode",  which I presume itself
> points to an  inode.   The inodes and superblocks I think I've got.
> It's the dnode that I don't understand.   Can you enlighten me
> on how they relate?
 
inodes are actual objects - eg files.
dnodes are namespace -eg /proc   /bin   ls etc
 
So what you normally end up doing in read_super is:
 
        MOD_INC_USE_COUNT;  [done]
        lock_super(s); [done]
 
Now nobody can run off with stuff
 
        set_blocksize(dev, CMSBLOCKSIZE);  [done]
        s->s_blocksize=CMSBLOCKSIZE;  [done]
        s->s_blocksize_bits = CMSBLOCKBITS;  [done]
 
Now the kernel knows the block sizes for I/O
 
Typically it then reads the blocks from disk for the controlling info
(eg magic numbers, index headers etc) using bread
 
so something like
 
        bh = bhread(dev, 0, CMSBLOCKSIZE);  [done outside of "mount"]
 
would read the first block. bh->b_data then points to the data in that block.
(and brelse(bh) allows it to be flushed)
 
        s->s_magic = CMS_MAGIC;
        s->s_flags |= MS_RDONLY;
 
        s->s_op = &cms_sops;  [done]
 
Now the inode/dnode stuff. You dont actually need a real inode for your index,
you can just pick a number that wont occur elsewhere (eg set its inode number
to 1, and number the files off sequentially from it)
 
        root_inode = iget(s, ROOT_INODE);
        if(!root_inode)
                ... oops...
        s->s_root = d_alloc_root(root_inode, NULL);
        if(!s->s_root0
                ....
 
Then set the operations - you can set different operations on the index inode
and the others if it helps
 
        s->s_root->d_op = &cms_index_dentry_operations;
 
        unlock_super(s);  [done]
        return s;  [done]
 */
 
 
 
/* legit end-of-file */
