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-13 00:11:40.000000000 +0800
-@@ -0,0 +1,2645 @@
++++ linux-2.4.20-8/fs/ext3/snap.c 2004-01-18 01:48:54.000000000 +0800
+@@ -0,0 +1,2588 @@
+/* fs/ext3/snap.c
+ *
+ * Copyright (c) 2002 Cluster File Systems, Inc. <info@clusterfs.com>
+#define EXT3_SNAP_INDEX EXT3_XATTR_INDEX_LUSTRE
+
+#ifdef EXT3_SNAP_DEBUG
-+ static long snap_kmem = 0;
+ #define snap_debug(f, a...) \
+ do { \
+ printk (KERN_INFO "SNAP DEBUG: (%s, %d): %s: ", \
+
+ /* we update the new cowed ino list end in memory */
+ SB_LAST_COWED_INO(pri->i_sb) = cpu_to_le32(pri->i_ino);
-+ snap_debug("cowed_inode_list_end %lu, append ino=%d\n",
-+ last_inode->i_ino, le32_to_cpu(snaps->ino[index]));
++ snap_debug("cowed_inode_list_end %lu, append ino=%lu\n",
++ last_inode->i_ino, pri->i_ino);
+exit:
+ if (last_inode)
+ iput(last_inode);
+
+ ext3_copy_meta(handle, dst, src);
+
-+ snap_debug("migrating %ld data blocks from %lu to %lu\n",
-+ blocks, src->i_ino, dst->i_ino);
++ snap_debug("migrating data blocks from %lu to %lu\n", src->i_ino, dst->i_ino);
+ /* Can't check blocks in case of EAs */
+ memcpy(EXT3_I(dst)->i_data, EXT3_I(src)->i_data,
+ sizeof(EXT3_I(src)->i_data));
+ ext3_mark_inode_dirty(handle, src);
+ ext3_mark_inode_dirty(handle, dst);
+
++ truncate_inode_pages(src->i_mapping, 0);
++
+ return SNAP_ERROR(err);
+}
+
+
+static int ext3_copy_block (struct inode *dst, struct inode *src, int blk)
+{
-+ struct buffer_head *bh_dst, *bh_src;
++ struct buffer_head *bh_dst = NULL, *bh_src = NULL;
+ int err = 0;
-+ int journal_data;
+ handle_t *handle = NULL;
+
-+ if (!ext3_bmap(src->i_mapping, blk))
-+ return 0;
-+
++
++ snap_debug("copy blk %d from %lu to %lu \n", blk, src->i_ino, dst->i_ino);
+ /*
+ * ext3_getblk() require handle!=NULL
+ */
-+ journal_data = !S_ISREG(src->i_mode);
++ if (S_ISREG(src->i_mode))
++ return 0;
+
+ handle = ext3_journal_start(dst, SNAP_COPYBLOCK_TRANS_BLOCKS);
+ if( !handle )
+ bh_src = ext3_bread(handle, src, blk, 0, &err);
+ if (!bh_src) {
+ snap_err("error for src blk %d, error %d\n", blk, err);
-+ err = -1;
-+ goto exit_stop;
++ goto exit_relese;
+ }
+ bh_dst = ext3_getblk(handle, dst, blk, 1, &err);
+ if (!bh_dst) {
+ snap_err("error for dst blk %d, error %d\n", blk, err);
-+ err = -1;
-+ goto exit_rels_src;
++ err = -ENOSPC;
++ goto exit_relese;
+ }
+ snap_debug("copy block %lu to %lu (%ld bytes)\n",
-+ bh_src->b_blocknr, bh_dst->b_blocknr,
-+ src->i_sb->s_blocksize);
++ bh_src->b_blocknr, bh_dst->b_blocknr,
++ src->i_sb->s_blocksize);
+
-+ if(journal_data){
-+ ext3_journal_get_write_access(handle, bh_dst);
-+ }
++ ext3_journal_get_write_access(handle, bh_dst);
+
+ memcpy(bh_dst->b_data, bh_src->b_data, src->i_sb->s_blocksize);
+
-+ if(journal_data){
-+ ext3_journal_dirty_metadata(handle, bh_dst);
-+ }else{
-+ mark_buffer_dirty(bh_dst);
-+ if (IS_SYNC(src)) {
-+ ll_rw_block (WRITE, 1, &bh_dst);
-+ wait_on_buffer (bh_dst);
-+ }
-+ }
-+ brelse(bh_dst);
-+exit_rels_src:
-+ brelse(bh_src);
-+exit_stop:
-+ ext3_journal_stop(handle, dst);
++ ext3_journal_dirty_metadata(handle, bh_dst);
++ err = 1;
++exit_relese:
++ if (bh_src) brelse(bh_src);
++ if (bh_dst) brelse(bh_dst);
++ if (handle)
++ ext3_journal_stop(handle, dst);
+ return err;
+}
+
+{
+ struct inode *ind;
+ handle_t *handle = NULL;
-+ int err;
++ int err = 0;
+ int has_orphan = 0;
+
+ if( pri == pri->i_sb->u.ext3_sb.s_journal_inode ){
+ }
+
+ if (ind && !IS_ERR(ind)) {
-+ snap_err("existing indirect ino %lu for %lu: index %d\n",
-+ ind->i_ino, pri->i_ino, index);
++ snap_debug("existing indirect ino %lu for %lu: index %d\n",
++ ind->i_ino, pri->i_ino, index);
+ err = 0;
+ goto exit;
+ }
+ pri->i_ino, (ulong)le32_to_cpu(snaps->ino[index]), index);
+
+ ind = iget(pri->i_sb, le32_to_cpu (snaps->ino[index]) );
-+ snap_debug("iget ind %lu, ref count = %d\n", ind->i_ino, ind->i_count);
++ snap_debug("iget ind %lu, ref count = %d\n",
++ ind->i_ino, atomic_read(&ind->i_count));
+
+ if ( !ind || IS_ERR(ind) || is_bad_inode(ind) ) {
+ err = -EINVAL;
+ }
+
+ snap_debug("delete indirect ino %lu\n", ind->i_ino);
-+ snap_debug("iput ind %lu, ref count = %d\n", ind->i_ino, ind->i_count);
++ snap_debug("iput ind %lu, ref count = %d\n",
++ ind->i_ino, atomic_read(&ind->i_count));
+ ind->i_nlink = 0;
+ iput (ind);
+
+ }
+}
+
-+#if 1
+static int find_snap_meta_index(
+ struct table_snap_meta_data *snap_meta,
+ char *name)
+ for( i = 0; i < TABLE_ITEM_COUNT; i++){
+ /*compare name Max name Length 15*/
+ if (snap_meta->array[i].name[0]){
-+ if(strcmp(snap_meta->array[i].name, name))
-+ continue;
-+ return i;
++ if(!strncmp(snap_meta->array[i].name, name, strlen(name)))
++ return i;
+ }
+ }
+ return -1; /* can not find */
+ struct inode *inode;
+ struct buffer_head *bh = NULL;
+ struct table_snap_meta_data *s_attr;
-+ unsigned long map_len = 0, index = 0, left_size;
-+ int i, error = 0;
++ unsigned long map_len = 0, left_size;
++ int i, error = 0, index = 0;
+
+ ino = SB_SNAPTABLE_INO(sb);
+ if (ino == 0){
+ s_attr = (struct table_snap_meta_data *)(bh->b_data);
+ index = find_snap_meta_index(s_attr, name);
+ if (index < 0) {
-+ snap_debug("not exit %s meta attr of table ino %llu \n",
-+ name, ip->i_ino);
++ snap_debug("not exit %s meta attr of table ino %lu \n",
++ name, inode->i_ino);
+ error = 0;
+ goto out_iput;
+ }
+ s_attr = (struct table_snap_meta_data *)(bh->b_data);
+ index = find_snap_meta_index(s_attr, name);
+ if (index < 0 && !buf) {
-+ snap_debug("%s meta attr of table ino %llu do not exist\n",
++ snap_debug("%s meta attr of table ino %lu do not exist\n",
+ name, inode->i_ino);
+ error = 0;
++ brelse(bh);
+ goto exit;
+ }
+ if (!buf) {
-+ snap_debug("delete the meta attr %s in the table ino %s",
-+ *name, inode->ino);
++ snap_debug("delete the meta attr %s in the table ino %lu",
++ name, inode->i_ino);
+ /*Here we only delete the entry of the attr
+ *FIXME, should we also delete the block of
+ * this attr
+ s_attr->array[index].len = 0;
+ s_attr->count --;
+ ext3_journal_dirty_metadata(handle, bh);
++ brelse(bh);
+ goto exit;
+ }
+ new_len = (size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ if (index < 0){
+ snap_err("table full of ino %lu \n", inode->i_ino);
+ error = index;
-+ goto exit;
++ brelse(bh);
++ goto exit;
+ }
+ }
+ s_attr->array[index].len = size;
+ journal_dirty_metadata(handle, bh);
++ brelse(bh);
+ /*put this attr to the snap table*/
+ left_size = size;
+ for(i = 0; i < new_len; i++) {
+ s_attr->array[index].start + i, 1, &error);
+ if (!array_bh) {
+ snap_err("inode %lu Can not get the block of attr %s\n",
-+ inode->i_ino, name);
++ inode->i_ino, name);
+ error = -ENOSPC;
++ brelse(array_bh);
+ goto exit;
+ }
+ ext3_journal_get_write_access(handle, array_bh);
+ left_size -= inode->i_sb->s_blocksize;
+ brelse(array_bh);
+ }
-+ ext3_journal_stop(handle, sb->s_root->d_inode);
+exit:
-+ brelse(bh);
++ if (handle)
++ ext3_journal_stop(handle, sb->s_root->d_inode);
+ iput(inode);
+ return error;
+}
-+#else
-+static int ext3_get_meta_attr(struct super_block *sb,
-+ char* name, char* buf,
-+ int *size)
-+{
-+ struct inode *root_inode = sb->s_root->d_inode;
-+ int err = 0;
-+
-+ if (!root_inode)
-+ return -EINVAL;
-+
-+ if (buf)
-+ err = ext3_xattr_get(root_inode, EXT3_SNAP_INDEX, name,
-+ buf, *size);
-+ if (err == -ERANGE || !buf){
-+ /*get the size of the buf*/
-+ *size = ext3_xattr_get(root_inode, EXT3_SNAP_INDEX, name,
-+ NULL, *size);
-+ }
-+
-+ return err;
-+}
-+/*
-+ * set the meta info of the snap system
-+ * argument:
-+ * buf == NULL delete "name" meta attr
-+ * != NULL set "name" meta attr
-+ * return value:
-+ * = 0 ok;
-+ * < 0 error;
-+ */
-+
-+static int ext3_set_meta_attr(struct super_block *sb, char* name,
-+ char* buf, int size)
-+{
-+ struct inode *root_inode = sb->s_root->d_inode;
-+ handle_t *handle = NULL;
-+ int error = 0;
-+
-+
-+ handle = ext3_journal_start(root_inode, EXT3_XATTR_TRANS_BLOCKS);
-+ if(!handle)
-+ return -EINVAL;
-+
-+ error = ext3_xattr_set(handle, root_inode, EXT3_SNAP_INDEX, name, buf, size, 0);
-+
-+ ext3_journal_stop(handle, root_inode);
-+
-+ return error;
-+}
-+#endif
+
+struct snapshot_operations ext3_snap_operations = {
+ ops_version: SNAP_VERSION(2,0,2),
+
+
+
-Index: linux-2.4.20-8/fs/ext3/ioctl.c
-===================================================================
---- linux-2.4.20-8.orig/fs/ext3/ioctl.c 2004-01-05 10:54:00.000000000 +0800
-+++ linux-2.4.20-8/fs/ext3/ioctl.c 2004-01-13 00:10:14.000000000 +0800
-@@ -13,6 +13,12 @@
- #include <linux/ext3_jbd.h>
- #include <linux/sched.h>
- #include <asm/uaccess.h>
-+#include <linux/locks.h>
-+
-+#include <linux/snap.h>
-+extern struct snapshot_operations ext3_snap_operations;
-+extern int ext3_snap_print(struct super_block *sb, int index);
-+extern int ext3_snap_delete(struct super_block *sb, int index);
-
-
- int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
-@@ -189,6 +195,103 @@
- return ret;
- }
- #endif
-+#if 0
-+ case EXT3_IOC_SNAP_SETFILECOW: {
-+ printk(KERN_INFO "set file cow on dev %x\n",inode->i_dev);
-+
-+ /* clear block cow feature*/
-+ if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
-+ EXT3_FEATURE_COMPAT_BLOCKCOW)) {
-+ handle_t *handle = ext3_journal_start(inode, 1);
-+
-+ if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
-+ EXT3_FEATURE_COMPAT_SNAPFS)) {
-+ printk(KERN_INFO "can't change cow level while snapfs feature exist");
-+ return -EPERM;
-+ }
-+ lock_super(inode->i_sb);
-+ journal_get_write_access(handle, EXT3_SB(inode->i_sb)->s_sbh);
-+ inode->i_sb->u.ext3_sb.s_es->s_feature_compat &=
-+ cpu_to_le32(~EXT3_FEATURE_COMPAT_BLOCKCOW);
-+ inode->i_sb->s_dirt = 1;
-+ journal_dirty_metadata(handle, EXT3_SB(inode->i_sb)->s_sbh);
-+ unlock_super(inode->i_sb);
-+ ext3_journal_stop(handle, inode);
-+ }
-+ return 0;
-+ }
-+ case EXT3_IOC_CREATE_INDIR: {
-+ struct inode *ind;
-+ printk(KERN_INFO "create indirect on inode %lu\n",inode->i_ino);
-+ ind = ext3_snap_operations.create_indirect(inode, 0, 1, 0);
-+ if (!ind || IS_ERR(ind))
-+ return PTR_ERR(ind);
-+ printk(KERN_INFO "got indirect inode %lu\n",ind->i_ino);
-+ put_user(ind->i_ino,(int *) arg);
-+ iput(ind);
-+ return 0;
-+ }
-+ case EXT3_IOC_GET_INDIR: {
-+ struct inode *ind;
-+ int index = 1;
-+ if (get_user(index, (int *) arg))
-+ return -EFAULT;
-+
-+ printk(KERN_INFO "get indirect on inode %lu, index %d\n",
-+ inode->i_ino, index);
-+ ind = ext3_snap_operations.get_indirect(inode, NULL, index);
-+ if (!ind || IS_ERR(ind)) {
-+ put_user(0,(int *) arg);
-+ return PTR_ERR(ind);
-+ }
-+ printk(KERN_INFO "got indirect inode %lu for index %d\n",
-+ ind->i_ino, index);
-+ put_user(ind->i_ino,(int *) arg);
-+ iput(ind);
-+ return 0;
-+ }
-+ case EXT3_IOC_IS_REDIR: {
-+ int is_redirector = 0;
-+ printk(KERN_INFO "checking if inode %lu is redirector via\n",
-+ inode->i_ino);
-+ is_redirector = ext3_snap_operations.is_redirector(inode);
-+ printk(KERN_INFO "redirector: %s\n",is_redirector ? "yes":"no");
-+ put_user(is_redirector,(int *) arg);
-+
-+ return 0;
-+ }
-+ case EXT3_IOC_RESTORE_INDIR: {
-+ printk(KERN_INFO "restore indirect on inode %lu\n",inode->i_ino);
-+ return ext3_snap_operations.restore_indirect(inode, 1);
-+ }
-+ case EXT3_IOC_SNAP_PRINT: {
-+ int index = 1;
-+ if (get_user(index, (int *) arg))
-+ return -EFAULT;
-+ printk(KERN_INFO "print snap for index %d\n",index);
-+
-+ return ext3_snap_print(inode->i_sb, 1);
-+ }
-+ case EXT3_IOC_SNAP_DELETE: {
-+ int index = 1;
-+ if (get_user(index, (int *) arg))
-+ return -EFAULT;
-+
-+ // XXX: debug code , always set index = 1
-+ if(index !=1) index=1;
-+ printk(KERN_INFO "delete all cowed inode for index %d\n",index);
-+ return ext3_snap_delete(inode->i_sb, index);
-+ }
-+
-+ case EXT3_IOC_DESTROY_INDIR: {
-+ int index = 1;
-+ if (get_user(index, (int *) arg))
-+ index = 1;
-+ printk(KERN_INFO "destroy indirect on ino %lu, index %d\n",
-+ inode->i_ino, index);
-+ return ext3_snap_operations.destroy_indirect(inode, index, NULL);
-+ }
-+#endif
- default:
- return -ENOTTY;
- }
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
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-13 00:10:14.000000000 +0800
++++ linux-2.4.20-8/fs/ext3/inode.c 2004-01-18 01:48:19.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.
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-13 00:10:14.000000000 +0800
-@@ -78,7 +78,6 @@
- sb->u.ext3_sb.s_inode_bitmap[bitmap_nr] = bh;
- return retval;
- }
--
- /*
- * load_inode_bitmap loads the inode bitmap for a blocks group
- *
-@@ -160,6 +159,13 @@
++++ linux-2.4.20-8/fs/ext3/ialloc.c 2004-01-16 20:48:29.000000000 +0800
+@@ -160,6 +160,13 @@
return retval;
}
/*
* NOTE! When we get the inode, we're the only people
* 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
+@@ -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));
+ sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
++#define EXT3_SNAP_FS
++#ifdef EXT3_SNAP_FS
++ init_MUTEX(&(sbi->s_snap_list_sem));
++ sbi->s_snaptable_ino = le32_to_cpu(es->s_snaptable_ino);
++ sbi->s_first_cowed_pri_ino = le32_to_cpu(es->s_first_cowed_pri_ino);
++ sbi->s_last_cowed_pri_ino = le32_to_cpu(es->s_last_cowed_pri_ino);
++#endif
+ 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/include/linux/snap.h
===================================================================
--- linux-2.4.20-8.orig/include/linux/snap.h 2003-01-30 18:24:37.000000000 +0800
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-13 00:10:14.000000000 +0800
++++ linux-2.4.20-8/include/linux/ext3_fs.h 2004-01-16 20:45:09.000000000 +0800
@@ -183,7 +183,13 @@
#define EXT3_INDEX_FL 0x00001000 /* hash-indexed directory */
#define EXT3_IMAGIC_FL 0x00002000 /* AFS directory */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
- __u32 s_reserved[192]; /* Padding to the end of the block */
-+ /* for snapfs */
+ __u32 s_default_mount_opts;
+ __u32 s_first_meta_bg; /* First metablock group */
+ __u32 s_mkfs_time; /* When the filesystem was created */
++ /* for snapfs */
+ __u32 s_first_cowed_pri_ino; /* For snapfs,the first cowed primary inode */
+ __u32 s_last_cowed_pri_ino; /* last cowed ino in memory */
+ __u32 s_snaptable_ino; /* snaptable ino in memory */
+ __u32 s_last_snap_orphan; /* SnapFS: start of cowing indirect inode */
-+ __u32 s_reserved[185]; /* Padding to the end of the block,originally 204 */
++ __u32 s_reserved[186]; /* Padding to the end of the block,originally 204 */
};
#ifdef __KERNEL__
%diffstat
fs/ext3/Makefile | 2
- fs/ext3/ialloc.c | 8
+ fs/ext3/ialloc.c | 7
fs/ext3/inode.c | 2
- fs/ext3/ioctl.c | 103 +
- fs/ext3/snap.c | 2645 +++++++++++++++++++++++++++++++++++++++++++++
+ fs/ext3/snap.c | 2588 +++++++++++++++++++++++++++++++++++++++++++++
+ 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, 3092 insertions(+), 6 deletions(-)
+ 9 files changed, 2939 insertions(+), 5 deletions(-)
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/unistd.h>
+#include <linux/pagemap.h>
#include <linux/jbd.h>
#include <linux/ext3_fs.h>
#include <linux/snap.h>
#include "snapfs_internal.h"
-/* instantiate a file handle to the cache file */
-static void currentfs_prepare_snapfile(struct inode *inode,
- struct file *clone_file,
- struct inode *cache_inode,
- struct file *cache_file,
- struct dentry *cache_dentry)
+static int has_pages(struct inode *inode, int index)
{
- cache_file->f_pos = clone_file->f_pos;
- cache_file->f_mode = clone_file->f_mode;
- cache_file->f_flags = clone_file->f_flags;
- cache_file->f_count = clone_file->f_count;
- cache_file->f_owner = clone_file->f_owner;
- cache_file->f_dentry = cache_dentry;
- cache_file->f_dentry->d_inode = cache_inode;
+ unsigned long offset = index << PAGE_CACHE_SHIFT;
+ unsigned long blk_start = offset >> inode->i_sb->s_blocksize_bits;
+ unsigned long blk_end = (offset + PAGE_CACHE_SIZE) >>
+ inode->i_sb->s_blocksize_bits;
+
+ while (blk_start <= blk_end) {
+ if (inode->i_mapping && inode->i_mapping->a_ops) {
+ if (inode->i_mapping->a_ops->bmap(inode->i_mapping,
+ blk_start))
+ return 1;
+ }
+ blk_start++;
+ }
+ return 0;
}
-/* update the currentfs file struct after IO in cache file */
-static void currentfs_restore_snapfile(struct inode *cache_inode,
- struct file *cache_file,
- struct inode *clone_inode,
- struct file *clone_file)
+static int copy_back_page(struct inode *dst,
+ struct inode *src,
+ unsigned long start,
+ unsigned long end)
{
- cache_file->f_pos = clone_file->f_pos;
-}
+ char *kaddr_src, *kaddr_dst;
+ struct snap_cache *cache;
+ struct address_space_operations *c_aops;
+ struct page *src_page, *dst_page;
+ unsigned long index, offset, bytes;
+ int err = 0;
+ ENTRY;
+ offset = (start & (PAGE_CACHE_SIZE -1)); /* Within page */
+ bytes = end - start;
+ index = start >> PAGE_CACHE_SHIFT;
+
+ if (!has_pages(src, index) || bytes > 4096)
+ RETURN(0);
+
+ cache = snap_find_cache(src->i_dev);
+ if (!cache)
+ RETURN(-EINVAL);
+ c_aops = filter_c2cfaops(cache->cache_filter);
+
+ if (!c_aops)
+ RETURN(-EINVAL);
+
+ src_page = grab_cache_page(src->i_mapping, index);
+ if (!src_page) {
+ CERROR("copy block %lu from %lu to %lu ENOMEM \n",
+ index, src->i_ino, dst->i_ino);
+ RETURN(-ENOMEM);
+ }
+
+ c_aops->readpage(NULL, src_page);
+ wait_on_page(src_page);
+
+ kaddr_src = kmap(src_page);
+ if (!Page_Uptodate(src_page)) {
+ CERROR("Can not read page index %lu of inode %lu\n",
+ index, src->i_ino);
+ err = -EIO;
+ goto unlock_src_page;
+ }
+ dst_page = grab_cache_page(dst->i_mapping, index);
+ if (!dst_page) {
+ CERROR("copy block %lu from %lu to %lu ENOMEM \n",
+ index, src->i_ino, dst->i_ino);
+ err = -ENOMEM;
+ goto unlock_src_page;
+ }
+ kaddr_dst = kmap(dst_page);
+
+ err = c_aops->prepare_write(NULL, dst_page, offset, offset + bytes);
+ if (err)
+ goto unlock_dst_page;
+ memcpy(kaddr_dst, kaddr_src, PAGE_CACHE_SIZE);
+ flush_dcache_page(dst_page);
+
+ err = c_aops->commit_write(NULL, dst_page, offset, offset + bytes);
+ if (err)
+ goto unlock_dst_page;
+ err = 1;
+unlock_dst_page:
+ kunmap(dst_page);
+ UnlockPage(dst_page);
+ page_cache_release(dst_page);
+unlock_src_page:
+ kunmap(src_page);
+ page_cache_release(src_page);
+ RETURN(err);
+}
static ssize_t currentfs_write (struct file *filp, const char *buf,
size_t count, loff_t *ppos)
{
struct snap_cache *cache;
struct inode *inode = filp->f_dentry->d_inode;
- ssize_t rc;
struct file_operations *fops;
- loff_t pos;
- long block[2]={-1,-1}, mask, i;
+ long start[2]={-1,-1}, end[2]={-1,-1};
struct snap_table *table;
- int slot = 0;
- int index = 0;
- struct address_space_operations *aops;
struct inode *cache_inode = NULL;
- struct snapshot_operations *snapops;
+ int slot = 0, index = 0, result = 0;
+ long i;
+ ssize_t rc;
+ loff_t pos;
ENTRY;
if (pos != *ppos)
RETURN(-EINVAL);
}
-
- /*
- * we only need to copy back the first and last blocks
- */
- mask = inode->i_sb->s_blocksize-1;
- if( pos & mask )
- block[0] = pos >> inode->i_sb->s_blocksize_bits;
+ if (pos & PAGE_CACHE_MASK) {
+ start[0] = pos & PAGE_CACHE_MASK;
+ end[0] = pos;
+ }
pos += count - 1;
- if( (pos+1) & mask )
- block[1] = pos >> inode->i_sb->s_blocksize_bits;
- if( block[0] == block[1] )
- block[1] = -1;
+ if ((pos+1) & PAGE_CACHE_MASK) {
+ 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;
- aops = filter_c2cfaops(cache->cache_filter);
- snapops = filter_c2csnapops(cache->cache_filter);
-
- for( i=0; i<2; i++ ){
- if(block[i]!=-1 && aops->bmap(inode->i_mapping, block[i])) {
- table = &snap_tables[cache->cache_snap_tableno];
- for (slot = table->tbl_count - 1; slot >= 1; slot--) {
- struct address_space_operations *c_aops =
- cache_inode->i_mapping->a_ops;
- cache_inode = NULL;
- index = table->snap_items[slot].index;
- cache_inode = snap_get_indirect(inode, NULL, index);
-
- if ( !cache_inode ) continue;
-
- if (c_aops->bmap(cache_inode->i_mapping, block[i])) {
- CDEBUG(D_SNAP, "find cache_ino %lu\n",
- cache_inode->i_ino);
- if( snapops && snapops->copy_block) {
- snapops->copy_block(inode,
- cache_inode, block[i]);
- }
- iput(cache_inode);
- break;
- }
- iput(cache_inode);
- }
- }
+ for (i = 0; i < 2; i++) {
+ if (start[i] == -1)
+ continue;
+ table = &snap_tables[cache->cache_snap_tableno];
+ /*Find the nearest page in snaptable and copy back it*/
+ 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 (!cache_inode) continue;
+
+ CDEBUG(D_SNAP, "find cache_ino %lu\n", cache_inode->i_ino);
+
+ result = copy_back_page(inode, cache_inode, start[i], end[i]);
+ if (result == 1) {
+ CDEBUG(D_SNAP, "copy page%lu back from ind %lu to %lu\n",
+ (start[i] >> PAGE_CACHE_SHIFT),
+ cache_inode->i_ino,
+ inode->i_ino);
+ iput(cache_inode);
+ result = 0;
+ break;
+ }
+ if (result < 0) {
+ iput(cache_inode);
+ rc = result;
+ goto exit;
+ }
+ iput(cache_inode);
+ }
}
- rc = fops->write(filp, buf, count, ppos);
+ rc = fops->write(filp, buf, count, ppos);
+exit:
RETURN(rc);
}
static int currentfs_readpage(struct file *file, struct page *page)
{
- int result = 0;
struct inode *inode = file->f_dentry->d_inode;
unsigned long ind_ino = inode->i_ino;
struct inode *pri_inode = NULL;
struct inode *cache_inode = NULL;
- struct file open_file;
- struct dentry open_dentry ;
struct address_space_operations *c_aops;
struct snap_cache *cache;
- long block;
struct snap_table *table;
- int slot = 0;
- int index = 0;
- int search_older = 0;
+ struct page *cache_page = NULL;
+ int rc = 0, slot = 0, index = 0, search_older = 0;
+ long block;
ENTRY;
c_aops = filter_c2cfaops(cache->cache_filter);
- block = page->index >> inode->i_sb->s_blocksize_bits;
+ block = (page->index << PAGE_CACHE_SHIFT) >> inode->i_sb->s_blocksize_bits;
/* if there is a block in the cache, return the cache readpage */
- if( inode->i_blocks && c_aops->bmap(inode->i_mapping, block) ) {
+ if(c_aops->bmap(inode->i_mapping, block) ) {
CDEBUG(D_SNAP, "block %lu in cache, ino %lu\n",
block, inode->i_ino);
- result = c_aops->readpage(file, page);
- RETURN(result);
+ rc = c_aops->readpage(file, page);
+ RETURN(rc);
}
/*
table = &snap_tables[cache->cache_snap_tableno];
- for (slot = table->tbl_count - 1; slot >= 1; slot--)
- {
- struct address_space_operations *c_aops =
- cache_inode->i_mapping->a_ops;
+ 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);
break;
iput(cache_inode);
}
- if( pri_inode )
- iput(pri_inode);
+ if (pri_inode) iput(pri_inode);
- if ( !cache_inode )
+ if (!cache_inode )
RETURN(-EINVAL);
- currentfs_prepare_snapfile(inode, file, cache_inode, &open_file,
- &open_dentry);
-
down(&cache_inode->i_sem);
- if( c_aops->readpage ) {
- CDEBUG(D_SNAP, "block %lu NOT in cache, use redirected ino %lu\n",
- block, cache_inode->i_ino );
- result = c_aops->readpage(&open_file, page);
- }else {
- CDEBUG(D_SNAP, "cache ino %lu, readpage is NULL\n",
- cache_inode->i_ino);
- }
+ /*Here we have changed a file to read,
+ *So we should rewrite generic file read here
+ *FIXME later, the code is ugly
+ */
+
+ cache_page = grab_cache_page(cache_inode->i_mapping, page->index);
+ if (!cache_page)
+ GOTO(exit_release, rc = -ENOMEM);
+ if ((rc = c_aops->readpage(file, cache_page)))
+ GOTO(exit_release, 0);
+
+ wait_on_page(cache_page);
+
+ if (!Page_Uptodate(cache_page))
+ GOTO(exit_release, rc = -EIO);
+
+ memcpy(kmap(page), kmap(cache_page), PAGE_CACHE_SIZE);
+
+ kunmap(cache_page);
+ page_cache_release(cache_page);
+
up(&cache_inode->i_sem);
- currentfs_restore_snapfile(inode, file, cache_inode, &open_file);
iput(cache_inode);
- RETURN(result);
+
+ kunmap(page);
+ SetPageUptodate(page);
+ UnlockPage(page);
+
+ RETURN(rc);
+
+exit_release:
+ if (cache_page)
+ page_cache_release(cache_page);
+ up(&cache_inode->i_sem);
+ iput(cache_inode);
+ UnlockPage(page);
+ RETURN(rc);
}
+
struct address_space_operations currentfs_file_aops = {
readpage: currentfs_readpage,
};