Whamcloud - gitweb
- landing b_fid.
[fs/lustre-release.git] / lustre / smfs / kml.c
index 0658283..ecac5fe 100644 (file)
@@ -1,6 +1,9 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
+ *  lustre/smfs/kml.c
+ *  Lustre filesystem abstraction routines
+ *
  *  Copyright (C) 2004 Cluster File Systems, Inc.
  *
  *   This file is part of Lustre, http://www.lustre.org.
  *   You should have received a copy of the GNU General Public License
  *   along with Lustre; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
  */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
 
 #define DEBUG_SUBSYSTEM S_SM
 
 #include <linux/lustre_smfs.h>
 #include "smfs_internal.h"
 
-/*FIXME there should be more conditions in this check*/
-int smfs_do_rec(struct inode *inode)
+#define KML_BUF_REC_INIT(buffer, pbuf, len)     \
+do {                                            \
+        pbuf = buffer + sizeof(int);            \
+        len -= sizeof(int);                     \
+} while (0)
+        
+#define KML_BUF_REC_END(buffer, length, pbuf)   \
+do {                                            \
+        int len = length;                       \
+        memcpy(buffer, &len, sizeof(len));      \
+        length += sizeof(int);                  \
+        pbuf = buffer + length;                 \
+} while (0)
+
+static smfs_pack_rec_func smfs_get_rec_pack_type(struct super_block *sb)
 {
-        struct super_block *sb = inode->i_sb;
-        struct smfs_super_info *smfs_info = S2SMI(sb);
+        int idx = 0;
+        struct smfs_super_info *smsi = S2SMI(sb);
 
-        if (SMFS_DO_REC(smfs_info) && SMFS_INIT_REC(smfs_info) &&
-            SMFS_DO_INODE_REC(inode))
-                return 1;
-        return 0;
+        idx = GET_REC_PACK_TYPE_INDEX(smsi->smsi_flags);
+        return smsi->smsi_pack_rec[idx];
 }
 
-int smfs_rec_init(struct super_block *sb)
+static int smfs_post_kml_rec(struct inode *dir, void *de, void *data1, 
+                             void *data2, int op);
+
+static int smfs_rec_post_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;
 
-        SMFS_SET_REC(smfs_info);
-
+        if (smfs_do_rec(inode))                                  
+                rc = smfs_post_kml_rec(inode, dentry, data1, data2, op);  
+        
         RETURN(rc);
 }
 
-int smfs_rec_cleanup(struct super_block *sb)
+#define KML_HOOK "kml_hook"
+
+int smfs_rec_init(struct super_block *sb)
 {
         int rc = 0;
+        struct smfs_super_info *smfs_info = S2SMI(sb);
+        struct smfs_hook_ops   *rec_hops = NULL;
+        ENTRY;
+
+        SMFS_SET_REC(smfs_info);
+
+        rc = ost_rec_pack_init(smfs_info);
+        if (rc)
+                return rc;
+        
+        rc = mds_rec_pack_init(smfs_info);
+        if (rc)
+                return rc;
 
-        SMFS_CLEAN_REC(S2SMI(sb));
+        rec_hops = smfs_alloc_hook_ops(KML_HOOK, NULL, smfs_rec_post_hook);
+        if (!rec_hops) {
+                RETURN(-ENOMEM);
+        }
+        rc = smfs_register_hook_ops(smfs_info, rec_hops);
+        if (rc && rec_hops) {
+                smfs_unregister_hook_ops(smfs_info, rec_hops->smh_name);
+                smfs_free_hook_ops(rec_hops);
+        } 
         RETURN(rc);
 }
 
-void reint_rec_free(struct reint_record *reint_rec)
+int smfs_rec_cleanup(struct smfs_super_info *smfs_info)
 {
-        if (reint_rec) {
-                if (reint_rec->rec_data1)
-                        OBD_FREE(reint_rec->rec_data1,
-                                 reint_rec->rec1_size + 1);
-                if (reint_rec->rec_data2)
-                        OBD_FREE(reint_rec->rec_data2,
-                                 reint_rec->rec2_size + 1);
-
-                OBD_FREE(reint_rec, sizeof(struct reint_record));
-        }
+        struct smfs_hook_ops *rec_hops; 
+        int rc = 0;
+        ENTRY;
+
+        rec_hops = smfs_unregister_hook_ops(smfs_info, KML_HOOK);
+        smfs_free_hook_ops(rec_hops);
+        SMFS_CLEAN_REC(smfs_info);
+        
+        RETURN(rc);
 }
 
