Index: linux-2.4.20-8/fs/ext3/snap.c
===================================================================
--- linux-2.4.20-8.orig/fs/ext3/snap.c 2003-01-30 18:24:37.000000000 +0800
-+++ linux-2.4.20-8/fs/ext3/snap.c 2004-01-19 23:24:39.000000000 +0800
-@@ -0,0 +1,2583 @@
++++ linux-2.4.20-8/fs/ext3/snap.c 2004-01-27 00:07:10.000000000 +0800
+@@ -0,0 +1,2577 @@
+/* fs/ext3/snap.c
+ *
+ * Copyright (c) 2002 Cluster File Systems, Inc. <info@clusterfs.com>
+#define EXT3_MAX_SNAP_DATA (sizeof(struct snap_ea))
+#define EXT3_SNAP_INDEX EXT3_XATTR_INDEX_LUSTRE
+
++#define EXT3_SNAP_DEBUG
+#ifdef EXT3_SNAP_DEBUG
+ #define snap_debug(f, a...) \
+ do { \
+/*SET FLAGS*/
+extern int ext3_bmap(struct address_space *mapping, long block);
+extern int ext3_load_inode_bitmap (struct super_block * sb, unsigned int block_group);
++extern int ext3_block_truncate_page(handle_t *handle, struct address_space *mapping,
++ loff_t from);
+/* helper functions to manipulate field 'parent' in snap_ea */
-+//static inline int
-+static int
++static inline int
+set_parent_ino(struct snap_ea *pea, int size, int index, ino_t val)
+{
+ char * p = (char*) pea;
+
+ return 0;
+}
-+static inline ino_t
-+get_parent_ino(struct snap_ea *pea, int size, int index)
-+{
-+ char * p = (char*)pea;
-+ int offset;
-+
-+ offset = sizeof(ino_t)*2 + (size - sizeof(ino_t)*2)/2;
-+ offset += sizeof(ino_t) * index;
-+ return *(ino_t*)(p+offset);
-+}
-+static inline void snap_double_lock(struct inode *i1, struct inode *i2)
-+{
-+ double_down(&i1->i_sem, &i2->i_sem);
-+}
-+
-+static inline void snap_double_unlock(struct inode *i1, struct inode *i2)
-+{
-+ double_up(&i1->i_sem, &i2->i_sem);
-+}
-+
+/* ext3_iterate_cowed_inode:
+ * iterate all the cowed inode with the same index and
+ * run the associate function @repeat
+ if (inode->i_ino == le32_to_cpu(SB_FIRST_COWED_INO(inode->i_sb))) {
+ SB_FIRST_COWED_INO(inode->i_sb) = cpu_to_le32(next_ino);
+ EXT3_I(inode)->i_flags &= ~EXT3_SNAP_PRI_FLAG;
-+
++ if (next_ino == 0)
++ SB_LAST_COWED_INO(inode->i_sb) = 0;
+ } else {
+ if (!prev_ino)
+ goto err_exit;
+ * Is it right in snapfs EXT3, check it later?
+ */
+ inlist = 0;
-+ // ea_size = SNAP_EA_SIZE_FROM_INDEX(index);
+ } else if (err < 0 || err > EXT3_MAX_SNAP_DATA) {
+ goto out_unlock;
+ }
+{
+ return (EXT3_I(inode)->i_file_acl != 0);
+}
++/* XXX This function has a very bad effect to
++ * the performance of filesystem,
++ * will find another way to fix it
++ */
++static void fs_flushinval_pages(handle_t *handle, struct inode* inode)
++{
++ if (inode->i_blocks > 0 && inode->i_mapping) {
++ fsync_inode_data_buffers(inode);
++ // ext3_block_truncate_page(handle, inode->i_mapping, inode->i_size);
++ truncate_inode_pages(inode->i_mapping, 0);
++ }
++}
+
-+/* ext3_migrate_data:
++/* ext3_migrate_data2:
+ * MOVE all the data blocks from inode src to inode dst as well as
+ * COPY all attributes(meta data) from inode src to inode dst.
+ * For extended attributes(EA), we COPY all the EAs but skip the Snap EA from src to dst.
+ if (dst->i_ino == src->i_ino)
+ return 0;
+
++ fs_flushinval_pages(handle, src);
++
+ ext3_copy_meta(handle, dst, src);
+
+ snap_debug("migrating data blocks from %lu to %lu\n", src->i_ino, dst->i_ino);
+ ext3_mark_inode_dirty(handle, src);
+ ext3_mark_inode_dirty(handle, dst);
+
-+ truncate_inode_pages(src->i_mapping, 0);
+
+ return SNAP_ERROR(err);
+}
+ ext3_journal_stop(handle, pri);
+}
+
-+
-+
-+
+static handle_t * ext3_copy_data(handle_t *handle, struct inode *dst,
+ struct inode *src, int *has_orphan)
+{
+ snap_debug("create_indirect:fail to extend "
+ "journal, restart trans\n");
+ loopfail( 3 );
-+ if( !*has_orphan ){
++ if(!*has_orphan) {
++ snap_debug("add orphan ino %lu nlink %d to orphan list \n",
++ dst->i_ino, dst->i_nlink);
+#ifdef EXT3_ENABLE_SNAP_ORPHAN
+ add_snap_orphan(handle, dst, src);
+#else
+ * or ext3_rmdir will report errors "bad dir, no data blocks"
+ */
+ if( S_ISDIR(pri->i_mode)) {
-+ handle = ext3_copy_data( handle, pri, ind, &has_orphan );
-+ if( !handle )
++ handle = ext3_copy_data(handle, pri, ind, &has_orphan);
++ if(!handle) {
++ err = -EINVAL;
+ goto exit_unlock;
++ }
+ }
+
+ pri->u.ext3_i.i_flags |= EXT3_DEL_FL;
+ * it has been cowed and has ea )
+ */
+ if( S_ISLNK(ind->i_mode) &&
-+ (( ind->i_blocks == 0) || (ext3_has_ea(ind) && ind->i_blocks == bpib )) ){
-+ snap_debug("ino %lu is fast symlink\n",
-+ pri->i_ino);
-+ memcpy(EXT3_I(pri)->i_data,
-+ EXT3_I(ind)->i_data,
-+ sizeof(EXT3_I(ind)->i_data));
++ ((ind->i_blocks == 0) || (ext3_has_ea(ind) && ind->i_blocks == bpib))) {
++ snap_debug("ino %lu is fast symlink\n", pri->i_ino);
++ memcpy(EXT3_I(pri)->i_data, EXT3_I(ind)->i_data,
++ sizeof(EXT3_I(ind)->i_data));
+ pri->i_size = ind->i_size;
+ }
+ else {
+ handle = ext3_copy_data(handle, pri, ind, &has_orphan);
-+ if( !handle )
++ if (!handle)
+ goto exit_unlock;
+ }
+ }
+ pri->i_sb->s_dirt = 1;
+ unlock_super(pri->i_sb);
+ }
-+ if(has_orphan) {
++ if (has_orphan) {
++ snap_debug("del %lu nlink %d from orphan list\n",
++ ind->i_ino, ind->i_nlink);
+#ifdef EXT3_ENABLE_SNAP_ORPHAN
+ remove_snap_orphan(handle, ind);
+#else
+ up(&ind->i_sem);
+ ind->i_nlink = 0;
+exit:
++ if (has_orphan) {
++ snap_debug("del %lu nlink %d from orphan list\n",
++ ind->i_ino, ind->i_nlink);
++#ifdef EXT3_ENABLE_SNAP_ORPHAN
++ remove_snap_orphan(handle, ind);
++#else
++ ext3_orphan_del(handle, ind);
++#endif
++ }
+ iput(ind);
+ ext3_journal_stop(handle, pri);
-+ snap_debug("exiting with error %d\n", err);
++ if (err)
++ snap_err("exiting with error %d\n", err);
+ return NULL;
+}
+
+ }
+ /* if it's block level cow, first copy the blocks back */
+ if (EXT3_HAS_COMPAT_FEATURE(pri->i_sb, EXT3_FEATURE_COMPAT_BLOCKCOW) &&
-+ S_ISREG(pri->i_mode)) {
++ S_ISREG(pri->i_mode)) {
+
+ int blocks;
-+ if( !next_ind ) next_ind = pri;
++ if (!next_ind) {
++ next_ind = pri;
++ down(&ind->i_sem);
++ } else {
++ double_down(&next_ind->i_sem, &ind->i_sem);
++ }
+ blocks = (next_ind->i_size + next_ind->i_sb->s_blocksize-1)
+ >> next_ind->i_sb->s_blocksize_bits;
-+
+#define FAST_MIGRATE_BLOCK
+#ifdef FAST_MIGRATE_BLOCK
+ snap_debug("migrate block back from ino %lu to %lu\n",
+ ind->i_ino, next_ind->i_ino);
+
-+ snap_double_lock(next_ind, ind);
+ for(i = 0; i < blocks; i++) {
+ if( ext3_bmap(next_ind->i_mapping, i) )
+ continue;
+ next_ind->i_blocks = calculate_i_blocks( next_ind, blocks);
+ ext3_mark_inode_dirty(handle, next_ind);
+
-+ snap_double_unlock(next_ind, ind);
-+
-+#if 0
-+ snap_double_lock(pri, ind);
-+
-+ for(i = 0; i < blocks; i++) {
-+ if( ext3_bmap(pri, i) ) continue;
-+ if( !ext3_bmap(ind, i) ) continue;
-+ ext3_migrate_block( pri, ind, i) ;
-+ }
-+ /* Now re-compute the i_blocks */
-+ /* XXX shall we take care of ind here? probably not */
-+ pri->i_blocks = calculate_i_blocks( pri, blocks);
-+ mark_inode_dirty(pri);
-+
-+ double_unlock(pri, ind);
-+#endif
+#else
-+ snap_double_lock(next_ind, ind);
+ for (i = 0; i < blocks; i++) {
+ if (ext3_bmap(next_ind->i_mapping, i))
+ continue;
+ break;
+ }
+ ext3_mark_inode_dirty(handle, next_ind);
-+ double_unlock(next_ind, ind);
+#endif
-+ }
++ if (next_ind == pri)
++ up(&ind->i_sem);
++ else
++ double_up(&next_ind->i_sem, &ind->i_sem);
+
++ }
++
+ snap_debug("delete indirect ino %lu\n", ind->i_ino);
+ snap_debug("iput ind %lu, ref count = %d\n",
+ ind->i_ino, atomic_read(&ind->i_count));
+ /* XXX: check this, ext3_new_inode, the first arg should be "dir" */
+ tmp = ext3_new_inode(handle, pri, (int)pri->i_mode, 0);
+ if(tmp) {
-+ snap_double_lock(pri, tmp);
++ double_down(&pri->i_sem, &tmp->i_sem);
+ ext3_migrate_data(handle, tmp, pri);
-+ snap_double_unlock(pri, tmp);
++ double_up(&pri->i_sem, &tmp->i_sem);
+
+ tmp->i_nlink = 0;
+ iput(tmp);
+ }
+ else
+ snap_err("restore_indirect, new_inode err\n");
-+
-+ snap_double_lock(pri, ind);
++
++ double_down(&pri->i_sem, &ind->i_sem);
+ ext3_migrate_data(handle, pri, ind);
+ /* clear the cow flag for pri because ind has it */
+ pri->u.ext3_i.i_flags &= ~EXT3_COW_FL;
+ ext3_mark_inode_dirty(handle, pri);
-+ snap_double_unlock(pri, ind);
-+
++ double_up(&pri->i_sem, &ind->i_sem);
+ iput(ind);
+
+// ext3_destroy_indirect(pri, index);
+
Index: linux-2.4.20-8/fs/ext3/Makefile
===================================================================
---- linux-2.4.20-8.orig/fs/ext3/Makefile 2004-01-05 10:54:03.000000000 +0800
-+++ linux-2.4.20-8/fs/ext3/Makefile 2004-01-13 00:10:14.000000000 +0800
+--- linux-2.4.20-8.orig/fs/ext3/Makefile 2004-01-19 22:06:25.000000000 +0800
++++ linux-2.4.20-8/fs/ext3/Makefile 2004-01-19 22:06:25.000000000 +0800
@@ -13,7 +13,7 @@
obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
export-objs += xattr.o
Index: linux-2.4.20-8/fs/ext3/inode.c
===================================================================
---- linux-2.4.20-8.orig/fs/ext3/inode.c 2004-01-05 10:54:03.000000000 +0800
-+++ linux-2.4.20-8/fs/ext3/inode.c 2004-01-18 01:48:19.000000000 +0800
+--- linux-2.4.20-8.orig/fs/ext3/inode.c 2004-01-19 22:06:24.000000000 +0800
++++ linux-2.4.20-8/fs/ext3/inode.c 2004-01-26 01:12:48.000000000 +0800
@@ -1191,7 +1191,7 @@
* So, if we see any bmap calls here on a modified, data-journaled file,
* take extra steps to flush any blocks which might be in the cache.
{
struct inode *inode = mapping->host;
journal_t *journal;
+@@ -1403,7 +1403,7 @@
+ * This required during truncate. We need to physically zero the tail end
+ * of that block so it doesn't yield old data if the file is later grown.
+ */
+-static int ext3_block_truncate_page(handle_t *handle,
++int ext3_block_truncate_page(handle_t *handle,
+ struct address_space *mapping, loff_t from)
+ {
+ unsigned long index = from >> PAGE_CACHE_SHIFT;
Index: linux-2.4.20-8/fs/ext3/ialloc.c
===================================================================
---- linux-2.4.20-8.orig/fs/ext3/ialloc.c 2004-01-05 10:54:03.000000000 +0800
-+++ linux-2.4.20-8/fs/ext3/ialloc.c 2004-01-16 20:48:29.000000000 +0800
+--- linux-2.4.20-8.orig/fs/ext3/ialloc.c 2004-01-19 22:06:24.000000000 +0800
++++ linux-2.4.20-8/fs/ext3/ialloc.c 2004-01-19 22:06:25.000000000 +0800
@@ -160,6 +160,13 @@
return retval;
}
* that have access to it, and as such there are no
Index: linux-2.4.20-8/fs/ext3/super.c
===================================================================
---- linux-2.4.20-8.orig/fs/ext3/super.c 2004-01-05 10:54:03.000000000 +0800
-+++ linux-2.4.20-8/fs/ext3/super.c 2004-01-18 01:40:10.000000000 +0800
+--- linux-2.4.20-8.orig/fs/ext3/super.c 2004-01-19 22:06:24.000000000 +0800
++++ linux-2.4.20-8/fs/ext3/super.c 2004-01-19 22:06:25.000000000 +0800
@@ -1324,6 +1324,13 @@
sbi->s_mount_state = le16_to_cpu(es->s_state);
sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
for (i=0; i < 4; i++)
sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
sbi->s_def_hash_version = es->s_def_hash_version;
+Index: linux-2.4.20-8/fs/ext3/ext3-exports.c
+===================================================================
+--- linux-2.4.20-8.orig/fs/ext3/ext3-exports.c 2004-01-19 22:06:19.000000000 +0800
++++ linux-2.4.20-8/fs/ext3/ext3-exports.c 2004-01-26 01:13:53.000000000 +0800
+@@ -21,6 +21,9 @@
+ EXPORT_SYMBOL(ext3_xattr_set);
+ EXPORT_SYMBOL(ext3_prep_san_write);
+ EXPORT_SYMBOL(ext3_map_inode_page);
++EXPORT_SYMBOL(ext3_orphan_add);
++EXPORT_SYMBOL(ext3_orphan_del);
++EXPORT_SYMBOL(ext3_block_truncate_page)
+
+ EXPORT_SYMBOL(ext3_abort);
+ EXPORT_SYMBOL(ext3_decode_error);
Index: linux-2.4.20-8/include/linux/snap.h
===================================================================
--- linux-2.4.20-8.orig/include/linux/snap.h 2003-01-30 18:24:37.000000000 +0800
-+++ linux-2.4.20-8/include/linux/snap.h 2004-01-13 00:10:14.000000000 +0800
++++ linux-2.4.20-8/include/linux/snap.h 2004-01-19 22:11:26.000000000 +0800
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2002 Cluster File Systems, Inc. <info@clusterfs.com>
+#endif
Index: linux-2.4.20-8/include/linux/ext3_fs.h
===================================================================
---- linux-2.4.20-8.orig/include/linux/ext3_fs.h 2004-01-05 10:54:03.000000000 +0800
-+++ linux-2.4.20-8/include/linux/ext3_fs.h 2004-01-16 20:45:09.000000000 +0800
+--- linux-2.4.20-8.orig/include/linux/ext3_fs.h 2004-01-19 22:06:24.000000000 +0800
++++ linux-2.4.20-8/include/linux/ext3_fs.h 2004-01-19 22:11:15.000000000 +0800
@@ -183,7 +183,13 @@
#define EXT3_INDEX_FL 0x00001000 /* hash-indexed directory */
#define EXT3_IMAGIC_FL 0x00002000 /* AFS directory */
EXT3_FEATURE_INCOMPAT_RECOVER)
Index: linux-2.4.20-8/include/linux/ext3_fs_sb.h
===================================================================
---- linux-2.4.20-8.orig/include/linux/ext3_fs_sb.h 2004-01-05 10:54:00.000000000 +0800
-+++ linux-2.4.20-8/include/linux/ext3_fs_sb.h 2004-01-13 00:10:14.000000000 +0800
+--- linux-2.4.20-8.orig/include/linux/ext3_fs_sb.h 2004-01-19 22:06:18.000000000 +0800
++++ linux-2.4.20-8/include/linux/ext3_fs_sb.h 2004-01-19 22:10:06.000000000 +0800
@@ -86,6 +86,13 @@
wait_queue_head_t s_delete_thread_queue;
wait_queue_head_t s_delete_waiter_queue;
#endif /* _LINUX_EXT3_FS_SB */
Index: linux-2.4.20-8/include/linux/ext3_jbd.h
===================================================================
---- linux-2.4.20-8.orig/include/linux/ext3_jbd.h 2004-01-05 10:53:59.000000000 +0800
-+++ linux-2.4.20-8/include/linux/ext3_jbd.h 2004-01-13 00:10:14.000000000 +0800
+--- linux-2.4.20-8.orig/include/linux/ext3_jbd.h 2004-01-19 22:06:15.000000000 +0800
++++ linux-2.4.20-8/include/linux/ext3_jbd.h 2004-01-19 22:11:15.000000000 +0800
@@ -71,6 +71,33 @@
#define EXT3_INDEX_EXTRA_TRANS_BLOCKS 8
%diffstat
fs/ext3/Makefile | 2
+ fs/ext3/ext3-exports.c | 3
fs/ext3/ialloc.c | 7
- fs/ext3/inode.c | 2
- fs/ext3/snap.c | 2583 +++++++++++++++++++++++++++++++++++++++++++++
+ fs/ext3/inode.c | 4
+ fs/ext3/snap.c | 2577 +++++++++++++++++++++++++++++++++++++++++++++
fs/ext3/super.c | 7
include/linux/ext3_fs.h | 38
include/linux/ext3_fs_sb.h | 7
include/linux/ext3_jbd.h | 27
include/linux/snap.h | 266 ++++
- 9 files changed, 2934 insertions(+), 5 deletions(-)
+ 10 files changed, 2932 insertions(+), 6 deletions(-)
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,
};
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,
};
+
+
+
+
+