#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/pagemap.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/stat.h>
struct snap_info *snap_info = S2SNAPI(sb);
struct snap_table *snap_table = NULL;
struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
- int rc = 0, size, table_size, vallen;
+ int rc = 0, size, table_size, vallen, i;
ENTRY;
snap_table->sntbl_magic = cpu_to_le32((__u32)SNAPTABLE_MAGIC);
snap_table->sntbl_max_count = size;
+ for (i = 0; i < snap_table->sntbl_max_count; i++) {
+ /*init sn_index to -1*/
+ snap_table->sntbl_items[i].sn_index = -1;
+ }
/*get snaptable info*/
-
rc = snapops->fs_get_snap_info(sb, NULL, SNAPTABLE_INFO,
strlen(SNAPTABLE_INFO),
snap_table, &table_size);
RETURN(0);
}
/*Dir inode will do cow*/
-int smfs_cow_create(struct inode *dir, struct dentry *dentry)
+int smfs_cow_create(struct inode *dir, struct dentry *dentry,
+ void *data1, void *data2)
{
int rc = 0;
struct dentry *dparent;
RETURN(rc);
}
-int smfs_cow_setattr(struct inode *dir, struct dentry *dentry)
+int smfs_cow_setattr(struct inode *dir, struct dentry *dentry,
+ void *data1, void *data2)
{
int rc = 0;
ENTRY;
RETURN(rc);
}
-int smfs_cow_link(struct inode *dir, struct dentry *dentry)
+int smfs_cow_link(struct inode *dir, struct dentry *dentry,
+ void *data1, void *data2)
{
int rc = 0;
struct dentry *dparent;
RETURN(rc);
}
-int smfs_cow_unlink(struct inode *dir, struct dentry *dentry)
+int smfs_cow_unlink(struct inode *dir, struct dentry *dentry,
+ void *data1, void *data2)
{
struct dentry *dparent;
int rc = 0;
RETURN(rc);
}
-int smfs_cow_rename(struct inode *dir, struct dentry *dentry)
+int smfs_cow_rename(struct inode *dir, struct dentry *dentry,
+ void *data1, void *data2)
{
+ struct inode *new_dir = (struct inode *)data1;
+ struct dentry *new_dentry = (struct dentry *)data2;
+ struct dentry *dparent;
int rc = 0;
ENTRY;
-
+
+ LASSERT(new_dir);
+ LASSERT(new_dentry);
+ if (smfs_needs_cow(dir) != -1) {
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", dir->i_ino);
+ LASSERT(dentry->d_parent && dentry->d_parent->d_parent);
+ dparent = dentry->d_parent->d_parent;
+ if ((snap_do_cow(dir, dparent, 0))) {
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
+ if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 0))) {
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
+ }
+ if (smfs_needs_cow(new_dir) != -1) {
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", new_dir->i_ino);
+ LASSERT(new_dentry->d_parent && new_dentry->d_parent->d_parent);
+ dparent = new_dentry->d_parent->d_parent;
+ if ((new_dir != dir) && (snap_do_cow(new_dir, dparent, 0))){
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
+ if (new_dentry->d_inode && new_dentry->d_inode->i_nlink == 1) {
+ if ((snap_do_cow(new_dentry->d_inode,
+ new_dentry->d_parent, 0))) {
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
+ }
+ }
RETURN(rc);
}
-int smfs_cow_write(struct inode *dir, struct dentry *dentry)
+int smfs_cow_write(struct inode *inode, struct dentry *dentry, void *data1,
+ void *data2)
{
- int rc = 0;
+ struct snap_info *snap_info = S2SNAPI(inode->i_sb);
+ struct snap_table *table = snap_info->sntbl;
+ long blocks[2]={-1,-1};
+ int index = 0, i, rc = 0;
+ size_t count;
+ loff_t pos;
+
ENTRY;
+
+ LASSERT(data1);
+ LASSERT(data2);
+
+ count = *(size_t *)data1;
+ pos = *(loff_t*)data2;
+
+ down(&inode->i_sem);
+ if (smfs_needs_cow(inode) != -1 ) {
+ CDEBUG(D_INFO, "snap_needs_cow for ino %lu \n",inode->i_ino);
+ snap_do_cow(inode, dentry->d_parent, 0);
+ }
+
+ CDEBUG(D_INFO, "write offset %lld count %u \n", pos, count);
+
+ if(pos & (PAGE_CACHE_SIZE - 1)){
+ blocks[0] = pos >> inode->i_sb->s_blocksize_bits;
+ }
+ pos += count - 1;
+ if((pos + 1) & (PAGE_CACHE_SIZE - 1)){
+ blocks[1] = pos >> inode->i_sb->s_blocksize_bits;
+ }
+
+ if (blocks[0] == blocks[1])
+ blocks[1] = -1;
+
+ for (i = 0; i < 2; i++) {
+ int slot = 0;
+ if (blocks[i] == -1)
+ continue;
+ /*Find the nearest page in snaptable and copy back it*/
+ for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
+ struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
+ struct inode *cache_inode = NULL;
+ int result = 0;
+
+ index = table->sntbl_items[slot].sn_index;
+ cache_inode = snapops->fs_get_indirect(inode, NULL, index);
+
+ if (!cache_inode) continue;
+
+ CDEBUG(D_INFO, "find cache_ino %lu\n", cache_inode->i_ino);
+
+ result = snapops->fs_copy_block(inode, cache_inode, blocks[i]);
+ if (result == 1) {
+ iput(cache_inode);
+ result = 0;
+ break;
+ }
+ if (result < 0) {
+ iput(cache_inode);
+ up(&inode->i_sem);
+ GOTO(exit, rc = result);
+ }
+ iput(cache_inode);
+ }
+ }
+exit:
+ up(&inode->i_sem);
RETURN(rc);
}
+EXPORT_SYMBOL(smfs_cow_write);
-typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry);
+struct inode *smfs_cow_get_ind(struct inode *inode, int index)
+{
+ struct snap_info *snap_info = S2SNAPI(inode->i_sb);
+ struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
+ struct snap_table *table = snap_info->sntbl;
+ long block=(index << PAGE_CACHE_SHIFT) >> inode->i_sb->s_blocksize_bits;
+ int slot;
+
+ ENTRY;
+ for (slot = table->sntbl_count - 1; slot >= 0; slot--) {
+ struct address_space_operations *aops = inode->i_mapping->a_ops;
+ struct inode *cache_inode = NULL;
+ int index = 0;
+
+ index = table->sntbl_items[slot].sn_index;
+ cache_inode = snapops->fs_get_indirect(inode, NULL, index);
+
+ if (!cache_inode ) continue;
+
+ if (aops->bmap(cache_inode->i_mapping, block))
+ RETURN(cache_inode);
+ iput(cache_inode);
+ }
+
+ RETURN(NULL);
+}
+EXPORT_SYMBOL(smfs_cow_get_ind);
+typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry,
+ void *new_dir, void *new_dentry);
static cow_funcs smfs_cow_funcs[REINT_MAX + 1] = {
[REINT_SETATTR] smfs_cow_setattr,
[REINT_WRITE] smfs_cow_write,
};
-int smfs_cow(struct inode *dir, struct dentry *dentry, int op)
+int smfs_cow(struct inode *dir, struct dentry *dentry, void *new_dir,
+ void *new_dentry, int op)
{
- return smfs_cow_funcs[op](dir, dentry);
+ return smfs_cow_funcs[op](dir, dentry, new_dir, new_dentry);
}