Whamcloud - gitweb
remove unecessary debugging
[fs/lustre-release.git] / lustre / snapfs / snaptable.c
index 058164b..5759058 100644 (file)
@@ -6,53 +6,28 @@
  *
  */
 
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/malloc.h>
-#include <linux/locks.h>
-#include <linux/errno.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-#include <linux/vmalloc.h>
-#include <linux/blkdev.h>
-#include <linux/sysrq.h>
-#include <linux/file.h>
-#include <linux/init.h>
-#include <linux/quotaops.h>
+#define DEBUG_SUBSYSTEM S_SNAP
 
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/snap.h>
+#include <linux/time.h>
 #include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/mmu_context.h>
+#include "snapfs_internal.h" 
 
-#include <linux/filter.h>
-#include <linux/snapsupport.h>
-#include <linux/snapfs.h>
 
 struct snap_table snap_tables[SNAP_MAX_TABLES];
 
-#if 0
-static void snap_lock_table(int table_no)
-{
-
-       spin_lock(snap_tables[table_no].tbl_lock);
-
-}
-
-static void snap_unlock_table(int table_no)
-{
-
-       spin_unlock(snap_tables[table_no].tbl_lock);
-
-}
-#endif
-
 int snap_index2slot(struct snap_table *snap_table, int snap_index)
 {
        int slot;
 
-       for ( slot=0 ; slot<snap_table->tbl_count ; slot++ )
-               if ( snap_table->tbl_index[slot] == snap_index )
+       for ( slot=0 ; slot < snap_table->tbl_count ; slot++ )
+               if ( snap_table->snap_items[slot].index == snap_index )
                        return slot;
        return -1;
 }
@@ -63,7 +38,8 @@ int snap_index2slot(struct snap_table *snap_table, int snap_index)
    -  the index of the latest snapshot before NOW
    -  hence it returns 0 in case all the volume snapshots lie in the future
    -  this is the index where a COW will land (will be created) 
- */
+*/
+
 void snap_last(struct snap_cache *info, struct snap *snap)
 {
        int i ;
@@ -73,9 +49,10 @@ void snap_last(struct snap_cache *info, struct snap *snap)
 
        ENTRY;
        if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid table no %d\n", tableno);
+               CERROR("invalid table no %d\n", tableno);
                snap->index = -1;
        }
+       
        table = &snap_tables[tableno];
 
        /* start at the highest index in the superblock 
@@ -83,16 +60,11 @@ void snap_last(struct snap_cache *info, struct snap *snap)
        i = table->tbl_count - 1;
 
        /* NOTE: i>0 is an unnecessary check */
-       while ( table->tbl_times[i] > now && i > 0) {
-               CDEBUG(D_SNAP, "time: %ld, i: %d\n", table->tbl_times[i], i);
-               i--;
-       }
-
-       snap->index = table->tbl_index[i];
-       snap->time = table->tbl_times[i];
+       snap->index = table->snap_items[i].index;
+       snap->time = table->snap_items[i].time;
+       snap->gen = table->snap_items[i].gen;
        CDEBUG(D_SNAP, "index: %d, time[i]: %ld, now: %ld\n",
               snap->index, snap->time, now);
-       EXIT;
        return;
 }
 
@@ -104,372 +76,427 @@ int snap_needs_cow(struct inode *inode)
 {
        struct snap snap;
        struct snap_cache *cache;
+       struct filter_inode_info   *filter_info; 
        int index = -1;
        ENTRY;
 
        cache = snap_find_cache(inode->i_dev);
        if ( !cache ) {
-               EXIT;
-               return -1;
+               RETURN(index);
        }
-
+       filter_info = (struct filter_inode_info *) inode->i_filterdata;
        /* here we find the time of the last snap to compare with */
-       snap_last(cache, &snap);
 
+       snap_last(cache, &snap);
        /* decision .... if the snapshot is more recent than the object,
         * then any change to the object should cause a COW.
         */
-       if (inode->i_mtime <= snap.time && inode->i_ctime <= snap.time) {
+       if (filter_info && filter_info->generation < snap.gen ) {
                index = snap.index;
        }
-       printk("snap_needs_cow, ino %lu , get index %d\n",inode->i_ino, index);
 
-       EXIT;
-       return index;
+       CDEBUG(D_SNAP, "snap_needs_cow, ino %lu , get index %d\n",
+              inode->i_ino, index);
+
+       RETURN(index);
 } /* snap_needs_cow */
 
-#if 0
-int  snap_obd2snap(struct snap_clone_info *info, struct snap *snap)
+int snap_print_table(struct ioc_snap_tbl_data *data, char *buf, int *buflen)
 {
        struct snap_table *table;
-       int tableno = info->clone_cache->cache_snap_tableno;
-       int index =  info->clone_index;
-       int slot;
+       struct ioc_snap_tbl_data *stbl_out;
+       int tableno = data->no;
+       int i, rc = 0, nleft = (*buflen);
 
-       ENTRY;
-       if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid table no %d\n", tableno);
-               snap->index = -1;
+       char *buf_ptr;
+
+       if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
+               CERROR("invalid table number %d\n", tableno);
+               RETURN(-EINVAL);
        }
+       
        table = &snap_tables[tableno];
-       slot = snap_index2slot(table, index);
-
-       snap->index = index;
-       snap->time = table->tbl_times[slot];
-       EXIT;
-       return slot;
+       stbl_out = (struct ioc_snap_tbl_data *)buf;
+       stbl_out->count = table->tbl_count - 1;
+       stbl_out->no = tableno; 
+       buf_ptr = (char*)stbl_out->snaps; 
+       nleft -= buf_ptr - buf; 
+       for (i = 1; i < table->tbl_count; i++) {
+               memcpy(buf_ptr, &table->snap_items[i], sizeof(struct snap));
+               
+               nleft -= sizeof(struct snap);
+               if(nleft < 0) { 
+                       CERROR("can not get enough space to print snaptable\n");
+                       rc = -ERANGE;
+                       goto exit; 
+               } else {
+                       buf_ptr += sizeof(struct snap);
+               }       
+       }
+exit:
+       if(nleft > 0) 
+               (*buflen) = (*buflen) - nleft;
+       return 0;
 }
