#include "smfs_internal.h"
-#define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + \
- size * sizeof(struct snap))
+#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;
ENTRY;
- OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_super_info));
+ OBD_ALLOC(smfs_info->smsi_snap_info,
+ sizeof(struct snap_super_info));
+
if (!smfs_info->smsi_snap_info)
GOTO(exit, rc = -ENOMEM);
RETURN(NULL);
}
+#if 0
static int smfs_dotsnap_dir_size(struct inode *inode)
{
struct snap_super_info *snap_sinfo = S2SNAPI(inode->i_sb);
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;
RETURN(-EIO);
}
/*init dot_snap inode info*/
- inode->i_size = (loff_t)smfs_dotsnap_dir_size(inode);
+// 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;
}
#define COWED_NAME_LEN (7 + 8 + 1)
-static int smfs_init_cowed_dir(struct snap_info *snap_info, struct dentry* dir)
+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)dir->d_inode->i_ino);
+ sprintf(name, ".cowed_%08x", (__u32)inode->i_ino);
/*FIXME-WANGDI: will use simple_mkdir, when integrating snap to lustre*/
- dentry = smfs_simple_mkdir(dir, name, 0777, 1);
+ 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_snap_info(struct smfs_super_info *smb,
- struct snap_info *snap_info, struct dentry *de)
+ struct snap_info *snap_info, struct inode *inode)
{
struct snap_table *snap_table = NULL;
struct fsfilt_operations *snapcops;
int rc = 0, size, table_size, vallen, i;
- struct inode *root_inode = NULL;
ENTRY;
- root_inode = iget(smb->smsi_sb, de->d_inode->i_ino);
- if (!root_inode || is_bad_inode(root_inode))
- RETURN(-EIO);
snapcops = smb->smsi_snap_info->snap_cache_fsfilt;
/*Initialized table */
/*get the maxsize of snaptable*/
vallen = sizeof(int);
- rc = snapcops->fs_get_snap_info(root_inode, MAX_SNAPTABLE_COUNT,
+ rc = snapcops->fs_get_snap_info(I2CI(inode), MAX_SNAPTABLE_COUNT,
strlen(MAX_SNAPTABLE_COUNT), &size,
&vallen);
if (size == 0) {
for (i = 0; i < snap_table->sntbl_max_count; i++)
snap_table->sntbl_items[i].sn_index = -1;
/*get snaptable info*/
- rc = snapcops->fs_get_snap_info(root_inode, SNAPTABLE_INFO,
+ rc = snapcops->fs_get_snap_info(I2CI(inode), SNAPTABLE_INFO,
strlen(SNAPTABLE_INFO),
snap_table, &table_size);
if (rc < 0) {
if (rc == -ENODATA) {
snap_table->sntbl_count = 0;
+ rc = 0;
} else {
CERROR("Can not retrive the snaptable from this filesystem\n");
GOTO(exit, rc);
}
}
init_MUTEX(&snap_info->sni_sema);
- snap_info->sni_root_ino = de->d_inode->i_ino;
- rc = smfs_init_cowed_dir(snap_info, de);
+ 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 (root_inode)
- iput(root_inode);
if (rc && snap_table)
OBD_FREE(snap_table, table_size);
RETURN(rc);
}
static struct snap_info *smfs_create_snap_info(struct smfs_super_info *sinfo,
- struct dentry *dentry)
+ struct inode *inode)
{
struct snap_info *snap_info = NULL;
int rc = 0;
OBD_ALLOC(snap_info, sizeof(struct snap_info));
if (!snap_info)
RETURN(ERR_PTR(-ENOMEM));
- rc = smfs_init_snap_info(sinfo, snap_info, dentry);
+ rc = smfs_init_snap_info(sinfo, snap_info, inode);
if (rc)
- GOTO(exit, snap_info = ERR_PTR(rc));
+ GOTO(exit, rc);
/*set cow flags for the snap root inode*/
- I2SMI(dentry->d_inode)->smi_flags |= SM_DO_COW;
- I2SNAPI(dentry->d_inode)->sn_root_ino = dentry->d_inode->i_ino;
+ I2SMI(inode)->smi_flags |= SM_DO_COW;
+ I2SNAPI(inode)->sn_root_ino = inode->i_ino;
exit:
- if (rc)
+ if (rc) {
OBD_FREE(snap_info, sizeof(struct snap_info));
+ snap_info = ERR_PTR(rc);
+ }
RETURN(snap_info);
}
-static int smfs_cow_pre(struct inode *dir, struct dentry *dentry, void *new_dir,
+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, struct dentry *dentry, void *new_dir,
+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, struct dentry *dentry,
- void *data1, void *data2, int op, void *handle)
+static int smfs_cow_pre_hook(struct inode *inode, void *dentry, void *data1,
+ void *data2, int op, void *handle)
{
int rc = 0;
ENTRY;
}
RETURN(rc);
}
-static int smfs_cow_post_hook(struct inode *inode, struct dentry *dentry,
- void *data1, void *data2, int op, void *handle)
+static int smfs_cow_post_hook(struct inode *inode, void *dentry, void *data1,
+ void *data2, int op, void *handle)
{
int rc = 0;
ENTRY;
RETURN(rc);
}
+int smfs_cow_cleanup(struct smfs_super_info *smb)
+{
+ 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;
+
+ 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_sinfo->snap_fsfilt)
+ fsfilt_put_ops(snap_sinfo->snap_fsfilt);
+ if (snap_sinfo->snap_cache_fsfilt)
+ fsfilt_put_ops(snap_sinfo->snap_cache_fsfilt);
+
+ 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);
+}
+
int smfs_cow_init(struct super_block *sb)
{
struct smfs_super_info *smfs_info = S2SMI(sb);
vallen = sizeof(int);
rc = sops->fs_get_snap_info(root_inode, SNAP_COUNT, strlen(SNAP_COUNT),
&snap_count, &vallen);
- if (rc)
+ if (rc < 0)
GOTO(exit, rc);
if (snap_count > 0) {
rc = sops->fs_get_snap_info(root_inode, SNAP_ROOT_INO,
strlen(SNAP_ROOT_INO), snap_root,
&snap_root_size);
- if (rc) {
+ 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 dentry *tmp = smfs_info->smsi_sb->s_root;
struct snap_info *snap_info;
- struct dentry *dentry;
root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
smfs_init_snap_inode_info(root_inode, NULL, 0);
- dentry = pre_smfs_dentry(NULL, root_inode, tmp);
- snap_info = smfs_create_snap_info(S2SMI(sb), dentry);
- post_smfs_dentry(dentry);
+ 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);
}
ENTRY;
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);
RETURN(rc);
}
-int smfs_cow_cleanup(struct smfs_super_info *smb)
-{
- 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;
-
- 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_sinfo->snap_fsfilt)
- fsfilt_put_ops(snap_sinfo->snap_fsfilt);
- if (snap_sinfo->snap_cache_fsfilt)
- fsfilt_put_ops(snap_sinfo->snap_cache_fsfilt);
-
- 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);
-}
-
int smfs_snap_test_inode(struct inode *inode, void *args)
{
struct smfs_iget_args *sargs = (struct smfs_iget_args*)args;
}
}
- 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) {
{
struct dentry *dentry = NULL;
struct nameidata nd;
+ int error;
ENTRY;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
/* Wrote the whole snap_table to disk */
table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
+ 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->sni_sema);
if (root_inode)
}
static struct snap_info * smfs_find_create_snap_info(struct super_block *sb,
- struct dentry *dentry)
+ 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 == dentry->d_inode->i_ino) {
+ if (snap_info->sni_root_ino == inode->i_ino) {
RETURN(snap_info);
}
}
- CDEBUG(D_INFO, "create a new snap info root ino %lu\n",
- dentry->d_inode->i_ino);
+ CDEBUG(D_INFO, "create a new snap info root ino %lu\n", inode->i_ino);
- snap_info = smfs_create_snap_info(S2SMI(sb), dentry);
+ 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);
}
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);
+ 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));
static int link_cowed_inode(struct inode *inode)
{
struct dentry *cowed_dir = NULL;
- char fidname[LL_FID_NAMELEN];
+ char idname[LL_ID_NAMELEN];
struct snap_info *snap_info;
- int fidlen = 0, rc = 0;
+ int idlen = 0, rc = 0;
struct dentry *dchild = NULL;
struct dentry *tmp = NULL;
unsigned mode;
cowed_dir = snap_info->sni_cowed_dentry;
- fidlen = ll_fid2str(fidname, inode->i_ino, inode->i_generation);
-
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);
}
/*
PTR_ERR(cache_ind));
RETURN(PTR_ERR(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);
+ 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);
+ }
}
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) {
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 dentry *dentry = (struct dentry*)de;
struct snap_info *snap_info = NULL;
struct snap_table *table;
long blocks[2]={-1,-1};
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)
break;
}
}
- if (index != -1) {
+ 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(0);
}
-int smfs_cow_lookup(struct inode *inode, struct dentry *dentry, void *data1,
- void *data2)
+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, index = 0;
+ int rc = 0;
ENTRY;
snap_info = smfs_find_snap_info(inode);
dot_info = snap_info->sni_dot_info;
- LASSERT(dot_info != NULL);
- LASSERT(data1 != NULL);
-
- index = *(int *)data1;
-
if (smfs_primary_inode(inode) &&
dentry->d_name.len == dot_info->dot_name_len &&
memcmp(dentry->d_name.name, dot_info->dot_name,
d_add(dentry, dot_inode);
rc = 1;
RETURN(rc);
- }
- if (smfs_dotsnap_inode(inode)) {
+ } else if (smfs_dotsnap_inode(inode)) {
rc = smfs_dotsnap_lookup(inode, dentry, snap_info);
if (rc == 0)
rc = 1;
RETURN(rc);
- }
- if (index > 0) {
- /*HERE: will replace ino in dentry->d_name according to index*/
+ } 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;
hash = partial_name_hash(c, hash);
}
dentry->d_name.hash = end_name_hash(hash);
- }
+#endif
+ }
RETURN(rc);
}
}
EXPORT_SYMBOL(smfs_cow_get_ind);
-typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry,
- void *new_dir, void *new_dentry);
+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,
- [HOOK_LOOKUP] smfs_cow_lookup,
- [HOOK_LINK] smfs_cow_link,
- [HOOK_UNLINK] smfs_cow_unlink,
- [HOOK_SYMLINK] smfs_cow_create,
- [HOOK_MKDIR] smfs_cow_create,
- [HOOK_RMDIR] smfs_cow_unlink,
- [HOOK_MKNOD] smfs_cow_create,
- [HOOK_RENAME] smfs_cow_rename,
- [HOOK_SETATTR] smfs_cow_setattr,
- [HOOK_WRITE] smfs_cow_write,
+ [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,
};
-int smfs_cow_lookup_post(struct inode *dir, struct dentry *dentry, void *data1,
- void *data2)
+
+static int smfs_revalidate_dotsnap_dentry(struct dentry *dentry,
+ struct inode *dir, int index)
{
- struct inode *inode = dentry->d_inode;
- struct fsfilt_operations *sops = I2SNAPCOPS(inode);
- int index = I2SNAPI(dir)->sn_index;
- ENTRY;
+ struct inode *inode = dentry->d_inode;
+ ENTRY;
+
+ if (!inode)
+ RETURN(0);
- LASSERT(inode);
-
- if (index > 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->i_ino != I2CI(inode)->i_ino) {
+
+ if (cache_ind) {
struct inode *ind_inode = NULL;
+
+ LASSERT(cache_ind->i_ino != I2CI(inode)->i_ino);
- ind_inode = smfs_get_inode(dir->i_sb, cache_ind->i_ino,
+ ind_inode = smfs_get_inode(inode->i_sb, cache_ind->i_ino,
dir, index);
- /*replace the ind_inode here*/
list_del_init(&dentry->d_alias);
iput(inode);
- d_instantiate(dentry, ind_inode);
+ d_instantiate(dentry, ind_inode);
+ iput(cache_ind);
}
}
- inode = dentry->d_inode;
+ 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;
+}
- smfs_init_snap_inode_info(inode, dir, index);
+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_lookup_post(struct inode *dir, void *de, void *data1,
+ void *data2)
+{
+ 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_RENAME] NULL,
[HOOK_SETATTR] NULL,
[HOOK_WRITE] NULL,
+ [HOOK_READDIR] smfs_cow_readdir_post,
};
-static int smfs_cow_pre(struct inode *dir, struct dentry *dentry, void *new_dir,
+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 0;
}
-static int smfs_cow_post(struct inode *dir, struct dentry *dentry, void *new_dir,
+static int smfs_cow_post(struct inode *dir, void *dentry, void *new_dir,
void *new_dentry, int op)
{
if (smfs_cow_post_funcs[op]) {