#include <linux/lustre_idl.h>
#include <linux/lustre_fsfilt.h>
-#include <linux/lustre_snap.h>
#include <linux/lustre_smfs.h>
+#include <linux/lustre_snap.h>
#include "smfs_internal.h"
-#define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + size * sizeof(struct snap))
-static int smfs_init_snaptabe(struct super_block *sb)
+
+#define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + \
+ size * sizeof(struct snap))
+
+int smfs_cleanup_snap_info(struct snap_info *snap_info);
+
+static int smfs_init_snap_super_info(struct smfs_super_info *smfs_info)
+{
+ struct snap_super_info *snap_sinfo;
+ int rc = 0;
+
+ ENTRY;
+
+ OBD_ALLOC(smfs_info->smsi_snap_info,
+ sizeof(struct snap_super_info));
+
+ if (!smfs_info->smsi_snap_info)
+ GOTO(exit, rc = -ENOMEM);
+
+ snap_sinfo = smfs_info->smsi_snap_info;
+
+ /*init snap fsfilt operations*/
+ if (!snap_sinfo->snap_cache_fsfilt) {
+ char *snap_cache_ftype = NULL;
+ int tmp = strlen(smfs_info->smsi_cache_ftype) + strlen("_snap");
+
+ OBD_ALLOC(snap_cache_ftype, tmp + 1);
+ sprintf(snap_cache_ftype, "%s_snap", smfs_info->smsi_cache_ftype);
+ snap_sinfo->snap_cache_fsfilt = fsfilt_get_ops(snap_cache_ftype);
+ OBD_FREE(snap_cache_ftype, tmp + 1);
+ if (!snap_sinfo->snap_cache_fsfilt) {
+ CERROR("Can not get %s fsfilt ops needed by snap\n",
+ snap_cache_ftype);
+ GOTO(exit, rc = -EINVAL);
+ }
+ }
+ if (!snap_sinfo->snap_fsfilt) {
+ char *snap_ftype = NULL;
+ int tmp = strlen(smfs_info->smsi_ftype) + strlen("_snap");
+
+ OBD_ALLOC(snap_ftype, tmp + 1);
+ sprintf(snap_ftype, "%s_snap", smfs_info->smsi_ftype);
+ snap_sinfo->snap_fsfilt = fsfilt_get_ops(snap_ftype);
+ OBD_FREE(snap_ftype, tmp + 1);
+ if (!snap_sinfo->snap_fsfilt) {
+ CERROR("Can not get %s fsfilt ops needed by snap\n",
+ snap_ftype);
+ GOTO(exit, rc = -EINVAL);
+ }
+ }
+ INIT_LIST_HEAD(&snap_sinfo->snap_list);
+exit:
+ if (rc && smfs_info->smsi_snap_info)
+ OBD_FREE(snap_sinfo, sizeof(struct snap_super_info));
+ RETURN(rc);
+}
+/*FIXME-wangdi Should remove it when integrated it with lustre*/
+static struct dentry *smfs_simple_mkdir(struct dentry *dir, char *name,
+ int mode, int fix)
+{
+ struct dentry *dchild;
+ int err = 0;
+
+ dchild = ll_lookup_one_len(name, dir, strlen(name));
+ if (IS_ERR(dchild))
+ GOTO(out_up, dchild);
+
+ if (dchild->d_inode) {
+ int old_mode = dchild->d_inode->i_mode;
+ if (!S_ISDIR(old_mode))
+ GOTO(out_err, err = -ENOTDIR);
+
+ /* Fixup directory permissions if necessary */
+ if (fix && (old_mode & S_IALLUGO) != (mode & S_IALLUGO)) {
+ CWARN("fixing permissions on %s from %o to %o\n",
+ name, old_mode, mode);
+ dchild->d_inode->i_mode = (mode & S_IALLUGO) |
+ (old_mode & ~S_IALLUGO);
+ mark_inode_dirty(dchild->d_inode);
+ }
+ GOTO(out_up, dchild);
+ }
+ err = vfs_mkdir(dir->d_inode, dchild, mode);
+ if (err)
+ GOTO(out_err, err);
+ RETURN(dchild);
+out_err:
+ dput(dchild);
+ dchild = ERR_PTR(err);
+out_up:
+ return dchild;
+
+}
+static struct snap_info *smfs_find_snap_info(struct inode *inode)
+{
+ struct snap_inode_info *snap_iinfo = I2SNAPI(inode);
+ struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
+ struct snap_info *snap_info = NULL, *tmp;
+
+ ENTRY;
+ list_for_each_entry_safe(snap_info, tmp, &snap_sinfo->snap_list,
+ sni_list) {
+ if (snap_info->sni_root_ino == snap_iinfo->sn_root_ino)
+ RETURN(snap_info);
+ }
+ RETURN(NULL);
+}
+
+#if 0
+static int smfs_dotsnap_dir_size(struct inode *inode)
+{
+ struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
+ struct fsfilt_operations *snapops = snap_sinfo->snap_cache_fsfilt;
+ int size = 0, dir_size = 0, blocks, i = 0;
+ struct snap_table *snap_table = NULL;
+ struct snap_info *snap_info = NULL;
+ ENTRY;
+
+ snap_info = smfs_find_snap_info(inode);
+
+ if (!snap_info) {
+ CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+ RETURN(0);
+ }
+ snap_table = snap_info->sni_table;
+ for (i = 0; i < snap_table->sntbl_count; i++) {
+ char *name = snap_table->sntbl_items[i].sn_name;
+ size += snapops->fs_dir_ent_size(name);
+ }
+ /*FIXME this is only for ext3 dir format, may need fix for other FS*/
+ blocks = (size + inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits;
+
+ dir_size = blocks * inode->i_sb->s_blocksize;
+ RETURN(dir_size);
+
+}
+#endif
+
+static int smfs_init_snap_inode_info(struct inode *inode, struct inode *dir, int index)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (!inode)
+ RETURN(0);
+
+ if (dir) {
+ I2SNAPI(inode)->sn_flags = I2SNAPI(dir)->sn_flags;
+ I2SNAPI(inode)->sn_gen = I2SNAPI(dir)->sn_gen;
+ I2SNAPI(inode)->sn_root_ino = I2SNAPI(dir)->sn_root_ino;
+ I2SNAPI(inode)->sn_index = I2SNAPI(inode)->sn_index;
+ } else {
+ I2SNAPI(inode)->sn_flags = 0;
+ I2SNAPI(inode)->sn_gen = 0;
+ }
+
+ I2SNAPI(inode)->sn_index = index;
+
+ if (smfs_dotsnap_inode(inode)) {
+ struct snap_info *snap_info;
+
+ snap_info = smfs_find_snap_info(inode);
+ if (!snap_info) {
+ RETURN(-EIO);
+ }
+ /*init dot_snap inode info*/
+// inode->i_size = (loff_t)smfs_dotsnap_dir_size(inode);
+ inode->i_size = snap_info->sni_table->sntbl_count;
+ inode->i_nlink = snap_info->sni_table->sntbl_count + 2;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ } else if (SMFS_DO_COW(S2SMI(inode->i_sb)) &&
+ (I2SMI(inode)->smi_flags & SM_DO_COW) &&
+ smfs_primary_inode(inode)) {
+ struct snap_inode_info *sni_info = I2SNAPI(inode);
+ struct fsfilt_operations *sops = I2SNAPCOPS(inode);
+ int vallen = 0;
+
+ vallen = sizeof(sni_info->sn_gen);
+
+ rc = sops->fs_get_snap_info(I2CI(inode), SNAP_GENERATION,
+ strlen(SNAP_GENERATION),
+ &sni_info->sn_gen, &vallen);
+ }
+ RETURN(rc);
+}
+
+#define COWED_NAME_LEN (7 + 8 + 1)
+static int smfs_init_cowed_dir(struct snap_info *snap_info, struct inode* inode)
+{
+ struct dentry *dentry = NULL;
+ char name[COWED_NAME_LEN];
+ int rc = 0;
+ ENTRY;
+
+ sprintf(name, ".cowed_%08x", (__u32)inode->i_ino);
+ /*FIXME-WANGDI: will use simple_mkdir, when integrating snap to lustre*/
+ dentry = smfs_simple_mkdir(inode->i_sb->s_root, name, 0777, 1);
+ if (IS_ERR(dentry)) {
+ rc = PTR_ERR(dentry);
+ CERROR("create cowed directory: rc = %d\n", rc);
+ RETURN(rc);
+ }
+ snap_info->sni_cowed_dentry = dentry;
+ /*cleanup cowed inode attr for cowed dir*/
+ SMFS_CLEAN_INODE_COWED(dentry->d_inode);
+ RETURN(rc);
+}
+
+static int smfs_init_dotinfo(struct snap_info *snap_info)
+{
+ struct snap_dot_info *dot_info = NULL;
+ int rc = 0;
+ ENTRY;
+
+ if (snap_info->sni_dot_info)
+ RETURN(-EEXIST);
+
+ OBD_ALLOC(snap_info->sni_dot_info, sizeof(struct snap_dot_info));
+
+ if (!snap_info->sni_dot_info)
+ RETURN(-ENOMEM);
+
+ dot_info = snap_info->sni_dot_info;
+
+ OBD_ALLOC(dot_info->dot_name, strlen(DOT_SNAP_NAME) + 1);
+
+ if (!dot_info->dot_name) {
+ OBD_FREE(snap_info->sni_dot_info, sizeof(struct snap_dot_info));
+ RETURN(-ENOMEM);
+ }
+ memcpy(dot_info->dot_name, DOT_SNAP_NAME, strlen(DOT_SNAP_NAME));
+
+ dot_info->dot_name_len = strlen(DOT_SNAP_NAME);
+ dot_info->dot_snap_enable = 1;
+
+ RETURN(rc);
+}
+
+static int smfs_init_snap_info(struct smfs_super_info *smb,
+ struct snap_info *snap_info, struct inode *inode)
{
- struct snap_info *snap_info = S2SNAPI(sb);
struct snap_table *snap_table = NULL;
- struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
+ struct fsfilt_operations *snapcops;
int rc = 0, size, table_size, vallen, i;
ENTRY;
- init_MUTEX(&snap_info->sntbl_sema);
+ snapcops = smb->smsi_snap_info->snap_cache_fsfilt;
/*Initialized table */
/*get the maxsize of snaptable*/
vallen = sizeof(int);
- rc = snapops->fs_get_snap_info(sb, NULL, MAX_SNAPTABLE_COUNT,
+ rc = snapcops->fs_get_snap_info(I2CI(inode), MAX_SNAPTABLE_COUNT,
strlen(MAX_SNAPTABLE_COUNT), &size,
&vallen);
if (size == 0) {
CERROR("the Max snaptable count should not be zero\n");
- RETURN(-EINVAL);
+ GOTO(exit, rc);
}
-
table_size = SNAPTABLE_SIZE(size);
- OBD_ALLOC(snap_info->sntbl, table_size);
+ OBD_ALLOC(snap_info->sni_table, table_size);
- if (!snap_info->sntbl) {
+ if (!snap_info->sni_table) {
CERROR("No MEM\n");
RETURN(-ENOMEM);
}
- snap_table = snap_info->sntbl;
+ snap_table = snap_info->sni_table;
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*/
+ /*init sn_index to -1*/
+ for (i = 0; i < snap_table->sntbl_max_count; i++)
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);
+ rc = snapcops->fs_get_snap_info(I2CI(inode), SNAPTABLE_INFO,
+ strlen(SNAPTABLE_INFO),
+ snap_table, &table_size);
if (rc < 0) {
- if (rc == -ENOATTR) {
+ if (rc == -ENODATA) {
snap_table->sntbl_count = 0;
- CDEBUG(D_INFO, "No snaptable here\n");
- RETURN(0);
+ rc = 0;
} else {
CERROR("Can not retrive the snaptable from this filesystem\n");
- OBD_FREE(snap_table, table_size);
- RETURN(rc);
+ GOTO(exit, rc);
+ }
+ } else {
+ if (le32_to_cpu(snap_table->sntbl_magic) != SNAPTABLE_MAGIC) {
+ CERROR("On disk snaptable is not right \n");
+ GOTO(exit, rc = -EIO);
}
- }
- if (le32_to_cpu(snap_table->sntbl_magic) != SNAPTABLE_MAGIC) {
- CERROR("On disk snaptable is not right \n");
- OBD_FREE(snap_table, table_size);
- RETURN(-EIO);
}
+ init_MUTEX(&snap_info->sni_sema);
+ snap_info->sni_root_ino = inode->i_ino;
+ rc = smfs_init_cowed_dir(snap_info, inode);
+ if (rc) {
+ CERROR("Init cowed dir error rc=%d\n", rc);
+ GOTO(exit, rc);
+ }
+ rc = smfs_init_dotinfo(snap_info);
+exit:
+ if (rc && snap_table)
+ OBD_FREE(snap_table, table_size);
RETURN(rc);
}
-#define COWED_NAME_LEN (7 + 8 + 1)
-static int smfs_init_cowed_dir(struct super_block *sb, struct dentry* cowed_dir)
+
+static struct snap_info *smfs_create_snap_info(struct smfs_super_info *sinfo,
+ struct inode *inode)
{
- struct snap_info *snap_info = S2SNAPI(sb);
- struct dentry *dentry = NULL;
- struct lvfs_run_ctxt saved;
- char name[COWED_NAME_LEN];
- int rc = 0;
+ struct snap_info *snap_info = NULL;
+ int rc = 0;
ENTRY;
-
- sprintf(name, ".cowed_%08x", (__u32)cowed_dir->d_inode->i_ino);
- push_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
- dentry = simple_mkdir(cowed_dir, name, 0777, 1);
- pop_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
- if (IS_ERR(dentry)) {
- rc = PTR_ERR(dentry);
- CERROR("create cowed directory: rc = %d\n", rc);
- RETURN(rc);
+
+ OBD_ALLOC(snap_info, sizeof(struct snap_info));
+ if (!snap_info)
+ RETURN(ERR_PTR(-ENOMEM));
+ rc = smfs_init_snap_info(sinfo, snap_info, inode);
+ if (rc)
+ GOTO(exit, rc);
+
+ /*set cow flags for the snap root inode*/
+ I2SMI(inode)->smi_flags |= SM_DO_COW;
+ I2SNAPI(inode)->sn_root_ino = inode->i_ino;
+exit:
+ if (rc) {
+ OBD_FREE(snap_info, sizeof(struct snap_info));
+ snap_info = ERR_PTR(rc);
}
- snap_info->sn_cowed_dentry = dentry;
- RETURN(rc);
+ RETURN(snap_info);
}
-int smfs_start_cow(struct super_block *sb)
+
+static int smfs_cow_pre(struct inode *dir, void *dentry, void *new_dir,
+ void *new_dentry, int op);
+
+static int smfs_cow_post(struct inode *dir, void *dentry, void *new_dir,
+ void *new_dentry, int op);
+#define COW_HOOK "cow_hook"
+static int smfs_cow_pre_hook(struct inode *inode, void *dentry, void *data1,
+ void *data2, int op, void *handle)
{
- struct smfs_super_info *smfs_info = S2SMI(sb);
int rc = 0;
-
ENTRY;
- OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_info));
-
- if (!smfs_info->smsi_snap_info)
- RETURN(-ENOMEM);
-
- /*init snap fsfilt operations*/
- if (!S2SNAPI(sb)->snap_cache_fsfilt) {
- char *snap_cache_ftype = NULL;
- int tmp = strlen(S2SMI(sb)->smsi_cache_ftype) + strlen("_snap");
-
- OBD_ALLOC(snap_cache_ftype, tmp + 1);
- sprintf(snap_cache_ftype, "%s_snap", S2SMI(sb)->smsi_cache_ftype);
- S2SNAPI(sb)->snap_cache_fsfilt = fsfilt_get_ops(snap_cache_ftype);
- OBD_FREE(snap_cache_ftype, tmp + 1);
- if (!S2SNAPI(sb)->snap_cache_fsfilt) {
- CERROR("Can not get %s fsfilt ops needed by snap\n",
- snap_cache_ftype);
- RETURN(-EINVAL);
- }
- }
- if (!S2SNAPI(sb)->snap_fsfilt) {
- char *snap_ftype = NULL;
- int tmp = strlen(S2SMI(sb)->smsi_ftype) + strlen("_snap");
-
- OBD_ALLOC(snap_ftype, tmp + 1);
- sprintf(snap_ftype, "%s_snap", S2SMI(sb)->smsi_ftype);
- S2SNAPI(sb)->snap_fsfilt = fsfilt_get_ops(snap_ftype);
- OBD_FREE(snap_ftype, tmp + 1);
- if (!S2SNAPI(sb)->snap_fsfilt) {
- CERROR("Can not get %s fsfilt ops needed by snap\n",
- snap_ftype);
- RETURN(-EINVAL);
- }
+
+ if (smfs_do_cow(inode)) {
+ /*FIXME:WANGDI, get index from the dentry*/
+ #if 0
+ int index = 0;
+ smfs_get_dentry_name_index(dentry, &name, index);
+ smfs_free_dentry_name(&name);
+ #endif
+ rc = smfs_cow_pre(inode, dentry, data1, data2, op);
}
- rc = smfs_init_snaptabe(sb);
- if (rc) {
- CERROR("can not init snaptable rc=%d\n", rc);
- RETURN(rc);
+ RETURN(rc);
+}
+static int smfs_cow_post_hook(struct inode *inode, void *dentry, void *data1,
+ void *data2, int op, void *handle)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (smfs_do_cow(inode)) {
+ rc = smfs_cow_post(inode, dentry, data1, data2, op);
}
- /*init cowed dir to put the primary cowed inode
- *FIXME-WANGDI, later the s_root may not be the
- *snap dir, we can indicate any dir to be cowed*/
- rc = smfs_init_cowed_dir(sb, sb->s_root);
- RETURN(rc);
+ RETURN(rc);
}
-EXPORT_SYMBOL(smfs_start_cow);
-int smfs_stop_cow(struct super_block *sb)
+
+int smfs_cow_cleanup(struct smfs_super_info *smb)
{
- struct snap_info *snap_info = S2SNAPI(sb);
- struct snap_table *snap_table = snap_info->sntbl;
- int rc = 0, table_size;
+ struct snap_super_info *snap_sinfo = smb->smsi_snap_info;
+ struct list_head *snap_list = &snap_sinfo->snap_list;
+ struct smfs_hook_ops *cow_hops;
+ int rc = 0;
ENTRY;
- l_dput(snap_info->sn_cowed_dentry);
+ while (!list_empty(snap_list)) {
+ struct snap_info *snap_info;
+
+ snap_info = list_entry(snap_list->next, struct snap_info,
+ sni_list);
+ rc = smfs_cleanup_snap_info(snap_info);
+ if (rc)
+ CERROR("cleanup snap_info error rc=%d\n", rc);
+ list_del(&snap_info->sni_list);
+ OBD_FREE(snap_info, sizeof(struct snap_info));
+ }
- if (snap_info->snap_fsfilt)
- fsfilt_put_ops(snap_info->snap_fsfilt);
- if (snap_info->snap_cache_fsfilt)
- fsfilt_put_ops(snap_info->snap_cache_fsfilt);
+ if (snap_sinfo->snap_fsfilt)
+ fsfilt_put_ops(snap_sinfo->snap_fsfilt);
+ if (snap_sinfo->snap_cache_fsfilt)
+ fsfilt_put_ops(snap_sinfo->snap_cache_fsfilt);
- if (snap_table) {
- table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
- OBD_FREE(snap_info->sntbl, table_size);
- }
- if (snap_info)
- OBD_FREE(snap_info, sizeof(*snap_info));
-
+ cow_hops = smfs_unregister_hook_ops(smb, COW_HOOK);
+ smfs_free_hook_ops(cow_hops);
+
+ SMFS_CLEAN_COW(smb);
+ if (snap_sinfo)
+ OBD_FREE(snap_sinfo, sizeof(struct snap_super_info));
RETURN(rc);
}
-EXPORT_SYMBOL(smfs_stop_cow);
int smfs_cow_init(struct super_block *sb)
{
struct smfs_super_info *smfs_info = S2SMI(sb);
- int rc = 0;
+ struct smfs_hook_ops *cow_hops = NULL;
+ struct fsfilt_operations *sops;
+ struct inode *root_inode = smfs_info->smsi_sb->s_root->d_inode;
+ int snap_count = 0, rc = 0, vallen;
+
+ ENTRY;
SMFS_SET_COW(smfs_info);
+ cow_hops = smfs_alloc_hook_ops(COW_HOOK, smfs_cow_pre_hook,
+ smfs_cow_post_hook);
+ if (!cow_hops) {
+ RETURN(-ENOMEM);
+ }
+
+ rc = smfs_register_hook_ops(smfs_info, cow_hops);
+ if (rc) {
+ smfs_free_hook_ops(cow_hops);
+ RETURN(rc);
+ }
+
+ rc = smfs_init_snap_super_info(smfs_info);
+ if (rc && cow_hops) {
+ smfs_unregister_hook_ops(smfs_info, cow_hops->smh_name);
+ smfs_free_hook_ops(cow_hops);
+ RETURN(rc);
+ }
+ sops = smfs_info->smsi_snap_info->snap_cache_fsfilt;
+
+ vallen = sizeof(int);
+ rc = sops->fs_get_snap_info(root_inode, SNAP_COUNT, strlen(SNAP_COUNT),
+ &snap_count, &vallen);
+ if (rc < 0)
+ GOTO(exit, rc);
+
+ if (snap_count > 0) {
+ int snap_root_size = snap_count * sizeof(ino_t);
+ ino_t *snap_root;
+ int i;
+
+ OBD_ALLOC(snap_root, snap_root_size);
+
+ if (!snap_root)
+ GOTO(exit, rc = -ENOMEM);
+
+ rc = sops->fs_get_snap_info(root_inode, SNAP_ROOT_INO,
+ strlen(SNAP_ROOT_INO), snap_root,
+ &snap_root_size);
+ if (rc < 0) {
+ OBD_FREE(snap_root, sizeof(int) * snap_count);
+ GOTO(exit, rc);
+ }
+ for (i = 0; i < snap_count; i++) {
+ ino_t root_ino = le32_to_cpu(snap_root[i]);
+ struct snap_info *snap_info;
+
+ root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
+ smfs_init_snap_inode_info(root_inode, NULL, 0);
+ snap_info = smfs_create_snap_info(S2SMI(sb), root_inode);
+ iput(root_inode);
+ if (IS_ERR(snap_info)) {
+ OBD_FREE(snap_root, sizeof(int) * snap_count);
+ GOTO(exit, rc = PTR_ERR(snap_info));
+ }
+ list_add(&snap_info->sni_list,
+ &(S2SNAPI(sb)->snap_list));
+ }
+ }
+ smfs_info->smsi_snap_info->snap_count = snap_count;
+exit:
+ if (rc)
+ smfs_cow_cleanup(smfs_info);
RETURN(rc);
}
-int smfs_cow_cleanup(struct super_block *sb)
-{
+static int smfs_cleanup_dotinfo(struct snap_info *snap_info)
+{
+ struct snap_dot_info *dot_info = NULL;
+ int rc = 0;
ENTRY;
- SMFS_CLEAN_COW(S2SMI(sb));
- RETURN(0);
+
+ if (!snap_info->sni_dot_info)
+ RETURN(rc);
+
+ dot_info = snap_info->sni_dot_info;
+
+ if (dot_info->dot_name) {
+ OBD_FREE(dot_info->dot_name, dot_info->dot_name_len + 1);
+ }
+
+ OBD_FREE(dot_info, sizeof(struct snap_dot_info));
+
+ RETURN(rc);
}
-/*FIXME Note indirect and primary inode
-* should be recorgnized here*/
-int smfs_init_snap_inode_info(struct inode *inode, int flags)
+int smfs_cleanup_snap_info(struct snap_info *snap_info)
{
- int vallen, rc = 0;
+ struct snap_table *snap_table = snap_info->sni_table;
+ int rc = 0, table_size;
ENTRY;
- if (SMFS_DO_COW(S2SMI(inode->i_sb)) &&
- (flags & SM_DO_COW)) {
- struct snap_inode_info *sni_info = I2SNAPI(inode);
- struct fsfilt_operations *snapops = I2SNAPOPS(inode);
-
- sni_info->sn_flags = flags;
- vallen = sizeof(sni_info->sn_gen);
+ l_dput(snap_info->sni_cowed_dentry);
+ //d_unalloc(snap_info->sni_cowed_dentry);
+ if (snap_table) {
+ table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
+ OBD_FREE(snap_info->sni_table, table_size);
+ }
+ smfs_cleanup_dotinfo(snap_info);
+ RETURN(rc);
+}
- rc = snapops->fs_get_snap_info(NULL, inode, SNAP_GENERATION,
- strlen(SNAP_GENERATION),
- &sni_info->sn_gen, &vallen);
- }
- RETURN(rc);
-
+int smfs_snap_test_inode(struct inode *inode, void *args)
+{
+ struct smfs_iget_args *sargs = (struct smfs_iget_args*)args;
+ struct inode *dir;
+
+ LASSERT(sargs);
+
+ dir = sargs->s_inode;
+
+ if (sargs->s_index > 0) {
+ if (I2SNAPI(inode)->sn_index != sargs->s_index)
+ return 0;
+ }else {
+ if (dir && I2SNAPI(inode)->sn_index != I2SNAPI(dir)->sn_index)
+ return 0;
+ }
+ return 1;
}
/* latest snap: returns
- 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 super_block *sb, struct snap *snap)
+void snap_last(struct inode *inode, struct snap *snap)
{
- struct snap_info *snap_info = S2SNAPI(sb);
- struct snap_table *table = snap_info->sntbl;
- time_t now = CURRENT_TIME;
+ time_t now = LTIME_S(CURRENT_TIME);
+ struct snap_table *snap_table;
+ struct snap_info *snap_info;
int i ;
ENTRY;
+
+ snap_info = smfs_find_snap_info(inode);
+ if (!snap_info) {
+ CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+ EXIT;
+ return;
+ }
+ snap_table = snap_info->sni_table;
/* start at the highest index in the superblock snaptime array */
- if (table->sntbl_count == 0) {
+ if (snap_table->sntbl_count == 0) {
memset(snap, 0, sizeof(struct snap));
} else {
- i = table->sntbl_count - 1;
- snap->sn_index = table->sntbl_items[i].sn_index;
- snap->sn_time = table->sntbl_items[i].sn_time;
- snap->sn_gen = table->sntbl_items[i].sn_gen;
+ i = snap_table->sntbl_count - 1;
+ snap->sn_index = snap_table->sntbl_items[i].sn_index;
+ snap->sn_time = snap_table->sntbl_items[i].sn_time;
+ snap->sn_gen = snap_table->sntbl_items[i].sn_gen;
}
CDEBUG(D_INFO, "index: %d, time[i]: %ld, now: %ld\n",
snap->sn_index, snap->sn_time, now);
return;
}
-static int inline get_index_of_item(struct snap_table *table, char *name)
+static inline int get_index_of_item(struct snap_table *table, char *name)
{
int count = table->sntbl_count;
int i, j;
}
}
- for (i = 0; i < table->sntbl_max_count; i++) {
+ for (i = 1; i <= table->sntbl_max_count; i++) {
int found = 0;
for (j = 0; j < (count + 1); j++) {
if (table->sntbl_items[j].sn_index == i) {
RETURN(-ENOSPC);
}
-int smfs_add_snap_item(struct super_block *sb, char *name)
+static struct dentry *smfs_find_snap_root(struct super_block *sb,
+ char *path_name)
{
- struct snap_info *snap_info = S2SNAPI(sb);
- struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
- struct snap_table *snap_table = snap_info->sntbl;
- struct snap *snap_item;
- int table_size, count = 0, index = 0, rc = 0;
+ struct dentry *dentry = NULL;
+ struct nameidata nd;
+ int error;
+ ENTRY;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+ if (path_init(path_name, LOOKUP_FOLLOW, &nd)) {
+ error = path_walk(path_name, &nd);
+ if (error) {
+ path_release(&nd);
+ RETURN(NULL);
+ }
+ } else {
+ RETURN(NULL);
+ }
+#else
+ if (path_lookup(path_name, LOOKUP_FOLLOW, &nd))
+ RETURN(NULL);
+
+#endif
+ dentry = dget(nd.dentry);
+ path_release(&nd);
+ RETURN(dentry);
+}
+static int snap_add_item(struct smfs_super_info *smb,
+ struct snap_info *snap_info,
+ char *name)
+{
+ struct fsfilt_operations *snapops;
+ struct snap_table *snap_table = snap_info->sni_table;
+ struct inode *root_inode = NULL;
+ int table_size, count = 0, index = 0, rc = 0;
+ struct snap *snap_item;
+ ENTRY;
count = snap_table->sntbl_count;
+ root_inode = iget(smb->smsi_sb, snap_info->sni_root_ino);
+ if (!root_inode || is_bad_inode(root_inode))
+ RETURN(-EIO);
/* XXX Is down this sema necessary*/
- down_interruptible(&snap_info->sntbl_sema);
+ down_interruptible(&snap_info->sni_sema);
snap_item = &snap_table->sntbl_items[count];
-
+ snapops = smb->smsi_snap_info->snap_cache_fsfilt;
/*add item in snap_table set generation*/
- snap_item->sn_time = CURRENT_TIME;
+ snap_item->sn_time = LTIME_S(CURRENT_TIME);
/* find table index */
index = get_index_of_item(snap_table, name);
if (index < 0)
memcpy(snap_item->sn_name, name, SNAP_MAX_NAMELEN);
/* Wrote the whole snap_table to disk */
table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
-
- rc = snapops->fs_set_snap_info(sb, NULL, SNAPTABLE_INFO,
+
+ snap_table->sntbl_count++;
+ snap_table->sntbl_generation++;
+ rc = snapops->fs_set_snap_info(root_inode, SNAPTABLE_INFO,
strlen(SNAPTABLE_INFO),
snap_table, &table_size);
if (rc) {
+ snap_table->sntbl_count--;
+ snap_table->sntbl_generation--;
CERROR("Set snaptable error rc=%d\n", rc);
GOTO(exit, rc);
}
- snap_table->sntbl_count++;
- snap_table->sntbl_generation++;
exit:
- up(&snap_info->sntbl_sema);
+ up(&snap_info->sni_sema);
+ if (root_inode)
+ iput(root_inode);
RETURN(rc);
}
-EXPORT_SYMBOL(smfs_add_snap_item);
+
+static struct snap_info * smfs_find_create_snap_info(struct super_block *sb,
+ struct inode *inode)
+{
+ struct snap_super_info *snap_sinfo = S2SNAPI(sb);
+ struct fsfilt_operations *sops = snap_sinfo->snap_cache_fsfilt;
+ struct snap_info *snap_info, *tmp;
+ ino_t *snap_root = NULL;
+ int rino_size, snap_count_size, rc = 0;
+ ENTRY;
+
+ list_for_each_entry_safe(snap_info, tmp, &snap_sinfo->snap_list,
+ sni_list) {
+ if (snap_info->sni_root_ino == inode->i_ino) {
+ RETURN(snap_info);
+ }
+ }
+
+ CDEBUG(D_INFO, "create a new snap info root ino %lu\n", inode->i_ino);
+
+ snap_info = smfs_create_snap_info(S2SMI(sb), inode);
+
+ if (IS_ERR(snap_info))
+ RETURN(snap_info);
+
+ snap_sinfo->snap_count++;
+
+ rino_size = snap_sinfo->snap_count * sizeof(ino_t);
+
+ OBD_ALLOC(snap_root, rino_size);
+
+ if (!snap_root)
+ GOTO(exit, rc = -ENOMEM);
+
+ rc = sops->fs_get_snap_info(I2CI(inode), SNAP_ROOT_INO,
+ strlen(SNAP_ROOT_INO), snap_root,
+ &rino_size);
+ if (rc < 0) {
+ if (rc == -ENODATA) {
+ rc = 0;
+ } else {
+ GOTO(exit, rc);
+ }
+ }
+ snap_root[snap_sinfo->snap_count - 1] = inode->i_ino;
+
+ snap_count_size = sizeof(int);
+ rc = sops->fs_set_snap_info(I2CI(inode), SNAP_COUNT, strlen(SNAP_COUNT),
+ &snap_sinfo->snap_count, &snap_count_size);
+ if (rc)
+ GOTO(exit, rc);
+
+ rc = sops->fs_set_snap_info(I2CI(inode), SNAP_ROOT_INO,
+ strlen(SNAP_ROOT_INO), snap_root,
+ &rino_size);
+
+ if (rc)
+ GOTO(exit, rc);
+
+ list_add(&snap_info->sni_list, &snap_sinfo->snap_list);
+exit:
+ if (rc) {
+ smfs_cleanup_snap_info(snap_info);
+ OBD_FREE(snap_info, sizeof(struct snap_info));
+ }
+ if (snap_root)
+ OBD_FREE(snap_root, rino_size);
+ RETURN(snap_info);
+}
+
+int smfs_add_snap_item(struct super_block *sb, char *path_name, char *name)
+{
+ struct dentry *dentry = NULL;
+ struct snap_info *snap_info;
+ int rc = 0;
+ ENTRY;
+
+ if (!SMFS_DO_COW(S2SMI(sb))) {
+ RETURN(0);
+ }
+
+ if (!path_name || !name) {
+ CERROR("patch_name and snapshot_name is NULL");
+ RETURN(-EINVAL);
+ }
+ dentry = smfs_find_snap_root(sb, path_name);
+ if (IS_ERR(dentry)) {
+ CERROR("can not find snap_shot root by %s\n", path_name);
+ RETURN(PTR_ERR(dentry));
+ }
+ snap_info = smfs_find_create_snap_info(sb, dentry->d_inode);
+ if (IS_ERR(snap_info)) {
+ CERROR("can not find snap_info by %s rc=%lu\n", path_name,
+ PTR_ERR(snap_info));
+ GOTO(exit, rc = PTR_ERR(snap_info));
+ }
+
+ rc = snap_add_item(S2SMI(sb), snap_info, name);
+exit:
+ dput(dentry);
+ RETURN(rc);
+}
+//EXPORT_SYMBOL(smfs_add_snap_item);
/*
* Note: this function should be differnet with snap_do_cow.
* In smfs_do_cow, we check the EA for whether do cow for that inode.
snap_info = &(smi_info->sm_sninfo);
- snap_last(inode->i_sb, &snap);
+ snap_last(inode, &snap);
/* decision .... if the snapshot is more recent than the object,
* then any change to the object should cause a COW.
*/
static int link_cowed_inode(struct inode *inode)
{
- struct snap_info *snap_info = S2SNAPI(inode->i_sb);
struct dentry *cowed_dir = NULL;
- char fidname[LL_FID_NAMELEN];
- int fidlen = 0, rc = 0;
+ char idname[LL_ID_NAMELEN];
+ struct snap_info *snap_info;
+ int idlen = 0, rc = 0;
struct dentry *dchild = NULL;
struct dentry *tmp = NULL;
unsigned mode;
- cowed_dir = snap_info->sn_cowed_dentry;
-
- fidlen = ll_fid2str(fidname, inode->i_ino, inode->i_generation);
+ snap_info = smfs_find_snap_info(inode);
+ if (!snap_info) {
+ CERROR("can not find snap info for inode %p\n", inode);
+ RETURN(-EINVAL);
+ }
+ cowed_dir = snap_info->sni_cowed_dentry;
+
down(&cowed_dir->d_inode->i_sem);
- dchild = ll_lookup_one_len(fidname, cowed_dir, fidlen);
+
+ idlen = ll_id2str(idname, inode->i_ino, inode->i_generation);
+ dchild = lookup_one_len(idname, cowed_dir, idlen);
if (IS_ERR(dchild)) {
rc = PTR_ERR(dchild);
if (rc != -EPERM && rc != -EACCES)
* for linking and return real mode back then -bzzz */
mode = inode->i_mode;
inode->i_mode = S_IFREG;
- rc = vfs_link(tmp, cowed_dir->d_inode, dchild);
+
+ rc = cowed_dir->d_inode->i_op->link(tmp, cowed_dir->d_inode, dchild);
+
post_smfs_dentry(tmp);
if (rc) {
CERROR("error linking cowed inode %s to COWED: rc = %d\n",
- fidname, rc);
+ idname, rc);
}
inode->i_mode = mode;
if ((mode & S_IFMT) == S_IFDIR) {
dchild->d_inode->i_nlink++;
cowed_dir->d_inode->i_nlink++;
+ mark_inode_dirty(cowed_dir->d_inode);
+ mark_inode_dirty(dchild->d_inode);
}
- mark_inode_dirty(dchild->d_inode);
out_dput:
+ up(&cowed_dir->d_inode->i_sem);
dput(dchild);
out_lock:
- up(&cowed_dir->d_inode->i_sem);
RETURN(rc);
}
/*
*/
int snap_do_cow(struct inode *inode, struct dentry *dparent, int del)
{
- struct snap_info *snap_info = S2SNAPI(inode->i_sb);
- struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
+ struct fsfilt_operations *snapops = I2SNAPCOPS(inode);
struct snap snap;
- struct inode *ind = NULL;
-
- ENTRY;
+ struct inode *cache_ind = NULL;
+ ENTRY;
if (!snapops || !snapops->fs_create_indirect)
RETURN(-EINVAL);
- snap_last(inode->i_sb, &snap);
- ind = snapops->fs_create_indirect(inode, snap.sn_index, snap.sn_gen,
- dparent->d_inode, del);
- if(!ind)
- RETURN(-EINVAL);
- if (!SMFS_DO_INODE_COWED(inode)) {
- /*insert the inode to cowed inode*/
- SMFS_SET_INODE_COWED(inode);
- link_cowed_inode(inode);
+ snap_last(inode, &snap);
+ cache_ind = snapops->fs_create_indirect(I2CI(inode), snap.sn_index,
+ snap.sn_gen, I2CI(dparent->d_inode),
+ del);
+ if(cache_ind && IS_ERR(cache_ind)) {
+ CERROR("Create ind inode %lu index %d gen %d del %d rc%lu\n",
+ inode->i_ino, snap.sn_index, snap.sn_gen, del,
+ PTR_ERR(cache_ind));
+ RETURN(PTR_ERR(cache_ind));
+ }
+ if (cache_ind) {
+ iput(cache_ind);
+ if (!SMFS_DO_INODE_COWED(inode)) {
+ /*insert the inode to cowed inode*/
+ SMFS_SET_INODE_COWED(inode);
+ link_cowed_inode(inode);
+ }
}
-
- I2SMI(ind)->sm_sninfo.sn_flags = 0;
- I2SMI(ind)->sm_sninfo.sn_gen = snap.sn_gen;
-
- iput(ind);
RETURN(0);
}
/*Dir inode will do cow*/
-int smfs_cow_create(struct inode *dir, struct dentry *dentry,
- void *data1, void *data2)
+int smfs_cow_create_pre(struct inode *dir, void *de, void *data1, void *data2)
{
- int rc = 0;
struct dentry *dparent;
+ struct dentry *dentry = (struct dentry *)de;
+ int rc = 0;
ENTRY;
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");
+ if ((rc = snap_do_cow(dir, dparent, 0))) {
+ CERROR("Do cow error %d\n", rc);
RETURN(-EINVAL);
}
}
RETURN(rc);
}
-int smfs_cow_setattr(struct inode *dir, struct dentry *dentry,
- void *data1, void *data2)
+int smfs_cow_setattr_pre(struct inode *dir, void *de, void *data1, void *data2)
{
+ struct dentry *dentry = (struct dentry *)de;
int rc = 0;
ENTRY;
if (smfs_needs_cow(dir) != -1) {
RETURN(rc);
}
-int smfs_cow_link(struct inode *dir, struct dentry *dentry,
- void *data1, void *data2)
+int smfs_cow_link_pre(struct inode *dir, void *de, void *data1, void *data2)
{
- int rc = 0;
struct dentry *dparent;
+ struct dentry *dentry = (struct dentry *)de;
+ int rc = 0;
ENTRY;
if (smfs_needs_cow(dir) != -1) {
RETURN(rc);
}
-int smfs_cow_unlink(struct inode *dir, struct dentry *dentry,
- void *data1, void *data2)
+int smfs_cow_unlink_pre(struct inode *dir, void *de, void *data1, void *data2)
{
+ struct dentry *dentry = (struct dentry *)de;
struct dentry *dparent;
int rc = 0;
ENTRY;
RETURN(rc);
}
-int smfs_cow_rename(struct inode *dir, struct dentry *dentry,
- void *data1, void *data2)
+int smfs_cow_rename_pre(struct inode *dir, void *de, void *data1, void *data2)
{
+ struct dentry *dentry = (struct dentry*)de;
struct inode *new_dir = (struct inode *)data1;
struct dentry *new_dentry = (struct dentry *)data2;
struct dentry *dparent;
RETURN(rc);
}
-int smfs_cow_write(struct inode *inode, struct dentry *dentry, void *data1,
- void *data2)
+int smfs_cow_write_pre(struct inode *inode, void *de, void *data1, void *data2)
{
- struct snap_info *snap_info = S2SNAPI(inode->i_sb);
- struct snap_table *table = snap_info->sntbl;
+ struct dentry *dentry = (struct dentry*)de;
+ struct snap_info *snap_info = NULL;
+ struct snap_table *table;
long blocks[2]={-1,-1};
int index = 0, i, rc = 0;
size_t count;
ENTRY;
+ snap_info = smfs_find_snap_info(inode);
+ if (!snap_info) {
+ CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+ RETURN(0);
+ }
+ table = snap_info->sni_table;
+
LASSERT(data1);
LASSERT(data2);
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;
+ struct fsfilt_operations *sops = I2SNAPCOPS(inode);
+ struct inode *cind = NULL;
int result = 0;
index = table->sntbl_items[slot].sn_index;
- cache_inode = snapops->fs_get_indirect(inode, NULL, index);
-
- if (!cache_inode) continue;
+ cind = sops->fs_get_indirect(I2CI(inode), NULL, index);
+ if (!cind) continue;
- CDEBUG(D_INFO, "find cache_ino %lu\n", cache_inode->i_ino);
+ CDEBUG(D_INFO, "find cache_ino %lu\n", cind->i_ino);
- result = snapops->fs_copy_block(inode, cache_inode, blocks[i]);
+ result = sops->fs_copy_block(I2CI(inode), cind,
+ blocks[i]);
if (result == 1) {
- iput(cache_inode);
+ iput(cind);
result = 0;
break;
}
if (result < 0) {
- iput(cache_inode);
+ iput(cind);
up(&inode->i_sem);
GOTO(exit, rc = result);
}
- iput(cache_inode);
+ iput(cind);
}
}
exit:
up(&inode->i_sem);
RETURN(rc);
}
-EXPORT_SYMBOL(smfs_cow_write);
+EXPORT_SYMBOL(smfs_cow_write_pre);
+/*lookup inode in dotsnap inode */
+static int smfs_dotsnap_lookup(struct inode *dir, struct dentry *dentry,
+ struct snap_info *snap_info)
+{
+ if (dentry->d_name.len == 1 &&
+ !strcmp(dentry->d_name.name, ".")) {
+ d_add(dentry, iget(dir->i_sb, dir->i_ino));
+ } else if (dentry->d_name.len == 2 &&
+ !strcmp(dentry->d_name.name, "..")) {
+ struct inode *inode;
+ struct dentry *dparent = dentry->d_parent;
+ if (dparent->d_inode) {
+ inode = iget(dir->i_sb, dparent->d_inode->i_ino);
+ if (inode) {
+ if (!is_bad_inode(inode))
+ d_add(dentry, inode);
+ else
+ iput(inode);
+ }
+ }
+ } else {
+ /*find the name from the snaptable*/
+ struct fsfilt_operations *sops = I2SNAPCOPS(dir);
+ struct snap_table *table;
+ struct inode *inode;
+ ino_t cino;
+ int i = 0, index = -1;
+
+ table = snap_info->sni_table;
+
+ for (i = 0; i < table->sntbl_count; i++) {
+ char *name = table->sntbl_items[i].sn_name;
+ if ((dentry->d_name.len == strlen(name)) &&
+ (memcmp(dentry->d_name.name, name,
+ dentry->d_name.len) == 0)) {
+ index = table->sntbl_items[i].sn_index;
+ break;
+ }
+ }
+ if (index == -1) {
+ CERROR("No such %s in this .snap dir \n",
+ dentry->d_name.name);
+ RETURN(-ENOENT);
+ }
+ cino = sops->fs_get_indirect_ino(S2CSB(dir->i_sb), dir->i_ino,
+ index);
+ if (cino == 0)
+ cino = dir->i_ino;
+ inode = smfs_get_inode(dir->i_sb, cino, dir, index);
+ if (!inode || is_bad_inode(inode)) {
+ CERROR("Can not find cino %lu inode\n", cino);
+ RETURN(-ENOENT);
+ }
+ smfs_init_snap_inode_info(inode, dir, index);
+ d_add(dentry, inode);
+ }
+ RETURN(0);
+}
+int smfs_cow_lookup_pre(struct inode *inode, void *de, void *data1,
+ void *data2)
+{
+ struct dentry *dentry = (struct dentry*)de;
+ struct snap_info *snap_info;
+ struct snap_dot_info *dot_info;
+ int rc = 0;
+ ENTRY;
+
+ snap_info = smfs_find_snap_info(inode);
+ if (!snap_info) {
+ CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+ RETURN(0);
+ }
+
+ dot_info = snap_info->sni_dot_info;
+
+ if (smfs_primary_inode(inode) &&
+ dentry->d_name.len == dot_info->dot_name_len &&
+ memcmp(dentry->d_name.name, dot_info->dot_name,
+ strlen(dot_info->dot_name)) == 0) {
+ struct inode *dot_inode = NULL;
+
+ dot_inode = smfs_get_inode(inode->i_sb, inode->i_ino, inode,
+ DOT_SNAP_INDEX);
+ smfs_init_snap_inode_info(dot_inode, inode, DOT_SNAP_INDEX);
+ d_add(dentry, dot_inode);
+ rc = 1;
+ RETURN(rc);
+ } else if (smfs_dotsnap_inode(inode)) {
+ rc = smfs_dotsnap_lookup(inode, dentry, snap_info);
+ if (rc == 0)
+ rc = 1;
+ RETURN(rc);
+ } else {
+ /*HERE: will replace ino in dentry->d_name according to index,
+ *For iopen, will fix it in integrating snapfs to Lustre*/
+#if 0
+ struct fsfilt_operations *snapops = I2SNAPOPS(inode);
+ char *name = (char *)dentry->d_name.name;
+ unsigned long ino, hash, ind_ino;
+ int len = sizeof(ind_ino);
+
+ ino = simple_strtoul(name, 0, 0);
+
+ ind_ino = snapops->fs_get_indirect_ino(inode->i_sb, ino, index);
+
+ snprintf(name, strlen(name), "0x%lx", ind_ino);
+
+ hash = init_name_hash();
+ while (len--) {
+ unsigned char c;
+ c = *(const unsigned char *)name++;
+ if (c == '\0') break;
+ hash = partial_name_hash(c, hash);
+ }
+ dentry->d_name.hash = end_name_hash(hash);
+#endif
+ }
+ RETURN(rc);
+}
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;
+ struct fsfilt_operations *sops = I2SNAPCOPS(inode);
+ struct snap_info *snap_info = NULL;
+ struct snap_table *table = NULL;
int slot;
- ENTRY;
+ ENTRY;
+
+ snap_info = smfs_find_snap_info(inode);
+ if (!snap_info) {
+ CDEBUG(D_INFO, "can not find snap info for inode %p\n", inode);
+ RETURN(NULL);
+ }
+
+ table = snap_info->sni_table;
+
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);
+ cache_inode = sops->fs_get_indirect(I2CI(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_CREATE] smfs_cow_create,
- [REINT_LINK] smfs_cow_link,
- [REINT_UNLINK] smfs_cow_unlink,
- [REINT_RENAME] smfs_cow_rename,
- [REINT_WRITE] smfs_cow_write,
+
+static int smfs_cow_readdir_pre(struct inode *dir, void *de, void *data1,
+ void *data2)
+{
+ struct file *filp = (struct file*)de;
+ void *dirent = data1;
+ filldir_t filldir = (filldir_t)data2;
+ struct snap_info *snap_info = NULL;
+
+ if (smfs_under_dotsnap_inode(dir))
+ RETURN(0);
+
+ snap_info = smfs_find_snap_info(dir);
+
+ if (!snap_info) {
+ CDEBUG(D_INFO, "can not find snap info for ino %lu\n",
+ dir->i_ino);
+ RETURN(-EINVAL);
+ }
+
+ if (smfs_primary_inode(dir)) {
+ if (filp->f_pos == 0) {
+ struct snap_dot_info *dot = snap_info->sni_dot_info;
+ if (filldir(dirent, dot->dot_name, dot->dot_name_len,
+ filp->f_pos, -1, 0)) {
+ CERROR("fill .snap error \n");
+ RETURN(-EINVAL);
+ }
+ } else {
+ filp->f_pos -= 1;
+ }
+ } else if (smfs_dotsnap_inode(dir)) {
+ struct snap_table *table = snap_info->sni_table;
+ int i = 0;
+
+ if (filp->f_pos < 0)
+ RETURN(-EINVAL);
+
+ if ((filp->f_pos == 0) && filldir(dirent, ".", 1,
+ filp->f_pos++,
+ dir->i_ino, 0) < 0)
+ RETURN(-EIO);
+ if ((filp->f_pos == 1) && filldir(dirent, "..", 2,
+ filp->f_pos++,
+ dir->i_ino, 0) < 0)
+ RETURN(-EIO);
+
+ for (i = filp->f_pos - 2; i < table->sntbl_count; i++,
+ filp->f_pos++) {
+ int slot = table->sntbl_count - i - 1;
+
+ if (filldir(dirent, table->sntbl_items[slot].sn_name,
+ strlen(table->sntbl_items[slot].sn_name),
+ filp->f_pos, dir->i_ino, 0))
+ break;
+
+ }
+ RETURN(1);
+ }
+
+ RETURN(0);
+}
+
+
+typedef int (*cow_funcs)(struct inode *dir, void *dentry, void *new_dir,
+ void *new_dentry);
+
+static cow_funcs smfs_cow_pre_funcs[HOOK_MAX + 1] = {
+ [HOOK_CREATE] smfs_cow_create_pre,
+ [HOOK_LOOKUP] smfs_cow_lookup_pre,
+ [HOOK_LINK] smfs_cow_link_pre,
+ [HOOK_UNLINK] smfs_cow_unlink_pre,
+ [HOOK_SYMLINK] smfs_cow_create_pre,
+ [HOOK_MKDIR] smfs_cow_create_pre,
+ [HOOK_RMDIR] smfs_cow_unlink_pre,
+ [HOOK_MKNOD] smfs_cow_create_pre,
+ [HOOK_RENAME] smfs_cow_rename_pre,
+ [HOOK_SETATTR] smfs_cow_setattr_pre,
+ [HOOK_WRITE] smfs_cow_write_pre,
+ [HOOK_READDIR] smfs_cow_readdir_pre,
+};
+
+static int smfs_revalidate_dotsnap_dentry(struct dentry *dentry,
+ struct inode *dir, int index)
+{
+ struct inode *inode = dentry->d_inode;
+ ENTRY;
+
+ if (!inode)
+ RETURN(0);
+
+ if (index > 0 && index != DOT_SNAP_INDEX) {
+ struct fsfilt_operations *sops = I2SNAPCOPS(inode);
+ struct inode *cache_ind = NULL;
+
+ cache_ind = sops->fs_get_indirect(I2CI(inode), NULL, index);
+
+ if (cache_ind) {
+ struct inode *ind_inode = NULL;
+
+ LASSERT(cache_ind->i_ino != I2CI(inode)->i_ino);
+
+ ind_inode = smfs_get_inode(inode->i_sb, cache_ind->i_ino,
+ dir, index);
+ list_del_init(&dentry->d_alias);
+ iput(inode);
+ d_instantiate(dentry, ind_inode);
+ iput(cache_ind);
+ }
+ }
+ RETURN(0);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int
+smfs_revalidate_nd(struct dentry *de, struct nameidata *nd)
+{
+ struct inode *inode = de->d_inode;
+ ENTRY;
+
+ if (!inode)
+ RETURN(0);
+
+ if (smfs_under_dotsnap_inode(inode)) {
+ struct inode *dir = de->d_parent->d_inode;
+ int index = I2SNAPI(inode)->sn_index;
+
+ smfs_revalidate_dotsnap_dentry(de, dir, index);
+ smfs_init_snap_inode_info(de->d_inode, dir, index);
+ }
+
+ RETURN(0);
+}
+#else
+static int
+smfs_revalidate_it(struct dentry *de, int flags,
+ struct nameidata *nd,
+ struct lookup_intent *it)
+{
+ struct inode *inode = de->d_inode;
+ ENTRY;
+
+ if (!inode)
+ RETURN(0);
+
+ if (smfs_under_dotsnap_inode(inode)) {
+ struct inode *dir = de->d_parent->d_inode;
+ int index = I2SNAPI(inode)->sn_index;
+
+ smfs_revalidate_dotsnap_dentry(de, dir, index);
+ smfs_init_snap_inode_info(de->d_inode, dir, index);
+ }
+
+ RETURN(0);
+}
+#endif
+
+static int smfs_delete_dentry(struct dentry *dentry)
+{
+ dentry->d_op = NULL;
+ return 0;
+}
+
+struct dentry_operations smfs_cow_dops = {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+ .d_revalidate = smfs_revalidate_nd,
+#else
+ .d_revalidate_it = smfs_revalidate_it,
+#endif
+ .d_delete = smfs_delete_dentry,
};
-int smfs_cow(struct inode *dir, struct dentry *dentry, void *new_dir,
- void *new_dentry, int op)
+int smfs_cow_lookup_post(struct inode *dir, void *de, void *data1,
+ void *data2)
{
- return smfs_cow_funcs[op](dir, dentry, new_dir, new_dentry);
+ struct dentry *dentry = (struct dentry*)de;
+ struct inode *inode = dentry->d_inode;
+ ENTRY;
+
+ if (inode && smfs_under_dotsnap_inode(inode)) {
+ int index = I2SNAPI(dir)->sn_index;
+
+ smfs_revalidate_dotsnap_dentry(dentry, dir, index);
+ smfs_init_snap_inode_info(inode, dir, index);
+ }
+ dentry->d_op = &smfs_cow_dops;
+ RETURN(0);
+}
+
+static int smfs_cow_readdir_post(struct inode *dir, void *de, void *data1,
+ void *data2)
+{
+ struct file *filp = (struct file*)de;
+
+ if (smfs_primary_inode(dir)) {
+ filp->f_pos += 1;
+ }
+ RETURN(0);
+}
+
+
+static cow_funcs smfs_cow_post_funcs[HOOK_MAX + 1] = {
+ [HOOK_CREATE] NULL,
+ [HOOK_LOOKUP] smfs_cow_lookup_post,
+ [HOOK_LINK] NULL,
+ [HOOK_UNLINK] NULL,
+ [HOOK_SYMLINK] NULL,
+ [HOOK_MKDIR] NULL,
+ [HOOK_RMDIR] NULL,
+ [HOOK_MKNOD] NULL,
+ [HOOK_RENAME] NULL,
+ [HOOK_SETATTR] NULL,
+ [HOOK_WRITE] NULL,
+ [HOOK_READDIR] smfs_cow_readdir_post,
+};
+
+static int smfs_cow_pre(struct inode *dir, void *dentry, void *new_dir,
+ void *new_dentry, int op)
+{
+ if (smfs_cow_pre_funcs[op]) {
+ return smfs_cow_pre_funcs[op](dir, dentry, new_dir, new_dentry);
+ }
+ return 0;
+}
+
+static int smfs_cow_post(struct inode *dir, void *dentry, void *new_dir,
+ void *new_dentry, int op)
+{
+ if (smfs_cow_post_funcs[op]) {
+ return smfs_cow_post_funcs[op](dir, dentry, new_dir, new_dentry);
+ }
+ return 0;
}