-#endif
-
-/* at what index is the current snapshot located */
-int snap_current(struct snap_cache *cache)
+static int inline get_index_of_item(struct snap_table *table, char *name)
 {
-       int tableno = cache->cache_snap_tableno;
-
-       return snap_tables[tableno].tbl_index[0];
+       int count = table->tbl_count;
+       int i, j;
+       
+       for (i = 0; i < SNAP_MAX; i++) { 
+               if (!strcmp(name, table->snap_items[i].name)) 
+                       return -EINVAL; 
+       }
+       for (i = 0; i < SNAP_MAX; i++) {
+               int found = 0;
+               for (j = 0; j < (count + 1); j++) {
+                       if (table->snap_items[j].index == i) {
+                               found = 1;
+                               break;  
+                       }
+                }
+               if (!found)
+                       return i;
+       }
+       return -EINVAL;
 }
-
-int snap_is_used(int table_no, int snap_index) 
-
+/* This function will write one item(a snapshot) to snaptable  
+ * and will also write to disk.
+ */
+static int snaptable_add_item(struct ioc_snap_tbl_data *data)
 {
-       /* ENTRY; */
-       if ( snap_index < 0 || snap_index >= SNAP_MAX ) {
-               printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
-                      snap_index, table_no);
-               EXIT;
-               return -1;
-       }
-       if ( table_no < 0 || table_no > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
-                      snap_index, table_no);
-               EXIT;
-               return -1;
-       }
+       struct snap_table               *table;
+       struct snap_disk_table          *disk_snap_table;
+       struct snapshot_operations      *snapops;
+       struct snap_cache               *cache;
+       int                             tableno , index, i, count, rc;
+       
+       if (!(cache = snap_find_cache((kdev_t)data->dev)))
+               RETURN(-ENODEV);
 
-       /* EXIT; */
-       return snap_tables[table_no].tbl_used & (1<<snap_index);
-}
+       snapops = filter_c2csnapops(cache->cache_filter);
+       if (!snapops || !snapops->set_meta_attr)
+               RETURN(-EINVAL);
 
-void snap_use(int table_no, int snap_index) 
-{
-       if ( snap_index < 0 || snap_index >= SNAP_MAX ) {
-               printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
-                      snap_index, table_no);
-               return;
+       tableno = data->no;
+       if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
+               CERROR("invalid table number %d\n", tableno);
+               RETURN(-EINVAL);
        }
-       if ( table_no < 0 || table_no > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
-                      snap_index, table_no);
-               return;
-       }
-       if ( snap_index2slot(&snap_tables[table_no], snap_index) < 0 ) 
-               return;
+       table = &snap_tables[tableno];  
+       count = table->tbl_count;
 
-       snap_tables[table_no].tbl_used |=  (1<<snap_index);
-}
+       /* XXX Is down this sema necessary*/
+       down_interruptible(&table->tbl_sema);
 
-void snap_unuse(int table_no, int snap_index) 
-{
-       if ( snap_index < 0 || snap_index >= SNAP_MAX ) {
-               printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
-                      snap_index, table_no);
-               return;
-       }
-       if ( table_no < 0 || table_no > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid snapno %d,table %d\n",
-                      snap_index, table_no);
-               return;
+       /*add item in snap_table set generation*/
+       table->snap_items[count].gen = table->generation + 1;
+       table->snap_items[count].time = CURRENT_TIME;
+       /* find table index */
+       index = get_index_of_item(table, data->snaps[0].name);
+       if (index < 0) {
+               CERROR("snaptable full Or Duplicate name in snaptable\n");
+               GOTO(exit, rc = -EINVAL);
        }
-       if ( snap_index2slot(&snap_tables[table_no], snap_index) < 0 ) 
-               return;
-
-       snap_tables[table_no].tbl_used &=  ~(1<<snap_index);
+       
+       table->snap_items[count].index = index;
+       table->snap_items[count].flags = 0;
+       memcpy(&table->snap_items[count].name[0], 
+              data->snaps[0].name, SNAP_MAX_NAMELEN);
+       /* we will write the whole snap_table to disk */
+       SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
+       if (!disk_snap_table)
+               GOTO(exit, rc = -ENOMEM);
+       disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
+       disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count);
+       disk_snap_table->generation = cpu_to_le32((__u32)table->generation + 1);
+       memset(&disk_snap_table->snap_items[0], 0, 
+              SNAP_MAX * sizeof(struct snap_disk));
+       
+       for (i = 1; i <= count; i++) {
+               struct snap *item = &table->snap_items[i];
+               disk_snap_table->snap_items[i-1].time = cpu_to_le64((__u64)item->time);
+               disk_snap_table->snap_items[i-1].gen = cpu_to_le32((__u32)item->gen);
+               disk_snap_table->snap_items[i-1].flags = cpu_to_le32((__u32)item->flags);
+               disk_snap_table->snap_items[i-1].index = cpu_to_le32((__u32)item->index);
+               memcpy(&disk_snap_table->snap_items[i-1].name , item->name, SNAP_MAX_NAMELEN);
+       }
+       rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
+                                   (char*)disk_snap_table, sizeof(struct snap_disk_table));
+
+       SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
+       table->tbl_count++;
+       table->generation++;
+exit:
+       up(&table->tbl_sema);
+       RETURN(rc);
 }
 