-static inline void copy_inode_attr(struct iattr *iattr, struct inode *inode)
+static inline void
+copy_inode_attr(struct iattr *iattr, struct inode *inode)
 {
         iattr->ia_mode = inode->i_mode;
         iattr->ia_uid  = inode->i_uid;
@@ -89,39 +133,6 @@ static inline void copy_inode_attr(struct iattr *iattr, struct inode *inode)
         iattr->ia_size = inode->i_size;
 }
 
-void smfs_rec_pack(struct update_record *rec, struct inode *dst,
-                   void *data, int op)
-{
-        rec->ur_fsuid = current->fsuid;
-        rec->ur_fsgid = current->fsgid;
-        rec->ur_rdev = dst->i_rdev;
-        rec->ur_opcode = op;
-        copy_inode_attr(&rec->ur_iattr, dst);
-        if (data) {
-                switch (op) {
-                case REINT_CREATE:
-                case REINT_LINK:
-                case REINT_UNLINK:
-                case REINT_RENAME: {
-                        struct inode *dir = (struct inode *)data;
-                        copy_inode_attr(&rec->ur_pattr, dir);
-                        break;
-                }
-                case REINT_SETATTR: {
-                        struct iattr *attr = (struct iattr *)data;
-                        memcpy(&rec->ur_pattr, attr, sizeof(struct iattr));
-                        break;
-                }
-                }
-        }
-}
-
-static inline void unpack_attr(struct reint_record *r_rec,
-                               struct update_record *u_rec)
-{
-        memcpy(&r_rec->u_rec, u_rec, sizeof(struct update_record));
-}
-
 static inline int unpack_rec_data(char **p_buffer, int *size,
                                   char *in_data, char *args_data)
 {
@@ -138,11 +149,12 @@ static inline int unpack_rec_data(char **p_buffer, int *size,
         OBD_ALLOC(*p_buffer, *size + args_len + 1);
         if (!*p_buffer)
                 RETURN(-ENOMEM);
-        /*First copy reint dir */
+
+        /* first copy reint dir. */
         if (args_data)
                 memcpy(*p_buffer, args_data, args_len);
 
-        /*then copy the node name */
+        /* then copy the node name. */
         memcpy(*p_buffer + args_len,
                       (in_data + sizeof(int)), *size);
 
@@ -151,59 +163,19 @@ static inline int unpack_rec_data(char **p_buffer, int *size,
         RETURN(rc);
 }
 
-int smfs_rec_unpack(struct smfs_proc_args *args, struct reint_record *r_rec,
-                    char *rec_buf)
+int smfs_rec_unpack(struct smfs_proc_args *args, char *record, 
+                    char **pbuf, int *opcode)
 {
-        struct update_record *u_rec = (struct update_record *)rec_buf;
-        int rc = 0, length = 0;
-        ENTRY;
-        /*FIXME wangdi, there unpack are so smiliar that
-          *we will put it together later*/
-
-        if (SMFS_DO_WRITE_KML(args->sr_flags))
-                SET_REC_WRITE_KML_FLAGS(r_rec->u_rec.ur_flags, SMFS_WRITE_KML);
-        unpack_attr(r_rec, u_rec);
-        length += sizeof(struct update_record);
-        rc = unpack_rec_data(&r_rec->rec_data1, &r_rec->rec1_size,
-                             (rec_buf + length), args->sr_data);
-        switch (u_rec->ur_opcode) {
-        case REINT_OPEN:
-        case REINT_CLOSE:
-                /*record src path which will be passed to reint and undo*/
-                rc = unpack_rec_data(&r_rec->rec_data2, &r_rec->rec2_size,
-                                     (rec_buf + length), NULL);
-                break;
-        case REINT_LINK:
-        case REINT_RENAME:
-        case REINT_SETATTR:
-        case REINT_UNLINK:
-        case REINT_CREATE:
-        case REINT_WRITE: {
-                length += rc;
-                if (length < u_rec->ur_len) {
-                        char *pre_name;
-                        if (u_rec->ur_opcode == REINT_CREATE ||
-                            u_rec->ur_opcode == REINT_WRITE ||
-                            (u_rec->ur_opcode == REINT_UNLINK &&
-                             SMFS_DO_DEC_LINK(r_rec->u_rec.ur_flags)))
-                                pre_name = NULL;
-                        else
-                                pre_name = args->sr_data;
-
-                        rc = unpack_rec_data(&r_rec->rec_data2,
-                                             &r_rec->rec2_size,
-                                             (rec_buf + length), pre_name);
-                }
-                break;
-        }
-        }
-        if (rc > 0)
-                rc = 0;
+        int offset = *(int *)(record);
+        char *tmp = record + offset + sizeof(int);
 
-        RETURN(rc);
+        *opcode = *(int *)tmp;
+        *pbuf = tmp + sizeof(*opcode);
+        return 0;
 }
+EXPORT_SYMBOL(smfs_rec_unpack);
 
-int smfs_start_rec(struct super_block *sb)
+int smfs_start_rec(struct super_block *sb, struct vfsmount *mnt)
 {
         struct dentry *dentry;
         struct lvfs_run_ctxt saved;
@@ -213,28 +185,21 @@ int smfs_start_rec(struct super_block *sb)
         if (SMFS_INIT_REC(S2SMI(sb)) ||
             (!SMFS_DO_REC(S2SMI(sb)) && !SMFS_CACHE_HOOK(S2SMI(sb))))
                 RETURN(rc);
-
-        rc = smfs_llog_setup(sb);
+        
+        rc = smfs_llog_setup(sb, mnt);
         if (rc)
-                RETURN(rc);
-
+                RETURN(rc); 
         push_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
         dentry = simple_mkdir(current->fs->pwd, "DELETE", 0777, 1);
         if (IS_ERR(dentry)) {
                 rc = PTR_ERR(dentry);
-                CERROR("cannot create LOGS directory: rc = %d\n", rc);
+                CERROR("cannot create DELETE directory: rc = %d\n", rc);
                 GOTO(err_exit, rc = -EINVAL);
         }
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-        if (list_empty(&dentry->d_hash))
-                d_rehash(dentry);
-#else
-        /* FIXME-WANGDI: here should be be something. */
-#endif
+        S2SMI(sb)->smsi_delete_dir = dentry;
 
         if (!rc)
                 SMFS_SET_INIT_REC(S2SMI(sb));
-        S2SMI(sb)->smsi_delete_dir = dentry;
 exit:
         pop_ctxt(&saved, S2SMI(sb)->smsi_ctxt, NULL);
         RETURN(rc);
@@ -243,6 +208,38 @@ err_exit:
                 OBD_FREE(S2SMI(sb)->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
         goto exit;
 }
+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);
+        ENTRY;
+        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)
 {
@@ -263,8 +260,57 @@ int smfs_stop_rec(struct super_block *sb)
         }
         RETURN(rc);
 }
