lh = &(snap_caches[snap_cache_hash(dev)]);
list_for_each_entry(cache, lh, cache_chain) {
- if ( cache->cache_dev == dev )
+ if (cache->cache_dev == dev)
return cache;
}
return NULL;
static int clonefs_readlink(struct dentry *dentry, char *buf, int len)
{
- int res;
struct inode * cache_inode;
struct inode * old_inode;
+ int rc = -ENOENT;
ENTRY;
cache_inode = clonefs_get_inode(dentry->d_inode);
- res = -ENOENT;
-
- if ( ! cache_inode ) {
+ if (!cache_inode) {
CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
- RETURN(res);
+ RETURN(rc);
}
/* XXX: shall we allocate a new dentry ?
/* set dentry inode to cache inode */
dentry->d_inode = cache_inode;
- if ( cache_inode->i_op->readlink ) {
- res = cache_inode->i_op->readlink(dentry, buf, len);
+ if (cache_inode->i_op->readlink) {
+ rc = cache_inode->i_op->readlink(dentry, buf, len);
}else {
CDEBUG(D_INODE,"NO readlink for ino %lu\n", cache_inode->i_ino);
}
iput(cache_inode);
- RETURN(res);
+ RETURN(rc);
}
static int clonefs_follow_link(struct dentry * dentry, struct nameidata *nd)
{
struct inode * cache_inode;
struct inode * old_inode;
- int res;
+ int rc = -ENOENT;
ENTRY;
cache_inode = clonefs_get_inode(dentry->d_inode);
- if ( ! cache_inode ) {
+ if (!cache_inode) {
CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
- RETURN(-ENOENT);
+ RETURN(rc);
}
/* XXX: shall we allocate a new dentry ?
/* set dentry inode to cache inode */
dentry->d_inode = cache_inode;
- if ( cache_inode->i_op->follow_link ) {
- res = cache_inode->i_op->follow_link(dentry, nd);
+ if (cache_inode->i_op->follow_link) {
+ rc = cache_inode->i_op->follow_link(dentry, nd);
}
/* restore the old inode */
iput(cache_inode);
- RETURN(res);
+ RETURN(rc);
}
+static ssize_t
+clonefs_getxattr(struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
+{
+ struct inode * cache_inode;
+ struct inode * old_inode;
+ int rc = -ENOENT;
+
+ ENTRY;
+
+ cache_inode = clonefs_get_inode(dentry->d_inode);
+ if (!cache_inode) {
+ CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
+ RETURN(rc);
+ }
+
+ /* XXX: shall we allocate a new dentry ?
+ The following is safe for ext2, etc. because ext2_follow_link
+ only use the inode info */
+ /* save the old dentry inode */
+ old_inode = dentry->d_inode;
+ /* set dentry inode to cache inode */
+ dentry->d_inode = cache_inode;
+
+ if (cache_inode->i_op->getxattr) {
+ rc = cache_inode->i_op->getxattr(dentry, name, buffer, size);
+ }
+
+ /* restore the old inode */
+ dentry->d_inode = old_inode;
+
+ iput(cache_inode);
+
+ RETURN(rc);
+}
+static ssize_t
+clonefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+ struct inode * cache_inode;
+ struct inode * old_inode;
+ int rc = -ENOENT;
+
+ ENTRY;
+
+ cache_inode = clonefs_get_inode(dentry->d_inode);
+ if (!cache_inode) {
+ CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n");
+ RETURN(rc);
+ }
+
+ /* XXX: shall we allocate a new dentry ?
+ The following is safe for ext2, etc. because ext2_follow_link
+ only use the inode info */
+
+ /* save the old dentry inode */
+ old_inode = dentry->d_inode;
+ /* set dentry inode to cache inode */
+ dentry->d_inode = cache_inode;
+
+ if (cache_inode->i_op->listxattr) {
+ rc = cache_inode->i_op->listxattr(dentry, buffer, size);
+ }
+
+ /* restore the old inode */
+ dentry->d_inode = old_inode;
+
+ iput(cache_inode);
+
+ RETURN(rc);
+
+}
struct inode_operations clonefs_symlink_inode_ops =
{
/*FIXME later getxattr, listxattr,
* other method need to be replaced too
* */
- readlink: clonefs_readlink, /* readlink */
- follow_link: clonefs_follow_link,/* follow_link */
+ readlink: clonefs_readlink, /* readlink */
+ follow_link: clonefs_follow_link, /* follow_link */
+ getxattr: clonefs_getxattr, /* get xattr */
+ listxattr: clonefs_listxattr, /* list xattr */
};
+int clonefs_mounted(struct snap_cache *cache, int index)
+{
+ struct snap_clone_info *clone_sb;
+ struct list_head *list, *end;
+
+ end = list = &cache->cache_clone_list;
+
+ list_for_each_entry(clone_sb, list, clone_list_entry) {
+ if (clone_sb->clone_index == index)
+ return 1;
+ }
+ return 0;
+}
+
static void d_unadd_iput(struct dentry *dentry)
{
+ spin_lock(&dcache_lock);
list_del(&dentry->d_alias);
INIT_LIST_HEAD(&dentry->d_alias);
list_del(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_hash);
+ spin_unlock(&dcache_lock);
+
iput(dentry->d_inode);
dentry->d_inode = NULL;
}
ino = 0xF0000000 | dir->i_ino;
snap = iget(dir->i_sb, ino);
- CDEBUG(D_INODE, ".snap inode ino %ld, mode %o\n", snap->i_ino, snap->i_mode);
+ CDEBUG(D_INODE, ".snap inode ino %ld, mode %o\n",
+ snap->i_ino, snap->i_mode);
d_add(dentry, snap);
RETURN(NULL);
}
}
rc = iops->lookup(dir, dentry);
- if ( rc || !dentry->d_inode) {
+ if (rc || !dentry->d_inode ||
+ is_bad_inode(dentry->d_inode) ||
+ IS_ERR(dentry->d_inode)) {
RETURN(NULL);
}
-
+
+ CDEBUG(D_INODE, "cache inode ino %lu, mode %o\n",
+ dentry->d_inode->i_ino, dentry->d_inode->i_mode);
/*
* If we are under dotsnap, we need save extra data into
* dentry->d_fsdata: For dir, we only need _this_ snapshot's index;
}
cache = snap_find_cache(dir->i_dev);
- if ( !cache ) {
+ if (!cache) {
RETURN(-EINVAL);
}
handle = snap_trans_start(cache, dir, SNAP_OP_CREATE);
- if ( snap_needs_cow(dir) != -1 ) {
+ if (snap_needs_cow(dir) != -1) {
CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 1);
if ((snap_do_cow(dir, get_parent_ino(dir), 0))) {
CERROR("Error in currentfs_mkdir, dentry->d_inode is NULL\n");
}
- snap_debug_device_fail(dir->i_dev, SNAP_OP_MKDIR, 3);
+ set_filter_ops(cache, dentry->d_inode);
+ init_filter_data(dentry->d_inode, 0);
+
+ CDEBUG(D_INODE, "inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op);
+ snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 3);
+
exit:
snap_trans_commit(cache, handle);
snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 2);
rc = iops->symlink(dir, dentry, symname);
- snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 3);
+ set_filter_ops(cache, dentry->d_inode);
+ init_filter_data(dentry->d_inode, 0);
+
+ snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 3);
exit:
snap_trans_commit(cache, handle);
RETURN(rc);
snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 2);
rc = iops->mknod(dir, dentry, mode, rdev);
+
+ set_filter_ops(cache, dentry->d_inode);
+ init_filter_data(dentry->d_inode, 0);
snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 3);
/* XXX do we need to set the correct snap_{*}_iops */
off_t i_size = 0;
ino_t ino = 0;
int keep_inode = 0;
-// struct dentry_operations *save_dop = NULL;
void *handle = NULL;
ENTRY;
if (snap_needs_cow(dentry->d_inode) != -1 ||
snap_is_redirector(dentry->d_inode)) {
snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 2);
- snap_do_cow (dir, get_parent_ino(dir), SNAP_CREATE_IND_DEL_PRI);
+ snap_do_cow (dentry->d_inode, get_parent_ino(dentry->d_inode),
+ SNAP_CREATE_IND_DEL_PRI);
keep_inode = 1;
}
-#if 0
- if ( keep_inode ) {
- printk("set up dentry ops, before %p\n",dentry->d_op);
- save_dop = dentry->d_op;
-
- filter_setup_dentry_ops(cache->cache_filter,
- dentry->d_op, ¤tfs_dentry_ops);
- dentry->d_op = filter_c2udops(cache->cache_filter);
-
- printk("set up dentry ops, after %p\n",dentry->d_op);
-
- }
-
-#endif
if( keep_inode && dentry->d_inode ) {
ino = dentry->d_inode->i_ino;
rc = iops->rmdir(dir, dentry);
snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 5);
- /* XXX : check this */
-#if 0
- if ( keep_inode ) {
- dentry->d_op = save_dop;
- printk("restore dentry ops, now at %p\n",dentry->d_op);
- }
-
-#endif
-
if( keep_inode && ino) {
- inode = iget ( dir->i_sb, ino);
+ inode = iget (dir->i_sb, ino);
if( inode) {
// inode->i_ctime = i_ctime;
inode->i_nlink = i_nlink;
inode->i_size = i_size;
mark_inode_dirty(inode);
iput( inode);
-#ifdef CONFIG_SNAPFS_EXT3
/*
* In Ext3, rmdir() will put this inode into
* orphan list, we must remove it out. It's ugly!!
*/
if( cache->cache_type == FILTER_FS_EXT3 )
ext3_orphan_del(handle, inode);
-#endif
snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 6);
}
}
rmdir: currentfs_rmdir,
unlink: currentfs_unlink,
rename: currentfs_rename,
- lookup: currentfs_lookup
+ lookup: currentfs_lookup,
+ removexattr: currentfs_removexattr,
+ setattr: currentfs_setattr,
+ setxattr: currentfs_setxattr,
};
char *kaddr_src, *kaddr_dst;
struct snap_cache *cache;
struct address_space_operations *c_aops;
- struct page *src_page, *dst_page;
+ struct page *src_page = NULL, *dst_page = NULL;
unsigned long index, offset, bytes;
int err = 0;
ENTRY;
flush_dcache_page(dst_page);
err = c_aops->commit_write(NULL, dst_page, offset, offset + bytes);
+ CDEBUG(D_SNAP, "copy back pages %p index %lu src %lu dst %lu \n",
+ dst_page, dst_page->index, src->i_ino, dst->i_ino);
if (err)
goto unlock_dst_page;
err = 1;
if ( !cache )
RETURN(-EINVAL);
+ down(&inode->i_sem);
+
if ( snap_needs_cow(inode) != -1 ) {
CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
snap_do_cow(inode, filp->f_dentry->d_parent->d_inode->i_ino, 0);
}
fops = filter_c2cffops(cache->cache_filter);
- if (!fops || !fops->write)
- RETURN(-EINVAL);
-
+ if (!fops || !fops->write) {
+ up(&inode->i_sem);
+ RETURN(-EINVAL);
+ }
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else {
pos = *ppos;
- if (pos != *ppos)
+ if (pos != *ppos){
+ up(&inode->i_sem);
RETURN(-EINVAL);
+ }
}
- if (pos & PAGE_CACHE_MASK) {
+
+ CDEBUG(D_SNAP, "write offset %lld count %u \n", pos, count);
+
+ if (pos & (PAGE_CACHE_SIZE - 1)) {
start[0] = pos & PAGE_CACHE_MASK;
end[0] = pos;
}
pos += count - 1;
- if ((pos+1) & PAGE_CACHE_MASK) {
+ if ((pos+1) & (PAGE_CACHE_SIZE - 1)) {
start[1] = pos;
end[1] = PAGE_CACHE_ALIGN(pos);
}
if (((start[0] >> PAGE_CACHE_SHIFT) == (start[1] >> PAGE_CACHE_SHIFT)) ||
pos > inode->i_size)
start[1] = -1;
-
+
+ CDEBUG(D_SNAP, "copy back start[0] %ld end[0] %ld start[1] %ld end[1] %ld \n",
+ start[0], end[0], start[1], end[1]);
for (i = 0; i < 2; i++) {
if (start[i] == -1)
continue;
if (result < 0) {
iput(cache_inode);
rc = result;
+ up(&inode->i_sem);
goto exit;
}
iput(cache_inode);
}
}
+
+ up(&inode->i_sem);
rc = fops->write(filp, buf, count, ppos);
exit:
RETURN(rc);
table = &snap_tables[cache->cache_snap_tableno];
for (slot = table->tbl_count - 1; slot >= 1; slot--) {
- cache_inode = NULL;
index = table->snap_items[slot].index;
cache_inode = snap_get_indirect(inode, NULL, index);
if (!search_older && c_aops->bmap(cache_inode->i_mapping, block))
break;
iput(cache_inode);
+ cache_inode = NULL;
}
if (pri_inode) iput(pri_inode);
- if (!cache_inode )
- RETURN(-EINVAL);
-
+ if (!cache_inode) {
+ CDEBUG(D_SNAP, "block %lu is a hole of inode %lu \n",
+ block, inode->i_ino);
+ memset(kmap(page), 0, PAGE_CACHE_SIZE);
+ flush_dcache_page(page);
+ GOTO(exit, rc = 0);
+ }
+ CDEBUG(D_INODE, "readpage ino %lu icount %d \n", cache_inode->i_ino,
+ atomic_read(&cache_inode->i_count));
down(&cache_inode->i_sem);
/*Here we have changed a file to read,
GOTO(exit_release, rc = -EIO);
memcpy(kmap(page), kmap(cache_page), PAGE_CACHE_SIZE);
+ flush_dcache_page(page);
kunmap(cache_page);
page_cache_release(cache_page);
up(&cache_inode->i_sem);
iput(cache_inode);
-
+exit:
kunmap(page);
SetPageUptodate(page);
UnlockPage(page);
};
struct inode_operations currentfs_file_iops = {
- revalidate: NULL,
+ setattr: currentfs_setattr,
+ setxattr: currentfs_setxattr,
+ removexattr: currentfs_removexattr,
};
u_iops->mknod = filter_iops->mknod;
if (cache_iops->permission && filter_iops->permission)
u_iops->permission = filter_iops->permission;
+ if (cache_iops->setattr && filter_iops->setattr)
+ u_iops->setattr = filter_iops->setattr;
+ if (cache_iops->setxattr && filter_iops->setxattr)
+ u_iops->setxattr = filter_iops->setxattr;
+ if (cache_iops->removexattr && filter_iops->removexattr)
+ u_iops->removexattr = filter_iops->removexattr;
+
}
/* copy dir fops */
if (filter_iops) {
if (filter_iops->revalidate)
u_iops->revalidate = filter_iops->revalidate;
+ if (filter_iops->removexattr)
+ u_iops->removexattr = filter_iops->removexattr;
+ if (filter_iops->setxattr)
+ u_iops->setxattr = filter_iops->setxattr;
+ if (filter_iops->setattr)
+ u_iops->setattr = filter_iops->setattr;
}
if (filter_fops) {
if (filter_fops->read)
u_iops->readlink = filter_iops->readlink;
if (cache_iops->follow_link && filter_iops->follow_link)
u_iops->follow_link = filter_iops->follow_link;
+ if (cache_iops->getxattr && filter_iops->getxattr)
+ u_iops->getxattr = filter_iops->getxattr;
+ if (cache_iops->listxattr && filter_iops->listxattr)
+ u_iops->listxattr = filter_iops->listxattr;
+
}
EXIT;
}
return;
}
snapops = filter_c2csnapops(cache->cache_filter);
+
+ if (inode->i_filterdata) return;
inode->i_filterdata = (struct filter_inode_info *) \
kmem_cache_alloc(filter_info_cache, SLAB_KERNEL);
inode->i_ino, inode->i_op);
}
}
+int currentfs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct snap_cache *cache;
+ struct inode *inode = dentry->d_inode;
+ struct inode_operations *iops;
+ int rc;
+
+ ENTRY;
+
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CERROR("currentfs_setxattr: cannot find cache\n");
+ RETURN(-EINVAL);
+ }
+
+ iops = filter_c2cfiops(cache->cache_filter);
+
+ if (!iops || !iops->setxattr) {
+ RETURN(-EINVAL);
+ }
+ if ( snap_needs_cow(inode) != -1 ) {
+ CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
+ }
+
+ rc = iops->setxattr(dentry, name, value, size, flags);
+
+ RETURN(rc);
+}
+int currentfs_removexattr(struct dentry *dentry, const char *name)
+{
+ struct snap_cache *cache;
+ struct inode *inode = dentry->d_inode;
+ struct inode_operations *iops;
+ int rc;
+
+ ENTRY;
+
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CERROR("currentfs_setxattr: cannot find cache\n");
+ RETURN(-EINVAL);
+ }
+
+ iops = filter_c2cfiops(cache->cache_filter);
+
+ if (!iops || !iops->removexattr) {
+ RETURN(-EINVAL);
+ }
+
+ if (snap_needs_cow(inode) != -1) {
+ CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
+ }
+ rc = iops->removexattr(dentry, name);
+
+ RETURN(rc);
+}
+
+int currentfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct snap_cache *cache;
+ struct inode *inode = dentry->d_inode;
+ struct inode_operations *iops;
+ int rc;
+
+ ENTRY;
+
+ cache = snap_find_cache(inode->i_dev);
+ if (!cache) {
+ CERROR("currentfs_setxattr: cannot find cache\n");
+ RETURN(-EINVAL);
+ }
+ iops = filter_c2cfiops(cache->cache_filter);
+
+ if (!iops || !iops->setattr) {
+ RETURN(-EINVAL);
+ }
+ if ( snap_needs_cow(inode) != -1 ) {
+ CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0);
+ }
+
+ rc = iops->setattr(dentry, attr);
+
+ RETURN(rc);
+}
/* Superblock operations. */
static void currentfs_read_inode(struct inode *inode)
{
if( !inode )
return;
-
CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino);
cache = snap_find_cache(inode->i_dev);
if(filter_c2csops(cache->cache_filter))
filter_c2csops(cache->cache_filter)->read_inode(inode);
+ CDEBUG(D_INODE, "read_inode ino %lu icount %d \n",
+ inode->i_ino, atomic_read(&inode->i_count));
set_filter_ops(cache, inode);
/*init filter_data struct
* FIXME flag should be set future*/
init_filter_data(inode, 0);
+ CDEBUG(D_INODE, "read_inode ino %lu icount %d \n",
+ inode->i_ino, atomic_read(&inode->i_count));
return;
}
put_super: currentfs_put_super,
clear_inode: currentfs_clear_inode,
};
+
+
+
+
+
unsigned int snap_index;/* which snapshot is ours */
unsigned int snap_table;/* which table do we use */
};
-#define DISK_SNAPTABLE_ATTR "Snaptable"
+#define DISK_SNAPTABLE_ATTR "Snaptable12"
#define DISK_SNAP_TABLE_MAGIC 0x1976
struct snap_disk_table {
unsigned int magic;
int init_filter_info_cache(void);
extern void init_filter_data(struct inode *inode, int flag);
extern void set_filter_ops(struct snap_cache *cache, struct inode *inode);
+extern int currentfs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+extern int currentfs_removexattr(struct dentry *dentry, const char *name);
+extern int currentfs_setattr(struct dentry *dentry, struct iattr *attr);
/* dir.c */
extern struct inode_operations currentfs_dir_iops;
extern struct file_operations currentfs_dir_fops;
extern int init_option(char *data);
extern void cleanup_option(void);
extern int get_opt(struct option **opt, char **pos);
+/* clonefs.c */
+int clonefs_mounted(struct snap_cache *cache, int index);
#define FILTER_DID_SUPER_OPS 0x1
#define FILTER_DID_INODE_OPS 0x2
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;
table->snap_items[count].time = CURRENT_TIME;
/* find table index */
index = get_index_of_item(table, data->snaps[0].name);
- if (index < 0)
+ if (index < 0) {
+ CERROR("snaptable full Or Duplicate name in snaptable\n");
GOTO(exit, rc = -EINVAL);
+ }
table->snap_items[count].index = index;
table->snap_items[count].flags = 0;
}
old_ind = redirect->i_ino;
iput(redirect);
+
+ /* 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;
} else {
snap_set_indirect(primary, old_ind, this_index, 0);
snap_set_indirect(primary, 0, index, 0);
+ up(&primary->i_sem);
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 --) {
+ for (slot = table->tbl_count - 1; slot > delete_slot; slot --) {
my_table[slot - delete_slot] = table->snap_items[slot].index;
}
- 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;
- }
+
+ this_index = table->tbl_count - delete_slot - 1;
+ next_ind = snap_get_indirect(primary, my_table, this_index);
- if (next_ind && (next_ind->i_ino == old_ind)) {
+ 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);
/* 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)
{
struct snap_disk_table *disk_snap_table;
struct snapshot_operations *snapops;
struct snap_cache *cache;
- int tableno = data->tableno, index, i, slot, rc, count;
+ int tableno = data->tableno;
+ int index, i, del_slot, rc;
if (!(cache = snap_find_cache((kdev_t)data->dev)))
RETURN(-ENODEV);
- snapops = filter_c2csnapops(cache->cache_filter);
- if (!snapops || !snapops->set_meta_attr)
- RETURN(-EINVAL);
-
if (tableno < 0 || tableno > SNAP_MAX_TABLES) {
CERROR("invalid table number %d\n", tableno);
RETURN(-EINVAL);
}
+
+ 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);
RETURN(-EINVAL);
/*delete item in snaptable */
table = &snap_tables[tableno];
- index = data->index;
- slot = snap_index2slot(table, index);
- if (slot < 0)
+ del_slot = snap_index2slot(table, index);
+ if (del_slot < 0)
RETURN(-EINVAL);
down_interruptible(&table->tbl_sema);
- while(slot < table->tbl_count) {
- struct snap *item = &table->snap_items[slot];
- item->time = table->snap_items[slot + 1].time;
- item->flags = table->snap_items[slot + 1].flags;
- item->gen = table->snap_items[slot + 1].gen;
- item->index = table->snap_items[slot + 1].index;
- memcpy(&item->name[0], &table->snap_items[slot + 1].name[0],
- SNAP_MAX_NAMELEN);
- }
-
- table->tbl_count --;
SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table));
- if (!disk_snap_table)
+ if (!disk_snap_table) {
+ up(&table->tbl_sema);
RETURN(-ENOMEM);
+ }
+
/* we will delete the item snap_table to disk */
-
+
+ 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 ++;
+ }
+
+ 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);
- disk_snap_table->generation = cpu_to_le32((__u32)table->generation);
+ 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));
- count = table->tbl_count;
-
- for (i = 1; i <= count; i++) {
- struct snap *item = &table->snap_items[i];
- disk_snap_table->snap_items[i].time = cpu_to_le64((__u64)item->time);
- disk_snap_table->snap_items[i].gen = cpu_to_le32((__u32)item->gen);
- disk_snap_table->snap_items[i].flags = cpu_to_le32((__u32)item->flags);
- disk_snap_table->snap_items[i].index = cpu_to_le32((__u32)item->index);
- memcpy(&disk_snap_table->snap_items[i].name , item->name, SNAP_MAX_NAMELEN);
+ 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);
}
+
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(0);
+ RETURN(rc);
}
int snapfs_read_snaptable(struct snap_cache *cache, int tableno)
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) {
}
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;
ENTRY;
- if(!pri) return 0;
+ if(!pri) RETURN(0);
data = (struct snap_iterdata*) param;
else {
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)
table = &snap_tables[tableno];
- for ( slot = 0 ; slot < SNAP_MAX ; slot++ ) {
+ for ( slot = 0 ; slot < table->tbl_count; slot++) {
if (!strcmp(&table->snap_items[slot].name[0], name)) {
return table->snap_items[slot].index;
}
table = &snap_tables[tableno];
index = snap_get_index_from_name(tableno, data->snaps[0].name);
- if (index < 0)
+ 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;
rc = -EINVAL;
break;
}
- RETURN(0);
+ RETURN(rc);
}
#define BUF_SIZE 1024
}
*/
memcpy(name, data->name, name_len);
- printk("dev %d , len %d, name_len %d, find name is [%s]\n", dev, input.ioc_inlen, 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;
}
return 0;
}
-
-int snap_dev_open(int argc, char **argv)
+static int open_snap_device(char *name)
{
struct snap_mnt *snaplist;
- char *dev_name;
- int rc;
-
- if (argc != 2) {
- fprintf(stderr, "The argument count is not right \n");
- return CMD_HELP;
- }
-
- dev_name = argv[1];
-
+ int rc;
get_snaplist();
list_for_each_entry(snaplist, &snap_list, snap_mnt_list) {
- if (!strcmp(&snaplist->device.name[0], dev_name)) {
+ if (!strcmp(&snaplist->device.name[0], name)) {
rc = open_device(&snaplist->device.name[0],
snaplist->device.dev);
release_snap_list();
}
}
release_snap_list();
- fprintf(stderr, "%s are not snapdevice\n", dev_name);
+ fprintf(stderr, "%s are not snapdevice\n", name);
return (-EINVAL);
}
+int snap_dev_open(int argc, char **argv)
+{
+ char *dev_name;
+ int rc;
+
+ if (argc != 2) {
+ fprintf(stderr, "The argument count is not right \n");
+ return CMD_HELP;
+ }
+
+ dev_name = argv[1];
+ rc = open_snap_device(dev_name);
+ if (rc)
+ fprintf(stderr, "%s are not snapdevice\n", dev_name);
+ return (rc);
+}
int snap_dev_list(int argc, char **argv)
{
struct snap_mnt *snaplist;
}
int snap_snap_list(int argc, char **argv)
{
+ char *dev_name = NULL;
int i, rc = 0;
if (argc != 1 && argc != 2) {
return CMD_HELP;
}
if (open_device_table.count == 0) {
- fprintf(stderr, "Please open a snapdevice first\n");
- return (-EINVAL);
+ if (argc == 2) {
+ dev_name = argv[1];
+ }
+ if (dev_name) {
+ rc = open_snap_device(dev_name);
+ }
+ if (!dev_name || rc) {
+ fprintf(stderr, "Please open a snapdevice first\n");
+ return (-EINVAL);
+ }
}
-
for (i = 0; i < open_device_table.count; i++) {
struct ioc_snap_tbl_data *snap_ioc_data;
}
int snap_snap_del(int argc, char **argv)
{
+ char *dev_name = NULL, *snap_name = NULL;
int rc = 0, i;
if (argc != 3 && argc !=2) {
fprintf(stderr, "The argument count is not right \n");
return CMD_HELP;
}
-
if (open_device_table.count == 0) {
- fprintf(stderr, "Please open a snapdevice first\n");
- return (-EINVAL);
+ if (argc == 3) {
+ dev_name = argv[1];
+ } else if (argc == 4) {
+ dev_name = argv[2];
+ }
+ if (dev_name) {
+ rc = open_snap_device(dev_name);
+ }
+ if (!dev_name || rc) {
+ fprintf(stderr, "Please open a snapdevice first\n");
+ return (-EINVAL);
+ }
}
for (i = 0; i < open_device_table.count; i++) {
struct ioc_snap_tbl_data *snap_ioc_data;
if (argc == 3) {
snap_ioc_data->no = atoi(argv[1]);
- memcpy(snap_ioc_data->snaps[0].name,
- argv[2], strlen(argv[2]));
+ if (!snap_name)
+ snap_name = argv[2];
} else {
snap_ioc_data->no = 0;
- memcpy(snap_ioc_data->snaps[0].name,
- argv[1], strlen(argv[1]));
+ if (!snap_name)
+ snap_name = argv[1];
}
+ memcpy(snap_ioc_data->snaps[0].name,
+ snap_name, strlen(snap_name));
+
snap_ioc_data->snaps[0].time = time(NULL);
IOC_PACK(sizeof(struct ioc_snap_tbl_data) + sizeof(struct snap));
if ((rc = ioctl(open_device_table.device[i].fd,
IOC_SNAP_DELETE, buf))) {
- fprintf(stderr, "del %s failed \n", argv[1]);
+ fprintf(stderr, "del %s failed \n", snap_name);
} else {
- fprintf(stderr, "del %s success\n", argv[1]);
+ fprintf(stderr, "del %s success\n", snap_name);
}
}
return rc;
}
int snap_snap_add(int argc, char **argv)
{
+ char *dev_name = NULL, *snap_name = NULL;
int rc = 0, i;
- if (argc != 3 && argc !=2) {
+ if (argc != 3 && argc !=2 && argc !=4) {
fprintf(stderr, "The argument count is not right \n");
return CMD_HELP;
}
-
if (open_device_table.count == 0) {
- fprintf(stderr, "Please open a snapdevice first\n");
- return (-EINVAL);
+ if (argc == 3) {
+ dev_name = argv[1];
+ snap_name = argv[2];
+ } else if (argc == 4) {
+ dev_name = argv[2];
+ snap_name = argv[3];
+ }
+ if (dev_name) {
+ rc = open_snap_device(dev_name);
+ }
+ if (!dev_name || rc) {
+ fprintf(stderr, "Please open a snapdevice first\n");
+ return (-EINVAL);
+ }
}
for (i = 0; i < open_device_table.count; i++) {
struct ioc_snap_tbl_data *snap_ioc_data;
if (argc == 3) {
snap_ioc_data->no = atoi(argv[1]);
- memcpy(snap_ioc_data->snaps[0].name,
- argv[2], strlen(argv[2]));
+ if (!snap_name)
+ snap_name = argv[2];
} else {
snap_ioc_data->no = 0;
- memcpy(snap_ioc_data->snaps[0].name,
- argv[1], strlen(argv[1]));
+ if (!snap_name)
+ snap_name = argv[1];
}
+ memcpy(snap_ioc_data->snaps[0].name,
+ snap_name, strlen(snap_name));
snap_ioc_data->snaps[0].time = time(NULL);
IOC_PACK(sizeof(struct ioc_snap_tbl_data) + sizeof(struct snap));
if ((rc = ioctl(open_device_table.device[i].fd,
IOC_SNAP_ADD, buf))) {
- fprintf(stderr, "add %s failed \n", argv[1]);
+ fprintf(stderr, "add %s failed \n", snap_name);
} else {
- fprintf(stderr, "add %s success\n", argv[1]);
+ fprintf(stderr, "add %s success\n", snap_name);
}
}
return rc;