-static int nprint_buf(char *buf, int buflen, char *fmt, ...)
+static int delete_inode(struct inode *primary, void *param)
 {
-        va_list args;
-        int n;
-       char local_buf[1024];
+       struct snap_iterdata * data;
+       int tableno = 0;
+       int index = 0;
+       int rc = 0;
 
-        va_start(args, fmt);
-        n = vsprintf(local_buf, fmt, args);
-        va_end(args);
-       
-       if( n > buflen ) {
-               if( buflen > 1024)      buflen=1024;
-               memcpy(buf, local_buf, buflen);
-               return buflen;
-       }
-       else {
-               memcpy(buf, local_buf, n);
-               return n;
-       }
-}
-       
-int snap_print_table(struct snap_table_data *data, char *buf, int *buflen)
-{
-       int tableno = data->tblcmd_no;
-       int i;
+       struct inode *redirect;
+       ino_t old_ind = 0;
        struct snap_table *table;
-       char *buf_ptr;
-       int nleft = (*buflen);
-       int nprint = 0;
+       int slot;
+       int delete_slot;
+       int this_index;
+       struct inode *next_ind = NULL;
+       int my_table[SNAP_MAX];
 
-       if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid table number %d\n", tableno);
-               EXIT;
-               return -EINVAL;
+       ENTRY;
+
+       if(!primary) RETURN(0);
+
+       data = (struct snap_iterdata*) param;
+
+       if (data) {
+               index = data->index;
+               tableno = data->tableno;
        }
 
+       CDEBUG(D_SNAP, "delete_inode ino %lu, index %d\n", primary->i_ino, index);
+
        table = &snap_tables[tableno];
 
-       printk("------- snap table %d\n", tableno);
-       printk("     -- snap count %d\n", table->tbl_count);
-       printk("     -- snap used  0x%x\n", table->tbl_used);
-       for ( i = 0 ; i < SNAP_MAX ; i++ ) {
-               printk("     -- slot %d, idx %d, time %ld, name %s\n",
-                      i, table->tbl_index[i], table->tbl_times[i], 
-                       table->tbl_name[i]);
+       redirect = snap_get_indirect(primary, NULL, index);
+
+       if (!redirect) {
+               CDEBUG(D_SNAP, "redirect inode index %d not exist \n", index);
+               RETURN(0); 
        }
+       old_ind = redirect->i_ino;
+       iput(redirect);
 
-       buf_ptr = buf;
-       nprint= nprint_buf(buf_ptr, nleft, "------- snap table %d\n", tableno);
-       nleft -= nprint;
-       if( nleft > 0 )  buf_ptr += nprint;
-       else goto exit; 
-       nprint = nprint_buf(buf_ptr, nleft, "     -- snap count %d\n", table->tbl_count);
-       nleft -= nprint;
-       if( nleft > 0 )  buf_ptr += nprint;
-       else goto exit;
-       nprint = nprint_buf(buf_ptr, nleft, "     -- snap used  0x%x\n", table->tbl_used);
-       nleft -= nprint;
-       if( nleft > 0 )  buf_ptr += nprint;
-       else goto exit;
-       for ( i = 0 ; i < SNAP_MAX ; i++ ) {
-               nprint = nprint_buf( buf_ptr, nleft,
-                       "     -- slot %d, idx %d, time %ld, name %s\n",
-                      i, table->tbl_index[i], table->tbl_times[i], 
-                       table->tbl_name[i]);
-               nleft -= nprint;
-               if( nleft > 0 )  buf_ptr += nprint;
-               else goto exit;
+       /* In destroy indirect inode, we lock the primary inode here */
+       down(&primary->i_sem);  
+       slot = snap_index2slot(table, index) - 1;
+       if (slot > 0) {
+               this_index = table->snap_items[slot].index;
+               redirect = snap_get_indirect(primary, NULL, this_index);
+               if (redirect) { 
+                       iput(redirect);
+               } else {
+                       snap_set_indirect(primary, old_ind, this_index, 0);
+                       snap_set_indirect(primary, 0, index, 0);
+                       up(&primary->i_sem);            
+                       RETURN(0);
+               }
        }
+       
+       delete_slot = snap_index2slot(table, index);
+       for (slot = table->tbl_count - 1; slot > delete_slot; slot --) {
+               my_table[slot - delete_slot] = table->snap_items[slot].index;
+       }
+       
+       this_index = table->tbl_count - delete_slot - 1;
+       next_ind = snap_get_indirect(primary, my_table, this_index);
 
-exit:
-       if(nleft > 0) (*buflen) = (*buflen) - nleft;
+       if (next_ind && (next_ind->i_ino == primary->i_ino)) {
+               iput(next_ind);
+               next_ind = NULL;
+       }
+       rc = snap_destroy_indirect(primary, index, next_ind);
+
+       up(&primary->i_sem);
+       
+       if (next_ind)   iput(next_ind);
+       
+       if (rc != 0)    
+               CERROR("snap_destroy_indirect(ino %lu,index %d),ret %d\n",
+                       primary->i_ino, index, rc);
+       RETURN(0);
+}
+
+static int snap_delete(struct super_block *sb, struct snap_iterdata *data)
+{
+       CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
+               data->dev, data->tableno, data->index, data->time );
 
+       snap_iterate(sb, &delete_inode, NULL, data, SNAP_ITERATE_COWED_INODE);
+       
        return 0;
 }
 
-int snap_install_table(int len, struct snap_table_data *data)
+/* This function will delete one item(a snapshot) in the snaptable  
+ * and will also delete the item in the disk.
+ * FIXME later, this should be in a transaction.
+ */
+int snaptable_delete_item(struct super_block *sb, struct snap_iterdata *data)
 {
-       int i, j;
-       int tableno = data->tblcmd_no;
-//     int found_current;
-       struct snap_table *table;
+       struct snap_table               *table;
+       struct snap_disk_table          *disk_snap_table;
+       struct snapshot_operations      *snapops;
+       struct snap_cache               *cache;
+       int                             tableno = data->tableno; 
+       int                             index, i, del_slot, rc;
+       
+       if (!(cache = snap_find_cache((kdev_t)data->dev)))
+               RETURN(-ENODEV);
 
-       if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid table number %d\n", tableno);
-               EXIT;
-               return -EINVAL;
+       if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
+               CERROR("invalid table number %d\n", tableno);
+               RETURN(-EINVAL);
        }
-       table = &snap_tables[tableno];  
 
-       /* for each index that is used by the current table
-          we need to make sure that the new table we are about
-          to put in contains that index too 
-       */
-       for ( i = 0; i < SNAP_MAX ; i++ ) {
-               int foundit;
-               int err;
+       snapops = filter_c2csnapops(cache->cache_filter);
+       if (!snapops || !snapops->set_meta_attr)
+               RETURN(-EINVAL);
+       
+       index = data->index;
+       if (clonefs_mounted(cache, index)) {
+               CERROR("Please first umount this clonefs \n");
+               RETURN(-EBUSY);         
+       }       
+       /*first delete the snapshot
+        * FIXME if snap delete error, how to handle this error*/
+       rc = snap_delete(sb, data);
+       if (rc) 
+               RETURN(-EINVAL);
+       /*delete item in snaptable */
+       table = &snap_tables[tableno];
 
-               if ((err = snap_is_used(tableno, i)) < 0 ) {
-                       printk(__FUNCTION__  ": table %d not used\n", tableno);
-                       EXIT;
-                       return -EINVAL;
-               } else if (err == 0) {
-                       continue;
-               }
+       del_slot = snap_index2slot(table, index);
+       if (del_slot < 0)
+               RETURN(-EINVAL);
 
-               foundit = 0;
-               for (j = 0 ; j<= data->tblcmd_count ; j++) {
-                       if ( i == data->tblcmd_snaps[j].index ) {
-                               foundit = 1;
-                               break;
-                       }
-               }
-               if ( !foundit ) {
-                       printk(__FUNCTION__ ": index %d not in table %d\n", 
-                              i, tableno);
-                       return -EINVAL;
-               }
-       }
+       down_interruptible(&table->tbl_sema);
+       
+       SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
 
-       /* we must have:
-           - valid indices 
-          - a current snapshot in the table 
-          - increasing snapshot times 
-       */
-//     found_current = 0;
-       CDEBUG(D_SNAP, "snaplist: tblcmd_count %d\n", data->tblcmd_count);
-       for (i = 0 ; i < data->tblcmd_count ; i++) {
-
-               if ( (data->tblcmd_snaps[i].index < 0) ||
-                    (data->tblcmd_snaps[i].index >= SNAP_MAX) ) {
-                       printk(__FUNCTION__ ": snap_index out of range!\n");
-                       return -EINVAL;
-               }
+       if (!disk_snap_table) {
+               up(&table->tbl_sema);
+               RETURN(-ENOMEM);
+       }
 
-               if (i>0 && data->tblcmd_snaps[i].time <= 
-                   data->tblcmd_snaps[i-1].time) {
-                       printk(__FUNCTION__ ": times not increasing\n");
-                       return -EINVAL;
-               }
+       /* we will delete the item  snap_table to disk */
 
-//             if ( 0 == data->tblcmd_snaps[i].time ) {
-//                     found_current = 1;
-//                     break;
-//             }
-       }
-//     if ( !found_current ) {
-//             printk(__FUNCTION__ "no current snapshot in table\n");
-//             return -EINVAL;
-//     }
-
-       /* ready to go: over write the table */
-/*     
-       for (i = 0 ; i < data->tblcmd_count ; i++) {
-
-               table->tbl_times[i] = data->tblcmd_snaps[i].time;
-               table->tbl_index[i] = data->tblcmd_snaps[i].index;
-               memcpy(table->tbl_name[i], data->tblcmd_snaps[i].name, 
-                       SNAP_MAX_NAMELEN);
-               table->tbl_name[i][SNAP_MAX_NAMELEN - 1] = '\0';
-
-               CDEBUG(D_SNAP, "snaplist: i %d, time %ld, idx %d, name %s\n",
-                      i, table->tbl_times[i], table->tbl_index[i], 
-                       table->tbl_name[i]);
-       }
-*/
-       /* below : new, we don't need current snapshot for data
-        * current snapshot always has slot 0, index 0, name "current" 
-        */
-       table->tbl_times[0] = 0;
-       table->tbl_index[0] = 0;
-       strcpy(table->tbl_name[0], "current");
-
-       i=0;    
-       CDEBUG(D_SNAP, "snaplist: i %d, time %ld, idx %d, name %s\n",
-              i, table->tbl_times[i], table->tbl_index[i], 
-               table->tbl_name[i]);
-
-       for (i = 0 ; i < data->tblcmd_count ; i++) {
-
-               table->tbl_times[i+1] = data->tblcmd_snaps[i].time;
-               table->tbl_index[i+1] = data->tblcmd_snaps[i].index;
-               memcpy(table->tbl_name[i+1], data->tblcmd_snaps[i].name, 
-                       SNAP_MAX_NAMELEN);
-               table->tbl_name[i+1][SNAP_MAX_NAMELEN - 1] = '\0';
-
-               CDEBUG(D_SNAP, "snaplist: i %d, time %ld, idx %d, name %s\n",
-                      i+1, table->tbl_times[i+1], table->tbl_index[i+1], 
-                       table->tbl_name[i+1]);
+       index = del_slot;
+       /*Move the items after the delete slot forward one step*/
+       memset(&table->snap_items[index], 0, sizeof(struct snap));
+       while(index < table->tbl_count - 1) {
+               struct snap *item = &table->snap_items[index];
+                       
+               item->time = table->snap_items[index + 1].time;
+               item->flags = table->snap_items[index + 1].flags;
+               item->gen = table->snap_items[index + 1].gen;
+               item->index = table->snap_items[index + 1].index;
+               memcpy(&item->name[0], &table->snap_items[index + 1].name[0],
+                      SNAP_MAX_NAMELEN);
+               index ++;
        }
 
-       for ( i = data->tblcmd_count + 1 ; i < SNAP_MAX ; i++ ) {
-               table->tbl_times[i] = 0;
-               table->tbl_index[i] = 0;
-               memset(table->tbl_name[i], 0, SNAP_MAX_NAMELEN);
+       table->tbl_count --;
+               
+       disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC);
+       disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count - 1);
+       disk_snap_table->generation = cpu_to_le32((__u32)table->generation + 1);
+       memset(&disk_snap_table->snap_items[0], 0, 
+              SNAP_MAX * sizeof(struct snap_disk));
+
+       for (i = 0; i < table->tbl_count - 1; i++) {
+               struct snap_disk *disk_item = &disk_snap_table->snap_items[i];
+               struct snap *item = &table->snap_items[i+1];
+               
+               disk_item[i].time = cpu_to_le64((__u64)item->time);
+               disk_item[i].gen = cpu_to_le32((__u32)item->gen);
+               disk_item[i].flags = cpu_to_le32((__u32)item->flags);
+               disk_item[i].index = cpu_to_le32((__u32)item->index);
+               memcpy(&disk_item[i].name , item->name, SNAP_MAX_NAMELEN);
        }
 
-       /* set the table count */
-//     table->tbl_count = data->tblcmd_count;
-       table->tbl_count = data->tblcmd_count + 1;
-       return 0;
-}
+       rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
+                                   (char*)disk_snap_table, sizeof(struct snap_disk_table));
 
