*
*/
-#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;
}
- 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 ;
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
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;
}
{
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)
*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;
}
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)
{
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;
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) {
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;
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;
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 */
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);
}
}
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)
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: {
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)
}
*/
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;
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;
break;
}
-
default:
rc = -EINVAL;
break;
}
- freedata(karg, input.len);
- EXIT;
- return rc;
+ freedata(karg, &input);
+ RETURN(rc);
}