+EXPORT_SYMBOL(smfs_stop_rec);
+
+int smfs_write_extents(struct inode *dir, struct dentry *dentry,
+                       unsigned long from, unsigned long num)
+{
+        return smfs_post_rec_write(dir, dentry, &from, &num);
+}
+EXPORT_SYMBOL(smfs_write_extents);
+
+int smfs_rec_setattr(struct inode *dir, struct dentry *dentry,
+                     struct iattr *attr)
+{
+        return smfs_post_rec_setattr(dir, dentry, attr, NULL);
+}
+EXPORT_SYMBOL(smfs_rec_setattr);
 
-int smfs_process_rec(struct super_block *sb, int count, char *dir, int flags)
+int smfs_rec_md(struct inode *inode, void *lmm, int lmm_size)
+{
+        char *set_lmm = NULL;
+        int  rc = 0;
+        ENTRY;
+
+        if (!SMFS_DO_REC(S2SMI(inode->i_sb)))
+                RETURN(0);
+
+        if (lmm) {
+                OBD_ALLOC(set_lmm, lmm_size + sizeof(lmm_size));
+                if (!set_lmm)
+                        RETURN(-ENOMEM);
+                memcpy(set_lmm, &lmm_size, sizeof(lmm_size));
+                memcpy(set_lmm + sizeof(lmm_size), lmm, lmm_size);
+                rc = smfs_post_rec_setattr(inode, NULL, NULL, set_lmm);
+                if (rc) {
+                        CERROR("Error: Record md for inode %lu rc=%d\n",
+                                inode->i_ino, rc);
+                }
+        }
+        if (set_lmm)
+                OBD_FREE(set_lmm, lmm_size + sizeof(lmm_size));
+        RETURN(rc);
+}
+EXPORT_SYMBOL(smfs_rec_md);
+
+int smfs_rec_precreate(struct dentry *dentry, int *num, struct obdo *oa)
+{
+       return smfs_post_rec_create(dentry->d_inode, dentry, num, oa);
+}
+EXPORT_SYMBOL(smfs_rec_precreate);
+
+int smfs_process_rec(struct super_block *sb,
+                     int count, char *dir, int flags)
 {
         struct llog_ctxt *ctxt;
         struct llog_handle *loghandle;
@@ -289,17 +335,16 @@ int smfs_process_rec(struct super_block *sb, int count, char *dir, int flags)
                 if (SMFS_DO_REINT_REC(flags)) {
                         struct llog_gen_rec *lgr;
 
-                        /*For reint rec, we need insert
-                          *a gen rec to identify the end
-                          *of the rec.*/
+                        /* for reint rec, we need insert a gen rec to identify
+                         * the end of the rec.*/
                         OBD_ALLOC(lgr, sizeof(*lgr));
                         if (!lgr)
                                 RETURN(-ENOMEM);
-                        lgr->lgr_hdr.lrh_len = lgr->lgr_tail.lrt_len =
-                                sizeof(*lgr);
+                        lgr->lgr_hdr.lrh_len = lgr->lgr_tail.lrt_len = sizeof(*lgr);
                         lgr->lgr_hdr.lrh_type = LLOG_GEN_REC;
                         lgr->lgr_gen = ctxt->loc_gen;
-                        rc = llog_add(ctxt, &lgr->lgr_hdr, NULL, NULL, 1, NULL);
+                        rc = llog_add(ctxt, &lgr->lgr_hdr, NULL, NULL, 1,
+                                      NULL, NULL, NULL);
                         OBD_FREE(lgr, sizeof(*lgr));
                         if (rc != 1)
                                 RETURN(rc);
@@ -309,14 +354,486 @@ int smfs_process_rec(struct super_block *sb, int count, char *dir, int flags)
         }
         if (loghandle) {
                 if (SMFS_DO_REINT_REC(flags))
-                        rc = llog_cat_process(loghandle, ctxt->loc_proc_cb,
+                        rc = llog_cat_process(loghandle, ctxt->llog_proc_cb,
                                               (void *)&args);
                 else
                         rc = llog_cat_reverse_process(loghandle,
-                                                      ctxt->loc_proc_cb,
+                                                      ctxt->llog_proc_cb,
                                                       (void *)&args);
                 if (rc == LLOG_PROC_BREAK)
                         rc = 0;
         }
         RETURN(rc);
 }
+
+/*smfs_path is gotten from intermezzo*/
+static char* smfs_path(struct dentry *dentry, struct dentry *root, char *buffer,
+                       int buflen)
+{
+        char * end = buffer + buflen;
+        char * name = buffer;
+        char * buf_end = buffer + buflen;
+        char * retval;
+
+        *--end = '\0';
+        buflen--;
+        /* Get '/' right */
+        retval = end-1;
+        *retval = '/';
+
+        for (;;) {
+                struct dentry * parent;
+                int namelen;
+
+                if (dentry == root)
+                        break;
+                parent = dentry->d_parent;
+                if (dentry == parent)
+                        break;
+                namelen = dentry->d_name.len;
+                buflen -= namelen + 1;
+                if (buflen < 0)
+                        break;
+                end -= namelen;
+                memcpy(end, dentry->d_name.name, namelen);
+                *--end = '/';
+                retval = end;
+                dentry = parent;
+        }
+        
+        while (end != buf_end) 
+                *name++ = *end++;
+        *name = '\0'; 
+        return retval;
+}
+
+static int smfs_log_path(struct super_block *sb, 
+                         struct dentry *dentry, 
+                         char   *buffer,
+                         int    buffer_len)
+{
+        struct dentry *root=sb->s_root;
+        char *p_name = buffer + sizeof(int);
+        char *name = NULL;
+        int namelen = 0;
+        ENTRY;
+
+        if (dentry) {
+                name = smfs_path(dentry, root, p_name, buffer_len - sizeof(int));
+                namelen = cpu_to_le32(strlen(p_name));
+                memcpy(buffer, &namelen, sizeof(int));        
+        }
+        namelen += sizeof(int);
+        RETURN(namelen);
+}
+
+static inline int log_it(char *buffer, void *data, int length)
+{
+        memcpy(buffer, &length, sizeof(int));
+        memcpy(buffer + sizeof(int), data, length);
+        return (sizeof(int) + length);                 
+}
+
+static int smfs_pack_rec (char *buffer, struct dentry *dentry, 
+                          struct inode *dir, void *data1, 
+                          void *data2, int op)
+{ 
+        smfs_pack_rec_func pack_func;        
+
+        pack_func = smfs_get_rec_pack_type(dir->i_sb);
+        if (!pack_func)
+                return 0;
+        return pack_func(buffer, dentry, dir, data1, data2, op);
+}
+
+int smfs_post_rec_create(struct inode *dir, struct dentry *dentry,
+                         void *data1, void *data2)
+{
+        struct smfs_super_info *sinfo;
+        char   *buffer = NULL, *pbuf;
+        int rc = 0, length = 0, buf_len = 0;
+        ENTRY;
+        
+        sinfo = S2SMI(dentry->d_inode->i_sb);
+        if (!sinfo)
+                RETURN(-EINVAL);
+        
+        OBD_ALLOC(buffer, PAGE_SIZE);
+        if (!buffer)
+                GOTO(exit, rc = -ENOMEM);        
+
+        buf_len = PAGE_SIZE;
+        KML_BUF_REC_INIT(buffer, pbuf, buf_len);
+        rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
+        if (rc < 0)
+                GOTO(exit, rc);
+        length = rc;
+        KML_BUF_REC_END(buffer, length, pbuf);   
+       
+        rc = smfs_pack_rec(pbuf, dentry, dir, 
+                           data1, data2, REINT_CREATE);
+        if (rc <= 0)
+                GOTO(exit, rc);
+        else
+                length += rc;
+        rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
+exit:
+        if (buffer)
+                OBD_FREE(buffer, PAGE_SIZE);        
+        
+        RETURN(rc);
+}
+
+static int smfs_post_rec_link(struct inode *dir, struct dentry *dentry, 
+                              void *data1, void *data2)
+{
+        struct dentry *new_dentry = (struct dentry *)data1;
+        int rc = 0, length = 0, buf_len = 0;
+        char *buffer = NULL, *pbuf = NULL;
+        struct smfs_super_info *sinfo;
+        ENTRY;
+        
+        sinfo = S2SMI(dir->i_sb);
+        if (!sinfo)
+                RETURN(-EINVAL);
+        OBD_ALLOC(buffer, PAGE_SIZE);
+        if (!buffer)
+                GOTO(exit, rc = -ENOMEM);
+        
+        buf_len = PAGE_SIZE;
+        KML_BUF_REC_INIT(buffer, pbuf, buf_len);
+        
+        rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
+        if (rc < 0)
+                GOTO(exit, rc);
+        
+        length = rc;
+        KML_BUF_REC_END(buffer, length, pbuf);  
+        
+        rc = smfs_pack_rec(pbuf, dentry, dir, dentry, 
+                           new_dentry, REINT_LINK);
+        if (rc <= 0)
+                GOTO(exit, rc);
+        
+        length += rc;
+        rc = smfs_llog_add_rec(sinfo, (void *)buffer, length); 
+exit:
+        if (buffer)
+                OBD_FREE(buffer, PAGE_SIZE);        
+        
+        RETURN(rc);
+}
+
+static int smfs_post_rec_unlink(struct inode *dir, struct dentry *dentry,
+                                void *data1, void *data2)
+{
+        struct smfs_super_info *sinfo;
+        int mode = *((int*)data1);
+        char   *buffer = NULL, *pbuf = NULL;
+        int  length = 0, rc = 0, buf_len = 0;
+        ENTRY;
+         
+        sinfo = S2SMI(dentry->d_inode->i_sb);
+        if (!sinfo)
+                RETURN(-EINVAL);
+        
+        OBD_ALLOC(buffer, PAGE_SIZE);
+        if (!buffer)
+                GOTO(exit, rc = -ENOMEM);        
+      
+        buf_len = PAGE_SIZE;
+        KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
+        rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
+        if (rc < 0)
+                GOTO(exit, rc);
+
+        length = rc;
+        KML_BUF_REC_END(buffer, length, pbuf);
+        rc = smfs_pack_rec(pbuf, dentry, dir, 
+                           &mode, NULL, REINT_UNLINK);
+        if (rc <= 0)
+                GOTO(exit, rc);
+        else
+                length += rc;         
+        
+        rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
+exit:
+        if (buffer)
+                OBD_FREE(buffer, PAGE_SIZE);        
+        
+        RETURN(rc);
+}
+
+static int smfs_post_rec_rename(struct inode *dir, struct dentry *dentry, 
+                                void *data1, void *data2)
+{
+        struct smfs_super_info *sinfo;
+        struct inode *new_dir = (struct inode *)data1;
+        struct dentry *new_dentry = (struct dentry *)data2;
+        char *buffer = NULL, *pbuf = NULL;
+        int rc = 0, length = 0, buf_len = 0;
+        ENTRY;
+        
+        sinfo = S2SMI(dir->i_sb);
+        if (!sinfo)
+                RETURN(-EINVAL);
+
+        OBD_ALLOC(buffer, PAGE_SIZE);
+        if (!buffer)
+                GOTO(exit, rc = -ENOMEM);
+        
+        buf_len = PAGE_SIZE;
+        KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
+        rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
+        if (rc < 0)
+                GOTO(exit, rc);
+
+        pbuf += rc; 
+        length += rc;
+        buf_len -= rc;
+        
+        /* record new_dentry path. */
+        rc = smfs_log_path(dir->i_sb, new_dentry, pbuf, buf_len);
+        if (rc < 0)
+                GOTO(exit, rc);
+
+        length += rc;
+        KML_BUF_REC_END(buffer, length, pbuf);
+               
+        rc = smfs_pack_rec(pbuf, dentry, dir, 
+                           new_dir, new_dentry, REINT_RENAME);
+        if (rc <= 0) 
+                GOTO(exit, rc);
+        length += rc;
+        
+        rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
+exit:
+        if (buffer)
+                OBD_FREE(buffer, PAGE_SIZE);
+        RETURN(rc);
+}
+
+static int smfs_insert_extents_ea(struct inode *inode, size_t from, loff_t num)
+{
+        struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
+        int rc = 0;
+        ENTRY;
+        
+        if (SMFS_INODE_OVER_WRITE(inode))
+                RETURN(rc);
+        
+        rc = fsfilt->fs_insert_extents_ea(inode, OFF2BLKS(from, inode), 
+                                          SIZE2BLKS(num, inode));        
+        RETURN(rc);
+}
+
+static int smfs_remove_extents_ea(struct inode *inode, size_t from, loff_t num)
+{
+        struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
+        int rc = 0;
+        ENTRY;
+        
+        rc = fsfilt->fs_remove_extents_ea(inode, OFF2BLKS(from, inode), 
+                                          SIZE2BLKS(num, inode));        
+        
+        RETURN(rc);
+}
+
+static int smfs_remove_all_extents_ea(struct inode *inode)
+{
+        struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
+        int rc = 0;
+        ENTRY;
+        
+        rc = fsfilt->fs_remove_extents_ea(inode, 0, 0xffffffff);        
+        RETURN(rc);
+}
+static int  smfs_init_extents_ea(struct inode *inode)
+{
+        struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
+        int rc = 0;
+        ENTRY;
+        
+        rc = fsfilt->fs_init_extents_ea(inode);        
+        
+        RETURN(rc);
+}
+static int smfs_set_dirty_flags(struct inode *inode, int flags)
+{
+        struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
+        void   *handle;
+        int    rc = 0;
+        ENTRY;
+
+        if (SMFS_INODE_OVER_WRITE(inode))
+                RETURN(rc);
+        /*FIXME later, the blocks needed in journal here will be recalculated*/
+         handle = smfs_trans_start(inode, FSFILT_OP_SETATTR, NULL);
+        if (IS_ERR(handle)) {
+                CERROR("smfs_set_dirty_flag:no space for transaction\n");
+                RETURN(-ENOSPC);
+        }
+        if ((!SMFS_INODE_DIRTY_WRITE(inode) && (!SMFS_INODE_OVER_WRITE(inode))) || 
+             ((flags == SMFS_OVER_WRITE) && (SMFS_INODE_DIRTY_WRITE(inode)))) {        
+                rc = fsfilt->fs_set_xattr(inode, handle, REINT_EXTENTS_FLAGS,
+                                            &flags, sizeof(int));
+                if (rc)
+                        GOTO(out, rc);
+        }
+        if (flags == SMFS_OVER_WRITE)
+                SMFS_SET_INODE_OVER_WRITE(inode);
+        else
+                SMFS_SET_INODE_DIRTY_WRITE(inode);
+out:
+        smfs_trans_commit(inode, handle, 0);
+        RETURN(rc);
+}
+
+int smfs_post_rec_setattr(struct inode *inode, struct dentry *dentry, 
+                          void  *data1, void  *data2)
+{        
+        struct smfs_super_info *sinfo;
+        struct iattr *attr = (struct iattr *)data1;
+        char   *buffer = NULL, *pbuf;
+        int rc = 0, length = 0, buf_len = 0;
+        ENTRY;
+
+        sinfo = S2SMI(inode->i_sb);
+        if (!sinfo)
+                RETURN(-EINVAL);
+        
+        OBD_ALLOC(buffer, PAGE_SIZE);
+        if (!buffer)
+                GOTO(exit, rc = -ENOMEM);        
+
+        buf_len = PAGE_SIZE;
+        KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
+        rc = smfs_log_path(inode->i_sb, dentry, pbuf, buf_len);
+        if (rc < 0)
+                GOTO(exit, rc);
+        
+        length = rc;
+        KML_BUF_REC_END(buffer, length, pbuf);
+        
+        rc = smfs_pack_rec(pbuf, dentry, inode, 
+                           data1, data2, REINT_SETATTR);
+        if (rc <= 0) 
+                GOTO(exit, rc);
+        else
+                length += rc;
+
+        rc = smfs_llog_add_rec(sinfo, (void*)buffer, length); 
+        if (!rc) {
+                if (attr && attr->ia_valid & ATTR_SIZE) {
+                        smfs_remove_extents_ea(inode, attr->ia_size,
+                                               0xffffffff);                                
+                        if (attr->ia_size == 0)
+                                smfs_set_dirty_flags(inode, SMFS_OVER_WRITE);
+                        else
+                                smfs_set_dirty_flags(inode, SMFS_DIRTY_WRITE);
+                }
+        }
+exit:
+        if (buffer)
+                OBD_FREE(buffer, PAGE_SIZE);        
+        RETURN(rc);
+}
+static int all_blocks_present_ea(struct inode *inode)
+{
+        int rc = 0;
+        ENTRY;
+        RETURN(rc);        
+}
+
+int smfs_post_rec_write(struct inode *dir, struct dentry *dentry, void *data1, 
+                        void *data2)
+{
+        struct smfs_super_info *sinfo;
+        char   *buffer = NULL, *pbuf;
+        int rc = 0, length = 0, buf_len = 0;
+        ENTRY;
+        
+        if (!SMFS_INODE_OVER_WRITE(dentry->d_inode) && 
+            !SMFS_INODE_DIRTY_WRITE(dentry->d_inode)) {
+                sinfo = S2SMI(dentry->d_inode->i_sb);
+                if (!sinfo)
+                        RETURN(-EINVAL);
+                
+                OBD_ALLOC(buffer, PAGE_SIZE);
+                if (!buffer)
+                        GOTO(exit, rc = -ENOMEM);        
+                
+                buf_len = PAGE_SIZE;
+                KML_BUF_REC_INIT(buffer, pbuf, buf_len);        
+                rc = smfs_log_path(dir->i_sb, dentry, pbuf, buf_len);
+                
+                if (rc < 0)
+                        GOTO(exit, rc);
+                pbuf += rc;
+                memcpy(buffer, &rc, sizeof(int));        
+                length = rc + sizeof(int);
+                        
+                rc = smfs_pack_rec(pbuf, dentry, dir, 
+                                   data1, data2, REINT_WRITE);
+                if (rc <= 0) 
+                        GOTO(exit, rc);
+                else
+                        length += rc;
+                rc = smfs_llog_add_rec(sinfo, (void*)buffer, length);
+                if (rc)
+                        GOTO(exit, rc);
+                rc = smfs_init_extents_ea(dentry->d_inode);
+                if (rc)
+                        GOTO(exit, rc);
+        } 
+        if (dentry->d_inode->i_size == 0) {
+                smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);        
+        } else {
+                /*insert extent EA*/
+                loff_t off = *((loff_t*)data1);        
+                size_t count = *((size_t*)data2);
+                
+                rc = smfs_insert_extents_ea(dentry->d_inode, off, count);        
+                if (rc < 0)  
+                        GOTO(exit, rc);        
+                if (all_blocks_present_ea(dentry->d_inode)){
+                        smfs_set_dirty_flags(dentry->d_inode, SMFS_OVER_WRITE);        
+                        smfs_remove_all_extents_ea(dentry->d_inode);
+                } else {
+                        smfs_set_dirty_flags(dentry->d_inode, SMFS_DIRTY_WRITE);        
+                }
+        }
+exit:
+        if (buffer)
+                OBD_FREE(buffer, PAGE_SIZE);
+        RETURN(rc);
+}
+
+typedef int (*post_kml_rec)(struct inode *dir, struct dentry *dentry,
+                           void *data1, void *data2);
+
+static post_kml_rec smfs_kml_post[HOOK_MAX + 1] = {
+        [HOOK_CREATE]  smfs_post_rec_create,
+        [HOOK_LOOKUP]  NULL,
+        [HOOK_LINK]    smfs_post_rec_link,
+        [HOOK_UNLINK]  smfs_post_rec_unlink,
+        [HOOK_SYMLINK] smfs_post_rec_create,
+        [HOOK_MKDIR]   smfs_post_rec_create,
+        [HOOK_RMDIR]   smfs_post_rec_unlink,
+        [HOOK_MKNOD]   smfs_post_rec_create,
+        [HOOK_RENAME]  smfs_post_rec_rename,
+        [HOOK_SETATTR] smfs_post_rec_setattr,
+        [HOOK_WRITE]   smfs_post_rec_write,
+        [HOOK_READDIR] NULL,
+};
+static int smfs_post_kml_rec(struct inode *dir, void *de, void *data1, 
+                             void *data2, int op)
+{
+        if (smfs_kml_post[op]) {
+                struct dentry *dentry = (struct dentry *)de;
+                return smfs_kml_post[op](dir, dentry, data1, data2);
+        }
+        return 0;
+}