+       SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
+       
+       up(&table->tbl_sema);
+       RETURN(rc);
+}
 
-int snap_table_attach(int tableno, int snap_index) 
+int snapfs_read_snaptable(struct snap_cache *cache, int tableno)
 {
-       struct snap_table *table;
+       struct snap_table               *table;
+       struct snap_disk_table          *disk_snap_table;
+       struct snapshot_operations      *snapops;
+       int                             i, rc;
+       int                             size = 0;
 
-       if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid table number %d\n", tableno);
-               EXIT;
-               return -EINVAL;
-       }
-       table = &snap_tables[tableno];  
        
-       if ( snap_index2slot(table, snap_index) < 0 ) {
-               printk(__FUNCTION__ ": snap index %d not present in table %d\n",
-                      snap_index, tableno);
-               return -EINVAL;
-       }
+       snapops = filter_c2csnapops(cache->cache_filter);
+       if (!snapops || !snapops->get_meta_attr)
+               RETURN(-EINVAL);
+       
+       SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
 
-       snap_use(tableno, snap_index);
+       size = sizeof(struct snap_disk_table);
+
+       
+       table = &snap_tables[tableno];
+
+       memset(table, 0, sizeof(struct snap_table));
+        init_MUTEX(&table->tbl_sema); 
+
+       /*Initialized table */
+       table->tbl_count = 1;
+       rc = snapops->get_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR,
+                              (char*)disk_snap_table, &size);
+       if (rc < 0) {
+               SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
+               RETURN(rc);
+       }
+       
+       if (le32_to_cpu(disk_snap_table->magic) != DISK_SNAP_TABLE_MAGIC) {
+               CERROR("On disk snaptable is not right \n");
+               RETURN(rc);
+       }
+       table->generation = le32_to_cpu(disk_snap_table->generation);
+       table->tbl_count += le32_to_cpu(disk_snap_table->count);
+       for ( i = 0; i < disk_snap_table->count; i++) {
+               struct snap *item = &table->snap_items[i + 1];
+               item->time = le64_to_cpu(disk_snap_table->snap_items[i].time);
+               item->gen = le32_to_cpu(disk_snap_table->snap_items[i].gen);
+               item->flags = le32_to_cpu(disk_snap_table->snap_items[i].flags);
+               item->index = le32_to_cpu(disk_snap_table->snap_items[i].index);
+               memcpy(&item->name[0], &disk_snap_table->snap_items[i].name[0],
+                      SNAP_MAX_NAMELEN);
+       }
+       SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table));
        return 0;
 }
 
