move primary cowed inode to cowed dir.
2)move MSG_CONNECT_INITIAL check before obd_uuid equal check, otherwise,
it will bring some problems in cmobd_setup.
3)set imp_conn_cnt to 0 in ptlrpc_disconnect_import
#define SM_OVER_WRITE 0x8
#define SM_DIRTY_WRITE 0x10
#define SM_DO_COW 0x20
+#define SM_DO_COWED 0x40
#define SMFS_DO_REC(smfs_info) (smfs_info->smsi_flags & SM_DO_REC)
#define SMFS_SET_REC(smfs_info) (smfs_info->smsi_flags |= SM_DO_REC)
#define SMFS_DO_INODE_COW(inode) (I2SMI(inode)->smi_flags & SM_DO_COW)
#define SMFS_CLEAN_INODE_COW(inode) (I2SMI(inode)->smi_flags &= ~SM_DO_COW)
+#define SMFS_SET_INODE_COWED(inode) (I2SMI(inode)->smi_flags |= SM_DO_COWED)
+#define SMFS_DO_INODE_COWED(inode) (I2SMI(inode)->smi_flags & SM_DO_COWED)
+#define SMFS_CLEAN_INODE_COWED(inode) (I2SMI(inode)->smi_flags &= ~SM_DO_COWED)
+
+
#define LVFS_SMFS_BACK_ATTR "lvfs_back_attr"
int smfs_cow(struct inode *dir, struct dentry *dentry, int op);
+extern int smfs_post_setup(struct super_block *sb, struct vfsmount *mnt);
+extern int smfs_post_cleanup(struct super_block *sb);
#endif /* _LUSTRE_SMFS_H */
struct semaphore sntbl_sema;
spinlock_t sntbl_lock;
struct snap_table *sntbl;
+ struct dentry *sn_cowed_dentry;
};
extern int smfs_add_snap_item(struct super_block *sb, char *name);
+extern int smfs_start_cow(struct super_block *sb);
+extern int smfs_stop_cow(struct super_block *sb);
#endif /*_LUSTRE_SNAP_H*/
rc = lustre_pack_reply(req, 0, NULL, NULL);
if (rc)
GOTO(out, rc);
-
+
+ if (lustre_msg_get_op_flags(req->rq_reqmsg) & MSG_CONNECT_INITIAL)
+ initial_conn = 1;
+
/* lctl gets a backstage, all-access pass. */
if (obd_uuid_equals(&cluuid, &target->obd_uuid))
goto dont_check_exports;
- if (lustre_msg_get_op_flags(req->rq_reqmsg) & MSG_CONNECT_INITIAL)
- initial_conn = 1;
-
spin_lock(&target->obd_dev_lock);
list_for_each(p, &target->obd_exports) {
export = list_entry(p, struct obd_export, exp_obd_chain);
if (mnt) {
sb = mnt->mnt_sb;
S2SMI(sb)->smsi_exp = obd->obd_self_export;
+ smfs_post_setup(sb, mnt);
if (SMFS_DO_REC(S2SMI(sb)))
rc = smfs_start_rec(sb, mnt);
+#ifdef CONFIG_SNAPFS
+ if (SMFS_DO_COW(S2SMI(sb)))
+ rc = smfs_start_cow(sb);
+#endif
if (rc)
GOTO(exit, rc);
if (obd)
sb = mnt->mnt_sb;
if (SMFS_DO_REC(S2SMI(sb)))
rc = smfs_stop_rec(sb);
+#ifdef CONFIG_SNAPFS
+ if (SMFS_DO_COW(S2SMI(sb)))
+ rc = smfs_stop_cow(sb);
+#endif
+ smfs_post_cleanup(sb);
}
RETURN(rc);
}
dst->i_size = dst->u.ext3_i.i_disksize = src->i_size;
RETURN(handle);
}
-
+/*Here delete the data of that pri inode
+ *FIXME later, should throw the blocks of
+ *primary inode directly
+ */
+static int ext3_throw_inode_data(handle_t *handle, struct inode *inode)
+{
+ struct inode *tmp = NULL;
+ ENTRY;
+
+ tmp = ext3_new_inode(handle, inode, (int)inode->i_mode, 0);
+ if(tmp) {
+ CERROR("ext3_new_inode error\n");
+ RETURN(-EIO);
+ }
+ double_down(&inode->i_sem, &tmp->i_sem);
+ ext3_migrate_data(handle, tmp, inode);
+ double_up(&inode->i_sem, &tmp->i_sem);
+ tmp->i_nlink = 0;
+ iput(tmp);
+ RETURN(0);
+}
/**
* fsfilt_ext3_create_indirect - copy data, attributes from primary to new indir inode
* @pri: primary (source) inode
* we just free the primary data blocks and mark this inode delete
*/
if((del) && ind && !IS_ERR(ind)) {
- struct inode *tmp;
/* for directory, we don't free the data blocks,
* or ext3_rmdir will report errors "bad dir, no data blocks"
*/
CDEBUG(D_INODE, "del==SNAP_DEL_PRI_WITH_IND && ind\n");
if(!S_ISDIR(pri->i_mode)) {
- /*Here delete the data of that pri inode.
- * FIXME later, should throw the blocks of
- * primary inode directly
- */
- tmp = ext3_new_inode(handle, pri, (int)pri->i_mode, 0);
- if(tmp) {
- down(&tmp->i_sem);
- ext3_migrate_data(handle, tmp, pri);
- up(&tmp->i_sem);
- tmp->i_nlink = 0;
- iput(tmp);
- } else {
- CERROR("ext3_new_inode error\n");
- GOTO(exit, err=-EIO);
- }
- pri->i_nlink = 1;
+ err = ext3_throw_inode_data(handle, pri);
+ if (err)
+ GOTO(exit, err);
+ pri->i_nlink = 1;
}
pri->u.ext3_i.i_dtime = CURRENT_TIME;
ext3_mark_inode_dirty(handle, pri);
static int fsfilt_ext3_restore_indirect(struct inode *pri, int index)
{
struct inode *ind;
- struct inode *tmp;
int err = 0;
handle_t *handle = NULL;
ENTRY;
if( !handle )
RETURN(-EINVAL);
/* first destroy all the data blocks in primary inode */
- /* XXX: check this, ext3_new_inode, the first arg should be "dir" */
- tmp = ext3_new_inode(handle, pri, (int)pri->i_mode, 0);
- if(tmp){
- double_down(&pri->i_sem, &tmp->i_sem);
- ext3_migrate_data(handle, tmp, pri);
- double_up(&pri->i_sem, &tmp->i_sem);
-
- tmp->i_nlink = 0;
- iput(tmp);
- } else
+ /* XXX: check this, ext3_new_inode, the first arg should be "dir" */
+ err = ext3_throw_inode_data(handle, pri);
+ if (err) {
CERROR("restore_indirect, new_inode err\n");
-
+ RETURN(err);
+ }
double_down(&pri->i_sem, &ind->i_sem);
ext3_migrate_data(handle, pri, ind);
pri->u.ext3_i.i_flags &= ~EXT3_COW_FL;
out:
IMPORT_SET_STATE_NOLOCK(imp, LUSTRE_IMP_CLOSED);
memset(&imp->imp_remote_handle, 0, sizeof(imp->imp_remote_handle));
+ memset(&imp->imp_conn_cnt, 0, sizeof(imp->imp_conn_cnt));
spin_unlock_irqrestore(&imp->imp_lock, flags);
RETURN(rc);
RETURN(-ENOSPC);
SMFS_CACHE_HOOK_PRE(CACHE_HOOK_LINK, handle, dir, rc);
-
+
+ lock_kernel();
+
+ SMFS_PRE_COW(dir, old_dentry, REINT_LINK, "link", rc, exit);
+
cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry);
cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry);
- lock_kernel();
if (!cache_parent || !cache_dentry)
GOTO(exit, rc = -ENOMEM);
SMFS_CACHE_HOOK_PRE(CACHE_HOOK_UNLINK, handle, dir, rc);
+ SMFS_PRE_COW(dir, dentry, REINT_UNLINK, "unlink", rc, exit);
+
cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry);
cache_dentry = pre_smfs_dentry(cache_parent, cache_inode, dentry);
}
EXPORT_SYMBOL(smfs_start_rec);
+int smfs_post_setup(struct super_block *sb, struct vfsmount *mnt)
+{
+ struct lvfs_run_ctxt *current_ctxt = NULL;
+ struct smfs_super_info *smb = S2SMI(sb);
+
+ OBD_ALLOC(current_ctxt, sizeof(*current_ctxt));
+ if (!current_ctxt)
+ RETURN(-ENOMEM);
+ OBD_SET_CTXT_MAGIC(current_ctxt);
+
+ current_ctxt->pwdmnt = mnt;
+ current_ctxt->pwd = mnt->mnt_root;
+ current_ctxt->fs = get_ds();
+ smb->smsi_ctxt = current_ctxt;
+
+ RETURN(0);
+}
+EXPORT_SYMBOL(smfs_post_setup);
+
+int smfs_post_cleanup(struct super_block *sb)
+{
+ struct smfs_super_info *smb = S2SMI(sb);
+
+ ENTRY;
+
+ if (smb->smsi_ctxt)
+ OBD_FREE(S2SMI(sb)->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
+ RETURN(0);
+}
+EXPORT_SYMBOL(smfs_post_cleanup);
+
int smfs_stop_rec(struct super_block *sb)
{
int rc = 0;
}
RETURN(rc);
}
-
-int smfs_cow_init(struct super_block *sb)
+#define COWED_NAME_LEN (7 + 8 + 1)
+static int smfs_init_cowed_dir(struct super_block *sb, struct dentry* cowed_dir)
+{
+ struct snap_info *snap_info = S2SNAPI(sb);
+ struct dentry *dentry = NULL;
+ struct lvfs_run_ctxt saved;
+ char name[COWED_NAME_LEN];
+ 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);
+ }
+ snap_info->sn_cowed_dentry = dentry;
+ RETURN(rc);
+}
+int smfs_start_cow(struct super_block *sb)
{
struct smfs_super_info *smfs_info = S2SMI(sb);
- struct inode *inode = sb->s_root->d_inode;
int rc = 0;
- SMFS_SET_COW(smfs_info);
-
+ ENTRY;
OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_info));
if (!smfs_info->smsi_snap_info)
}
}
rc = smfs_init_snaptabe(sb);
-
+ if (rc) {
+ CERROR("can not init snaptable rc=%d\n", rc);
+ RETURN(rc);
+ }
+ /*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);
}
-
-int smfs_cow_cleanup(struct super_block *sb)
+EXPORT_SYMBOL(smfs_start_cow);
+int smfs_stop_cow(struct super_block *sb)
{
- struct smfs_super_info *smfs_info = S2SMI(sb);
struct snap_info *snap_info = S2SNAPI(sb);
struct snap_table *snap_table = snap_info->sntbl;
int rc = 0, table_size;
ENTRY;
- SMFS_CLEAN_COW(smfs_info);
-
+ l_dput(snap_info->sn_cowed_dentry);
+
if (snap_info->snap_fsfilt)
fsfilt_put_ops(snap_info->snap_fsfilt);
if (snap_info->snap_cache_fsfilt)
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;
+
+ SMFS_SET_COW(smfs_info);
+
+ RETURN(rc);
+}
+
+int smfs_cow_cleanup(struct super_block *sb)
+{
+ ENTRY;
+ SMFS_CLEAN_COW(S2SMI(sb));
+ RETURN(0);
+}
/*FIXME Note indirect and primary inode
* should be recorgnized here*/
RETURN(index);
} /* snap_needs_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;
+ 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);
+
+ down(&cowed_dir->d_inode->i_sem);
+ dchild = ll_lookup_one_len(fidname, cowed_dir, fidlen);
+ if (IS_ERR(dchild)) {
+ rc = PTR_ERR(dchild);
+ if (rc != -EPERM && rc != -EACCES)
+ CERROR("child lookup error %d\n", rc);
+ GOTO(out_lock, rc);
+ }
+ if (dchild->d_inode != NULL) {
+ CERROR("re-cowed file %s?\n", dchild->d_name.name);
+ LASSERT(dchild->d_inode == inode);
+ GOTO(out_dput, rc = 0);
+ }
+ tmp = pre_smfs_dentry(NULL, inode, cowed_dir);
+ /* link() is semanticaly-wrong for S_IFDIR, so we set S_IFREG
+ * 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);
+ post_smfs_dentry(tmp);
+ if (rc) {
+ CERROR("error linking cowed inode %s to COWED: rc = %d\n",
+ fidname, 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(dchild->d_inode);
+out_dput:
+ dput(dchild);
+out_lock:
+ up(&cowed_dir->d_inode->i_sem);
+ RETURN(rc);
+}
/*
* Make a copy of the data and plug a redirector in between if there
* is no redirector yet.
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);
+ }
+
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)
{
int rc = 0;
+ struct dentry *dparent;
ENTRY;
if (smfs_needs_cow(dir) != -1) {
CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
- if ((snap_do_cow(dir, dentry->d_parent, 0))) {
+ 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);
}
{
int rc = 0;
ENTRY;
-
+ if (smfs_needs_cow(dir) != -1) {
+ CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino);
+ if ((snap_do_cow(dir, dentry->d_parent, 0))) {
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
+ }
RETURN(rc);
}
int smfs_cow_link(struct inode *dir, struct dentry *dentry)
{
int rc = 0;
+ struct dentry *dparent;
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");
+ RETURN(-EINVAL);
+ }
+ if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 0))) {
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
+ }
RETURN(rc);
}
int smfs_cow_unlink(struct inode *dir, struct dentry *dentry)
{
+ struct dentry *dparent;
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");
+ RETURN(-EINVAL);
+ }
+ if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 1))) {
+ CERROR("Do cow error\n");
+ RETURN(-EINVAL);
+ }
+ }
RETURN(rc);
}
extern int cleanup_smfs(void);
extern void smfs_put_super(struct super_block *sb);
extern struct super_block *smfs_get_sb_by_path(char *path, int len);
-extern struct vfsmount* get_vfsmount(struct super_block *sb);
/*sysctl.c*/
extern int sm_debug_level;
extern int sm_inodes;
{
struct llog_ctxt **ctxt = &(S2SMI(sb)->smsi_rec_log);
struct lvfs_run_ctxt saved;
- struct lvfs_run_ctxt *current_ctxt = NULL;
- struct vfsmount *get_mnt = mnt;
struct dentry *dentry;
int rc = 0, rc2;
/* create OBJECTS and LOGS for writing logs */
+ ENTRY;
- OBD_ALLOC(current_ctxt, sizeof(*current_ctxt));
- if (!current_ctxt)
- RETURN(-ENOMEM);
- if (!get_mnt) {
- get_mnt = get_vfsmount(sb);
- if (!get_mnt) {
- OBD_FREE(current_ctxt, sizeof(*current_ctxt));
- RETURN(-EINVAL);
- }
- }
- OBD_SET_CTXT_MAGIC(current_ctxt);
-
- current_ctxt->pwdmnt = get_mnt;
- current_ctxt->pwd = get_mnt->mnt_root;
- current_ctxt->fs = get_ds();
- S2SMI(sb)->smsi_ctxt = current_ctxt;
-
- push_ctxt(&saved, current_ctxt, NULL);
+ LASSERT(mnt);
+
+ push_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
dentry = simple_mkdir(current->fs->pwd, "LOGS", 0777, 1);
if (IS_ERR(dentry)) {
rc = PTR_ERR(dentry);
SMFS_CLEAN_INODE_CACHE_HOOK(S2SMI(sb)->smsi_logs_dir->d_inode);
if (SMFS_DO_REC(S2SMI(sb))) {
-
rc = llog_catalog_setup(ctxt, KML_LOG_NAME, S2SMI(sb)->smsi_exp,
- current_ctxt, S2SMI(sb)->sm_fsfilt,
+ S2SMI(sb)->smsi_ctxt, S2SMI(sb)->sm_fsfilt,
S2SMI(sb)->smsi_logs_dir,
S2SMI(sb)->smsi_objects_dir);
(*ctxt)->llog_proc_cb = smfs_llog_process_rec_cb;
rc = rc2;
}
exit:
- pop_ctxt(&saved, current_ctxt, NULL);
- if (current_ctxt && rc)
- OBD_FREE(current_ctxt, sizeof(*current_ctxt));
+ pop_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
RETURN(rc);
}
l_dput(S2SMI(sb)->smsi_objects_dir);
S2SMI(sb)->smsi_objects_dir = NULL;
}
-
- OBD_FREE(S2SMI(sb)->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
RETURN(rc);
}
return pos;
}
-struct vfsmount *get_vfsmount(struct super_block *sb)
-{
- struct vfsmount *rootmnt, *mnt, *ret = NULL;
- struct list_head *end, *list;
-
- rootmnt = mntget(current->fs->rootmnt);
- end = list = &rootmnt->mnt_list;
- do {
- mnt = list_entry(list, struct vfsmount, mnt_list);
- if (mnt->mnt_sb == sb) {
- ret = mnt;
- break;
- }
- list = list->next;
- } while (end != list);
-
- mntput(current->fs->rootmnt);
- return ret;
-}
-
struct super_block *smfs_get_sb_by_path(char *path, int len)
{
struct super_block *sb;
static int sm_mount_cache(struct super_block *sb, char *devstr,
char *typestr, char *opts, int iopen_nopriv)
{
- struct smfs_super_info *smb;
+ struct smfs_super_info *smb = S2SMI(sb);
int err = 0, typelen;
struct vfsmount *mnt;
unsigned long page;
CERROR("do_kern_mount failed: rc = %ld\n", PTR_ERR(mnt));
GOTO(err_out, err = PTR_ERR(mnt));
}
- smb = S2SMI(sb);
+
smb->smsi_sb = mnt->mnt_sb;
smb->smsi_mnt = mnt;
duplicate_sb(sb, mnt->mnt_sb);
sm_set_sb_ops(mnt->mnt_sb, sb);
+
err = smfs_init_fsfilt_ops(sb);
err_out:
return err;
if (smb->smsi_cache_ftype)
OBD_FREE(smb->smsi_cache_ftype,
strlen(smb->smsi_cache_ftype) + 1);
-
if (smb->smsi_ftype)
OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
-
+
return 0;
}