-static int getdata(int len, void **data)
+static int getdata(struct ioc_data *input, void **karg)
 {
        void *tmp = NULL;
 
-       if (!len) {
-               *data = NULL;
+       if (!input->ioc_inlen || !input->ioc_inbuf) 
                return 0;
-       }
 
-       SNAP_ALLOC(tmp, void *, len);
-       if ( !tmp )
-               return -ENOMEM;
+       SNAP_ALLOC(tmp, input->ioc_inlen);
+       if (!tmp)
+               RETURN(-ENOMEM);
 
-       CDEBUG(D_MALLOC, "snap_alloc:len %d, add %p\n", len, tmp);
+       CDEBUG(D_SNAP, "snap_alloc:len %d, add %p\n", input->ioc_inlen, tmp);
 
-       memset(tmp, 0, len);
-       if ( copy_from_user(tmp, *data, len)) {
-               SNAP_FREE(tmp, len);
-               CDEBUG(D_MALLOC, "snap_free:len %d, add %p\n", len, tmp);
-               return -EFAULT;
+       memset(tmp, 0, input->ioc_inlen);
+       if (copy_from_user(tmp, input->ioc_inbuf, input->ioc_inlen)) {
+               CERROR("get inbuf data error \n");
+               SNAP_FREE(tmp, input->ioc_inlen);
+               RETURN(-EFAULT);
        }
-       *data = tmp;
+       *karg = tmp;
 
        return 0;
 }
 
-static void freedata(void *data, int len) {
-       SNAP_FREE(data, len);
-       CDEBUG(D_MALLOC, "snap_free:len %d, add %p\n", len, data);
+static inline void freedata(void *data, struct ioc_data *input) 
+{
+       SNAP_FREE(data, input->ioc_inlen);
+       CDEBUG(D_SNAP, "snap_free:len %d, add %p\n", input->ioc_inlen, data);
 }
 
 static int get_next_inode(struct inode *pri, void *ino)
@@ -527,7 +554,7 @@ static int snap_get_next_inode(struct snap_ino_list_data *data, ino_t *found_ino
        *parent_ino = 0;
        inode = iget (cache->cache_sb, *found_ino);
        if (list_empty(&inode->i_dentry)) {
-               printk("No dentry for ino %lu, Error(XXX)! \n", inode->i_ino);
+               CERROR("No dentry for ino %lu, Error(XXX)! \n", inode->i_ino);
                iput(inode);    
                        return 0;
        }
@@ -544,35 +571,6 @@ static int snap_get_next_inode(struct snap_ino_list_data *data, ino_t *found_ino
 
        return 0;
 }
-/*
-static int snap_get_inode_info(struct snap_ino_list_data *data,  int index)
-{
-       kdev_t dev = data->dev;
-       ino_t pri = data->ino; 
-       int index = data->index;
-
-       struct snap_cache *cache;
-
-       struct inode *pri;
-       struct inode *ind;
-       ino_t ind_ino = 0;
-
-       ENTRY;
-
-       cache = snap_find_cache(dev); 
-       if ( !cache ) {
-                EXIT;
-                return -EINVAL;
-        }
-       pri = iget(cache->cache->sb, pri_ino);
-       ind = snap_get_indirect(pri, NULL, index);
-       if(ind) {
-               ind_ino = ind->i_ino;   
-               iput(ind);
-       }
-       return ind_ino;
-}
-*/
 
 static int print_inode(struct inode *pri,void *param)
 {
@@ -586,94 +584,6 @@ static int snap_print(struct super_block *sb, void *data)
        return 0;
 }
 
-static int delete_inode(struct inode *primary, void *param)
-{
-       struct snap_iterdata * data;
-       int tableno = 0;
-       int index = 0;
-       int rc = 0;
-
-       struct inode *redirect;
-       ino_t old_ind = 0;
-       struct snap_table *table;
-       int slot;
-       int delete_slot;
-       int this_index;
-       struct inode *next_ind = NULL;
-       int my_table[SNAP_MAX];
-
-       if(!primary) return 0;
-
-       data = (struct snap_iterdata*) param;
-
-       if(data) {
-               index = data->index;
-               tableno = data->tableno;
-       }
-
-       printk("delete_inode ino %lu, index %d\n", primary->i_ino, index);
-
-       table = &snap_tables[tableno];
-
-       redirect = snap_get_indirect(primary, NULL, index);
-
-       if(!redirect)   
-               return 0;
-
-       old_ind = redirect->i_ino;
-       iput(redirect);
-       slot = snap_index2slot(table, index) - 1;
-       if( slot > 0 ) {
-               this_index = table->tbl_index[slot];
-               redirect = snap_get_indirect(primary, NULL, this_index);
-               if(redirect)    
-                       iput(redirect);
-               else  {
-                       snap_set_indirect(primary, old_ind, this_index, 0);
-                       snap_set_indirect(primary, 0, index, 0);
-                       return 0;
-               }
-       }
-
-       /* get the FIRST index after this and before NOW */
-       /* used for destroy_indirect and block level cow */
-       /* XXX fix this later, now use tbl_count, not NOW */
-       delete_slot = snap_index2slot(table, index);
-       for(slot = table->tbl_count; slot > delete_slot; slot --)
-       {
-               my_table[slot - delete_slot] = table->tbl_index[slot];
-       }
-       next_ind = snap_get_indirect 
-               (primary, my_table, table->tbl_count - delete_slot );
-       if( next_ind && (next_ind->i_ino == primary->i_ino) ) {
-               iput(next_ind);
-               next_ind = NULL;
-       }
-
-       if( next_ind && (next_ind->i_ino == old_ind) ) {
-               iput(next_ind);
-               next_ind = NULL;
-       }
-
-       rc = snap_destroy_indirect(primary, index, next_ind);
-
-       if(next_ind)    iput(next_ind);
-
-       if(rc != 0)     
-               printk("ERROR:snap_destroy_indirect(ino %lu,index %d),ret %d\n",                        primary->i_ino, index, rc);
-       return 0;
-}
-
-static int snap_delete(struct super_block *sb, struct snap_iterdata *data)
-//static int snap_delete(struct super_block *sb, void *data)
-{
-       CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
-               data->dev, data->tableno, data->index, data->time );
-
-       snap_iterate(sb,&delete_inode,NULL, data, SNAP_ITERATE_COWED_INODE);
-       return 0;
-}
-
 static int delete_new_inode(struct inode *pri, void *param)
 {
        struct snap_iterdata * data;
@@ -683,13 +593,12 @@ static int delete_new_inode(struct inode *pri, void *param)
 
        ENTRY; 
 
-       if(!pri) return 0;
-
-       if(snap_is_redirector(pri)){
-               EXIT;
-               return 0;
-       }
+       if(!pri) 
+               RETURN(0);
 
+       if(snap_is_redirector(pri))
+               RETURN(0);
+       
        data = (struct snap_iterdata*) param;
 
        if(data) {
@@ -706,19 +615,16 @@ static int delete_new_inode(struct inode *pri, void *param)
 
                CDEBUG(D_SNAP, "snap_restore ino %lu is newer, delete \n",pri->i_ino);
                for( pos = head->next; pos != head; pos = pos->next ){
-//                     d_invalidate( list_entry(pos, struct dentry, d_alias) );
                        d_drop( list_entry(pos, struct dentry, d_alias) );
                }
                pri->i_nlink = 0;
        }
-       return 0;
-
+       RETURN(0);
 }
 
 static int restore_inode(struct inode *pri, void *param)
 {
        struct snap_iterdata * data;
-//     struct snap_cache *cache;
        int tableno = 0;
 
        int index = 1;
@@ -728,12 +634,11 @@ static int restore_inode(struct inode *pri, void *param)
        int slot;
        int restore_slot;
        struct snap_table *table;
-//     int my_table[SNAP_MAX];
        int restore_index;
        
        ENTRY; 
 
-       if(!pri) return 0;
+       if(!pri) RETURN(0);
 
        data = (struct snap_iterdata*) param;
 
@@ -747,8 +652,7 @@ static int restore_inode(struct inode *pri, void *param)
                        pri->i_ino, index, restore_time, tableno);
 
                /* XXX: should we have = here? */       
-       if( pri->i_mtime > restore_time || pri->i_ctime > restore_time )
-       {
+       if(pri->i_mtime > restore_time || pri->i_ctime > restore_time) {
                restore_index = index;
                table = &snap_tables[tableno];
                /* first find if there are indirected at the index */
@@ -760,33 +664,18 @@ static int restore_inode(struct inode *pri, void *param)
                        for(slot = restore_slot; slot <= table->tbl_count; 
                            slot++) {
                                ind = snap_get_indirect (pri, NULL, 
-                                       table->tbl_index[slot]);
+                                       table->snap_items[slot].index);
                                if(ind) {
-                                       restore_index = table->tbl_index[slot];
+                                       restore_index = table->snap_items[slot].index;
                                        break;
                                }
                        }
-/*                     for(slot = table->tbl_count; slot >= restore_slot; 
-                               slot --)
-                       {
-                               my_table[slot - restore_slot + 1] = 
-                                       table->tbl_index[slot];
-                       }
-                       ind = snap_get_indirect (pri, my_table, 
-                                       table->tbl_count - restore_slot + 1);
-
-                       if( ind && (ind->i_ino == pri->i_ino) ) {
-                               iput(ind);
-                               ind =  NULL;
-                       }
-*/
                }
 
                if(ind) {
                        CDEBUG(D_SNAP, "restore ino %lu with index %d\n",
                                        pri->i_ino, restore_index);
                        iput(ind);
-//                     snap_restore_indirect(pri, index);
                        snap_restore_indirect(pri, restore_index);
                        /* XXX */
                        //delete_inode(pri, param);
@@ -797,10 +686,9 @@ static int restore_inode(struct inode *pri, void *param)
                }
        }
        else {
-               printk("ino %lu is older, don't restore\n",pri->i_ino);
+               CDEBUG(D_SNAP, "ino %lu is older, don't restore\n", pri->i_ino);
        }
-       EXIT;
-       return 0;
+       RETURN(0);
 }
 
 //int snap_restore(struct super_block *sb, void *data)
@@ -821,160 +709,140 @@ int snap_get_index_from_name(int tableno, char *name)
        int slot;
 
        if ( tableno < 0 || tableno > SNAP_MAX_TABLES ) {
-               printk(__FUNCTION__ ": invalid table number %d\n", tableno);
+               CERROR("invalid table number %d\n", tableno);
                return -EINVAL;
        }
 
        table = &snap_tables[tableno];
 
-       for ( slot = 0 ; slot < SNAP_MAX ; slot++ ) {
-/*             if(memcmp (table->tbl_name[slot], name, 
-                       strlen(table->tbl_name[slot]) ) == 0 ) {
-                       return table->tbl_index[slot];
-               }
-*/
-               if(strncmp (table->tbl_name[slot], name, 
-                       SNAP_MAX_NAMELEN) == 0 ) {
-                       return table->tbl_index[slot];
+       for ( slot = 0 ; slot < table->tbl_count; slot++) {
+               if (!strcmp(&table->snap_items[slot].name[0], name)) {
+                       return table->snap_items[slot].index;
                }
        }
        return -EINVAL;
 }
 
-int snap_iterate_func(int len, struct snap_ioc_data *ioc_data, unsigned int cmd)
+int snap_iterate_func( struct ioc_snap_tbl_data *data, unsigned int cmd)
 {
-       struct snap_iterdata data;
-
-       kdev_t dev ;
-       char name[SNAP_MAX_NAMELEN];
-
-       int index ;
-       int tableno; 
-       int name_len;
-       int slot;
-
+       struct snapshot_operations      *snapops;
+       struct snap_iterdata iterate_data;
        struct super_block *sb;
        struct snap_cache *cache;
        struct snap_table *table;
+       int index, tableno, slot, rc;
 
        ENTRY;
+       
+       if (!(cache = snap_find_cache((kdev_t)data->dev)))
+               RETURN(-ENODEV);
 
-       dev = ioc_data->dev;
-       cache = snap_find_cache(dev); 
-       if ( !cache ) {
-                EXIT;
-                return -EINVAL;
-        }
+       snapops = filter_c2csnapops(cache->cache_filter);
+       if (!snapops || !snapops->set_meta_attr)
+               RETURN(-EINVAL);
+
+       tableno = data->no;
+       if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
+               CERROR("invalid table number %d\n", tableno);
+               RETURN(-EINVAL);
+       }
 
        sb = cache->cache_sb;
-       tableno = cache->cache_snap_tableno;
        table = &snap_tables[tableno];
-
-       name_len = len - sizeof(kdev_t);        
-       memset(name, 0, SNAP_MAX_NAMELEN);      
-       if(name_len > SNAP_MAX_NAMELEN)
-               name_len = SNAP_MAX_NAMELEN;
-       if(name_len < 0 ) 
-               name_len = 0;
-       memcpy(name, ioc_data->name, name_len);
-       if ( (index = snap_get_index_from_name (tableno, name)) < 0 ) {
-               EXIT;
-               return -EINVAL;
-       }
        
-       data.dev = dev;
-       data.index = index;
-       data.tableno = tableno;
+       index = snap_get_index_from_name(tableno, data->snaps[0].name);
+       if (index < 0) {
+               CERROR("Could not find %s in snaptable\n", 
+                      data->snaps[0].name);
+               RETURN(-EINVAL);
+       }
+       iterate_data.dev = (kdev_t)data->dev;
+       iterate_data.index = index;
+       iterate_data.tableno = tableno;
        slot = snap_index2slot (table, index);
-       if( slot < 0 ) {
-               EXIT;
-               return -EINVAL;
-       }
-       data.time = table->tbl_times[slot];
-
+       if( slot < 0 ) 
+               RETURN(-EINVAL);
+       
+       iterate_data.time = table->snap_items[slot].time;
        CDEBUG(D_SNAP, "dev %d, tableno %d, index %d, time %lu\n",
-               data.dev, data.tableno, data.index, data.time );
+              iterate_data.dev, iterate_data.tableno, 
+              iterate_data.index, iterate_data.time);
 
        switch (cmd) {
                case IOC_SNAP_DEBUG:
-                       snap_print(sb, &data);  
+                       rc = snap_print(sb, &iterate_data);     
                        break;
                case IOC_SNAP_DELETE:
-                       snap_delete(sb, &data); 
+                       rc = snaptable_delete_item(sb, &iterate_data);  
                        break;
                case IOC_SNAP_RESTORE:
-                       snap_restore(sb, &data);        
+                       rc = snap_restore(sb, &iterate_data);   
                        break;
                default:
-                       return -EINVAL;
+                       CERROR("unrecognized cmd %d \n", cmd);
+                       rc = -EINVAL;
+                       break;
        }
-       
-       EXIT;
-
-       return 0;
+       RETURN(rc);
 }
 
+#define BUF_SIZE 1024
 int snap_ioctl (struct inode * inode, struct file * filp, 
                             unsigned int cmd, unsigned long arg)
 {
-       void *uarg, *karg;
-       int len;
-       int err;
-       kdev_t dev;
-       struct  {
-               int len;
-               char *data;
-       }input;
+       struct ioc_data input; 
+       void *karg = NULL;
        int rc = 0;
+       kdev_t dev;
 
        ENTRY;  
 
         dev = MINOR(inode->i_rdev);
         if (dev != SNAP_PSDEV_MINOR)
-                return -ENODEV;
+                RETURN(-ENODEV);
 
         if (!inode) {
                 CDEBUG(D_IOCTL, "invalid inode\n");
-                return -EINVAL;
+                RETURN(-EINVAL);
         }
 
         if ( _IOC_TYPE(cmd) != IOC_SNAP_TYPE || 
              _IOC_NR(cmd) < IOC_SNAP_MIN_NR  || 
              _IOC_NR(cmd) > IOC_SNAP_MAX_NR ) {
-                CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
+                /*FIXME: Sometimes Gettimeof the day will come here
+                * still do not know the reason*/
+               CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
                                 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
-                EXIT;
-                return -EINVAL;
+                RETURN(0);
         }
 
        /* get data structures */
-       err = copy_from_user(&input, (void *)arg, sizeof(input));
-       if ( err ) {
-               EXIT;
-               return err;
-       }
-       uarg = input.data;
-       len = input.len;
-
-       karg = input.data;
-       err = getdata(input.len, &karg);
-       if ( err ) {
-               EXIT;
-               return err;
-       }
-       
+       rc = copy_from_user(&input, (void *)arg, sizeof(input));
+       if (rc) RETURN(rc);
+
+       /* get data from the input data*/
+       rc = getdata(&input, &karg);
+       if (rc) RETURN(rc);
+
        switch (cmd) {
-       case IOC_SNAP_SETTABLE:
-               rc = snap_install_table(len, karg);
+       case IOC_SNAP_ADD: {
+               rc = snaptable_add_item(karg);
                break;
+       }
        case IOC_SNAP_PRINTTABLE: {
-               struct output_data{
-                       int len;
-                       char buf[1024];
-               }output;
-               output.len = sizeof(output.buf);
-               snap_print_table(karg, output.buf, &(output.len));
-               rc = copy_to_user((char *)arg, &output, output.len+sizeof(int));
+               struct ioc_data *output;
+               char   *tmp;
+               
+               SNAP_ALLOC(tmp, BUF_SIZE);
+               output=(struct ioc_data*)tmp;
+               output->ioc_inbuf = output->ioc_bulk;
+               output->ioc_inlen = BUF_SIZE - sizeof(int) - sizeof(unsigned long);
+               snap_print_table(karg, output->ioc_inbuf, &(output->ioc_inlen));
+               
+               rc = copy_to_user((char *)arg, output, 
+                                 (output->ioc_inlen + sizeof(int) + sizeof(unsigned long)));
+               SNAP_FREE(tmp, BUF_SIZE);
+
                break;
        }
        case IOC_SNAP_GETINDEXFROMNAME: {
@@ -992,7 +860,7 @@ int snap_ioctl (struct inode * inode, struct file * filp,
 
                struct get_index_struct *data = karg;
        
-               name_len = len - sizeof(kdev_t);        
+               name_len = input.ioc_inlen - sizeof(kdev_t);    
                dev = data->dev;
                memset(name, 0, SNAP_MAX_NAMELEN);      
                if(name_len > SNAP_MAX_NAMELEN)
@@ -1004,7 +872,8 @@ int snap_ioctl (struct inode * inode, struct file * filp,
                }
                */
                memcpy(name, data->name, name_len);
-               printk("dev %d , len %d, name_len %d, find name is [%s]\n", dev, len, name_len, name);
+               printk("dev %d , len %d, name_len %d, find name is [%s]\n", 
+                       dev, input.ioc_inlen, name_len, name);
                cache = snap_find_cache(dev); 
                if ( !cache ) {
                        EXIT;
@@ -1062,11 +931,13 @@ int snap_ioctl (struct inode * inode, struct file * filp,
        case IOC_SNAP_DELETE: 
        case IOC_SNAP_RESTORE:
        case IOC_SNAP_DEBUG:
-               rc = snap_iterate_func(len, karg, cmd);
+               rc = snap_iterate_func(karg, cmd);
                break;
+#ifdef SNAP_DEBUG
        case IOC_SNAP_DEVFAIL:
                snap_debug_failcode = (unsigned int)arg;
                break;
+#endif
        case IOC_SNAP_SHOW_DOTSNAP: {
                struct ioc_show_info{
                        kdev_t dev;
@@ -1087,13 +958,11 @@ int snap_ioctl (struct inode * inode, struct file * filp,
                
                break;
        }
-
        default:
                rc = -EINVAL;
                break;
        }
 
-       freedata(karg, input.len);
-       EXIT;
-       return rc;
+       freedata(karg, &input);
+       RETURN(rc);
 }