Whamcloud - gitweb
Branch b1_4
[fs/lustre-release.git] / lustre / lvfs / fsfilt_snap_ext3.c
index fdb3ec5..a4accc7 100644 (file)
 #include <linux/ext3_fs.h>
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_extents.h>
-#include <linux/locks.h>
 #include <linux/version.h>
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <linux/locks.h>
 #include <linux/ext3_xattr.h>
+#include <linux/module.h>
+#include <linux/iobuf.h>
 #else
 #include <ext3/xattr.h>
 #endif
 
-#include <linux/kp30.h>
+#include <libcfs/kp30.h>
 #include <linux/lustre_fsfilt.h>
 #include <linux/obd.h>
 #include <linux/obd_class.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include <linux/module.h>
-#include <linux/iobuf.h>
-#endif
 #include <linux/lustre_smfs.h>
 #include <linux/lustre_snap.h>
 
 
 #define EXT3_SNAP_ATTR "@snap"
 #define EXT3_SNAP_GENERATION "@snap_generation"
-#define EXT3_MAX_SNAPS 20
+#define EXT3_MAX_SNAPS 10
 #define EXT3_MAX_SNAP_DATA (sizeof(struct snap_ea))
 #define EXT3_SNAP_INDEX EXT3_XATTR_INDEX_LUSTRE
+#define EXT3_SNAP_COUNT "@snapcount"
+#define EXT3_SNAP_ROOT_INO "@snap_rootino"
 
-#define SB_SNAPTABLE_INO(sb)   (EXT3_SB(sb)->s_es->s_snaptable_ino)
 #define SB_FEATURE_COMPAT(sb)  (EXT3_SB(sb)->s_es->s_feature_compat)
                                                                                                                                                                                                      
 #define SNAP_HAS_COMPAT_FEATURE(sb,mask)        \
 #define SNAP_EA_INO_BLOCK_SIZE(size)   (((size)-sizeof(ino_t)*2)/2)
 #define SNAP_EA_PARENT_OFFSET(size)    (sizeof(ino_t)*2 + SNAP_EA_INO_BLOCK_SIZE((size)))
 
+#define EXT3_EA_TRANS_BLOCKS            EXT3_DATA_TRANS_BLOCKS
+#define EXT3_SETMETA_TRANS_BLOCKS       EXT3_DATA_TRANS_BLOCKS
+#define EXT3_NEWINODE_TRANS_BLOCKS      10
+
+#define SNAP_COPYBLOCK_TRANS_BLOCKS    (EXT3_DATA_TRANS_BLOCKS)
+#define SNAP_INSERTLIST_TRANS_BLOCKS    (2 * EXT3_EA_TRANS_BLOCKS + 1)
+#define SNAP_DELETELIST_TRANS_BLOCKS    (2 * EXT3_EA_TRANS_BLOCKS + 2)
+#define SNAP_MIGRATEDATA_TRANS_BLOCKS   2
+#define SNAP_SETIND_TRANS_BLOCKS        (SNAP_INSERTLIST_TRANS_BLOCKS + 1)
+#define SNAP_ADDORPHAN_TRANS_BLOCKS     2
+#define SNAP_REMOVEORPHAN_TRANS_BLOCKS  1
+#define SNAP_RESTOREORPHAN_TRANS_BLOCKS (EXT3_EA_TRANS_BLOCKS + \
+                                         SNAP_DELETELIST_TRANS_BLOCKS + \
+                                         EXT3_NEWINODE_TRANS_BLOCKS + \
+                                         2 * SNAP_MIGRATEDATA_TRANS_BLOCKS)
+#define SNAP_BIGCOPY_TRANS_BLOCKS       (2 * EXT3_DATA_TRANS_BLOCKS)
+#define SNAP_CREATEIND_TRANS_BLOCKS     (EXT3_NEWINODE_TRANS_BLOCKS + \
+                                         SNAP_MIGRATEDATA_TRANS_BLOCKS + \
+                                         SNAP_SETIND_TRANS_BLOCKS + \
+                                         SNAP_BIGCOPY_TRANS_BLOCKS + 3)
+#define SNAP_MIGRATEBLK_TRANS_BLOCKS    2
+#define SNAP_DESTROY_TRANS_BLOCKS       (SNAP_DELETELIST_TRANS_BLOCKS + \
+                                         EXT3_EA_TRANS_BLOCKS + 2)
+#define SNAP_RESTORE_TRANS_BLOCKS       (EXT3_NEWINODE_TRANS_BLOCKS + \
+                                         2 * SNAP_MIGRATEDATA_TRANS_BLOCKS + 1)
+
+#define EXT3_JOURNAL_START(sb, handle, blocks, rc)              \
+do {                                                            \
+        journal_t *journal;                                     \
+        journal = EXT3_SB(sb)->s_journal;                       \
+        lock_kernel();                                          \
+        handle = journal_start(journal, blocks);                \
+        unlock_kernel();                                        \
+        if(IS_ERR(handle)) {                                    \
+                CERROR("can't start transaction\n");            \
+                rc = PTR_ERR(handle);                           \
+        } else                                                  \
+                rc = 0;                                         \
+} while(0)
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static inline void double_lock_inode(struct inode *i1, struct inode *i2)
+{
+        if (i1 == i2)
+                down(&i1->i_sem);
+       else
+                double_down(&i1->i_sem, &i2->i_sem);
+}
+static inline void double_unlock_inode(struct inode *i1, struct inode *i2)
+{
+        if (i1 == i2)
+                up(&i1->i_sem);
+        else 
+               double_up(&i1->i_sem, &i2->i_sem);
+}
+#else
+static inline void double_lock_inode(struct inode *i1, struct inode *i2)
+{
+       struct semaphore *s1 = &i1->i_sem;
+       struct semaphore *s2 = &i2->i_sem;
+
+       if (s1 != s2) {
+               if ((unsigned long) s1 < (unsigned long) s2) {
+                       struct semaphore *tmp = s2;
+                       s2 = s1; s1 = tmp;
+               }
+               down(s1);
+       }
+       down(s2);
+}
+
+static inline void double_unlock_inode(struct inode *i1, struct inode *i2)
+{
+       struct semaphore *s1 = &i1->i_sem;
+       struct semaphore *s2 = &i2->i_sem;
+
+       up(s1);
+       if (s1 != s2)
+               up(s2);
+}
+
+#endif
+
 /* helper functions to manipulate field 'parent' in snap_ea */
 static inline int
 set_parent_ino(struct snap_ea *pea, int size, int index, ino_t val)
@@ -119,7 +202,7 @@ static struct inode *fsfilt_ext3_get_indirect(struct inode *primary, int *table,
        struct snap_ea *snaps;
        ino_t ino;
        struct inode *inode = NULL;
-       int rc = 0, index = 0;
+       int rc = 0;
 
         ENTRY;
 
@@ -140,16 +223,14 @@ static struct inode *fsfilt_ext3_get_indirect(struct inode *primary, int *table,
 
        /* if table is NULL and there is a slot */
        if( !table && slot >= 0) {
-               index = slot;
-               ino = le32_to_cpu(snaps->ino[index]);
+               ino = le32_to_cpu(snaps->ino[slot]);
                if(ino) 
                         inode = iget(primary->i_sb, ino);
                GOTO(err_free, rc);
        }
        /* if table is not NULL */
-       while (!inode && slot >= 0 && table) {
-               index = table[slot];
-               ino = le32_to_cpu(snaps->ino[index]);
+       while (!inode && slot >= 0 ) {
+               ino = le32_to_cpu(snaps->ino[slot]);
 
                CDEBUG(D_INODE, "snap inode at slot %d is %lu\n", slot, ino);
                if (!ino) {
@@ -159,7 +240,7 @@ static struct inode *fsfilt_ext3_get_indirect(struct inode *primary, int *table,
                inode = iget(primary->i_sb, ino);
                GOTO(err_free, rc);
        }
-       if( slot == -1 && table ) {
+       if(slot == -1 && table) {
                CDEBUG(D_INODE, "redirector not found, using primary\n");
                inode = iget(primary->i_sb, primary->i_ino);
        }
@@ -173,7 +254,7 @@ static int fsfilt_ext3_set_indirect(struct inode *pri, int index, ino_t ind_ino,
 {
        char buf[EXT3_MAX_SNAP_DATA];
        struct snap_ea *snaps;
-       int err = 0, inlist = 1;
+       int rc = 0, inlist = 1;
        int ea_size;
        handle_t *handle = NULL;
         ENTRY;
@@ -185,9 +266,9 @@ static int fsfilt_ext3_set_indirect(struct inode *pri, int index, ino_t ind_ino,
                RETURN(-EINVAL);
        /* need lock the list before get_attr() to avoid race */
        /* read ea at first */
-       err = ext3_xattr_get(pri, EXT3_SNAP_INDEX ,EXT3_SNAP_ATTR,
+       rc = ext3_xattr_get(pri, EXT3_SNAP_INDEX ,EXT3_SNAP_ATTR,
                                          buf, EXT3_MAX_SNAP_DATA);
-       if (err == -ENODATA || err == -ENOATTR) {
+       if (rc == -ENODATA || rc == -ENODATA) {
                CDEBUG(D_INODE, "no extended attributes - zeroing\n");
                memset(buf, 0, EXT3_MAX_SNAP_DATA);
                /* XXX
@@ -195,27 +276,27 @@ static int fsfilt_ext3_set_indirect(struct inode *pri, int index, ino_t ind_ino,
                 * So take care of snap ea of primary inodes very carefully.
                 * Is it right in snapfs EXT3, check it later?
                 */
-               inlist = 0; 
-       } else if (err < 0 || err > EXT3_MAX_SNAP_DATA) {
-               GOTO(out_unlock, err);
+               inlist = 0;
+                rc = 0; 
+       } else if (rc < 0 || rc > EXT3_MAX_SNAP_DATA) {
+               GOTO(out_unlock, rc);
        }
+        EXT3_JOURNAL_START(pri->i_sb, handle, SNAP_SETIND_TRANS_BLOCKS, rc); 
+        if(rc) 
+               GOTO(out_unlock, rc = PTR_ERR(handle));
        
-       handle = ext3_journal_start(pri, SNAP_SETIND_TRANS_BLOCKS);
-       if(!handle)
-               GOTO(out_unlock, err = PTR_ERR(handle));
-       
-       snaps = (struct snap_ea *)buf;
+        snaps = (struct snap_ea *)buf;
        snaps->ino[index] = cpu_to_le32 (ind_ino);
        ea_size = EXT3_MAX_SNAP_DATA;
 
        set_parent_ino(snaps, ea_size, index, cpu_to_le32(parent_ino));
 
-       err = ext3_xattr_set(handle, pri, EXT3_SNAP_INDEX, EXT3_SNAP_ATTR,
-                                    buf, EXT3_MAX_SNAP_DATA, 0);
+       rc = ext3_xattr_set_handle(handle, pri, EXT3_SNAP_INDEX,EXT3_SNAP_ATTR,
+                                   buf, EXT3_MAX_SNAP_DATA, 0);
        ext3_mark_inode_dirty(handle, pri);
-       ext3_journal_stop(handle, pri);
+       journal_stop(handle);
 out_unlock:
-       return err;
+       RETURN(rc);
 }
 
 static int ext3_set_generation(struct inode *inode, unsigned long gen)
@@ -223,20 +304,20 @@ static int ext3_set_generation(struct inode *inode, unsigned long gen)
         handle_t *handle;
         int err = 0;
         ENTRY;
-                                                                                                                                                                                             
-        handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
-        if( !handle )
-                RETURN(-EINVAL);
-
-        err = ext3_xattr_set(handle, inode, EXT3_SNAP_INDEX, 
-                             EXT3_SNAP_GENERATION,
-                             (char*)&gen, sizeof(int), 0);
+       
+        EXT3_JOURNAL_START(inode->i_sb, handle, EXT3_XATTR_TRANS_BLOCKS, err);
+        if(err)
+                RETURN(err);
+        
+        err = ext3_xattr_set_handle(handle, inode, EXT3_SNAP_INDEX, 
+                                    EXT3_SNAP_GENERATION, (char*)&gen, 
+                                    sizeof(int), 0);
         if (err < 0) {
                 CERROR("ino %lu, set_ext_attr err %d\n", inode->i_ino, err);
                 RETURN(err);
         }
         
-        ext3_journal_stop(handle, inode);
+        journal_stop(handle);
         RETURN(0);
 }
 
@@ -256,14 +337,17 @@ static void ext3_copy_meta(handle_t *handle, struct inode *dst, struct inode *sr
        dst->i_mtime = src->i_mtime;
        dst->i_ctime = src->i_ctime;
 //     dst->i_version = src->i_version;
-       dst->i_attr_flags = src->i_attr_flags;
+       
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+        dst->i_attr_flags = src->i_attr_flags;
+#endif
        dst->i_generation = src->i_generation;
-       dst->u.ext3_i.i_dtime = src->u.ext3_i.i_dtime;
-       dst->u.ext3_i.i_flags = src->u.ext3_i.i_flags | EXT3_COW_FL;
+        EXT3_I(dst)->i_dtime = EXT3_I(src)->i_dtime;
+       EXT3_I(dst)->i_flags = EXT3_I(src)->i_flags | EXT3_COW_FL;
 #ifdef EXT3_FRAGMENTS
-       dst->u.ext3_i.i_faddr = src->u.ext3_i.i_faddr;
-       dst->u.ext3_i.i_frag_no = src->u.ext3_i.i_frag_no;
-       dst->u.ext3_i.i_frag_size = src->u.ext3_i.i_frag_size;
+        EXT3_I(dst)->i_faddr = EXT3_I(src)->i_faddr;
+        EXT3_I(dst)->i_frag_no = EXT3_I(src)->i_frag_no;
+        EXT3_I(dst)->i_frag_size = EXT3_I(src)->i_frag_size;
 #endif
        if ((size = ext3_xattr_list(src, NULL, 0)) > 0) {
                char names[size];
@@ -292,7 +376,6 @@ static void ext3_copy_meta(handle_t *handle, struct inode *dst, struct inode *sr
                        if (attrlen < 0)
                                continue;
                        OBD_ALLOC(buf, attrlen);
-                               break;
                        if (!buf) {
                                 CERROR("No MEM\n");
                                 break;
@@ -300,8 +383,9 @@ static void ext3_copy_meta(handle_t *handle, struct inode *dst, struct inode *sr
                         if (ext3_xattr_get(src, EXT3_SNAP_INDEX,
                                           EXT3_SNAP_ATTR, buf, attrlen) < 0)
                                continue;       
-                       if (ext3_xattr_set(handle, dst, EXT3_SNAP_INDEX,
-                                          EXT3_SNAP_ATTR, buf, attrlen, 0) < 0)
+                       if (ext3_xattr_set_handle(handle, dst, EXT3_SNAP_INDEX,
+                                                 EXT3_SNAP_ATTR, buf, attrlen, 
+                                                  0) < 0)
                                break;
                        OBD_FREE(buf, attrlen);
                        name += namelen + 1; /* skip name and trailing NUL */
@@ -350,7 +434,7 @@ static int ext3_copy_reg_block(struct inode *dst, struct inode *src, int blk)
                 rc = 1;
 dst_page_unlock:
         kunmap(dst_page);
-        UnlockPage(dst_page);
+        unlock_page(dst_page);
         page_cache_release(dst_page);
 src_page_unlock:
         kunmap(src_page);
@@ -362,10 +446,11 @@ static int ext3_copy_dir_block(struct inode *dst, struct inode *src, int blk)
         struct buffer_head *bh_dst = NULL, *bh_src = NULL;
         int rc = 0;
         handle_t *handle = NULL;
-        ENTRY;                                                                                                                                                                                             
-        handle = ext3_journal_start(dst, SNAP_COPYBLOCK_TRANS_BLOCKS);
-        if( !handle )
-                RETURN(-EINVAL);
+        ENTRY;   
+
+        EXT3_JOURNAL_START(dst->i_sb, handle, SNAP_COPYBLOCK_TRANS_BLOCKS, rc);
+        if(rc)
+                RETURN(rc);
                                                                                                                                                                                                      
         bh_src = ext3_bread(handle, src, blk, 0, &rc);
         if (!bh_src) {
@@ -389,7 +474,7 @@ exit_relese:
         if (bh_src) brelse(bh_src);
         if (bh_dst) brelse(bh_dst);
         if (handle)
-                ext3_journal_stop(handle, dst);
+                journal_stop(handle);
         RETURN(rc);
 }
 /* fsfilt_ext3_copy_block - copy one data block from inode @src to @dst.
@@ -430,7 +515,9 @@ static inline int ext3_has_ea(struct inode *inode)
 static void fs_flushinval_pages(handle_t *handle, struct inode* inode)
 {
         if (inode->i_blocks > 0 && inode->i_mapping) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
                 fsync_inode_data_buffers(inode);
+#endif
                 truncate_inode_pages(inode->i_mapping, 0);
         }
 }
@@ -500,6 +587,7 @@ static handle_t * ext3_copy_data(handle_t *handle, struct inode *dst,
 {
        unsigned long blocks, blk, cur_blks;
        int low_credits, save_ref;
+        int err = 0;
         ENTRY;
 
        blocks =(src->i_size + src->i_sb->s_blocksize-1) >>
@@ -527,7 +615,7 @@ static handle_t * ext3_copy_data(handle_t *handle, struct inode *dst,
                                        ext3_orphan_add(handle, dst);
                                        *has_orphan = 1;
                                }
-                               dst->u.ext3_i.i_disksize =
+                               EXT3_I(dst)->i_disksize =
                                        blk * dst->i_sb->s_blocksize;
                                dst->i_blocks = cur_blks;
                                dst->i_mtime = CURRENT_TIME;
@@ -538,17 +626,14 @@ static handle_t * ext3_copy_data(handle_t *handle, struct inode *dst,
                                 */
                                save_ref = handle->h_ref;
                                handle->h_ref = 1;
-                               if( ext3_journal_stop(handle, dst) ){
+                               if(journal_stop(handle) ){
                                        CERROR("fail to stop journal\n");
                                        handle = NULL;
                                        break;
                                }
-                               handle = ext3_journal_start(dst,
-                                               low_credits + needed);
-                               if( !handle ){
-                                       CERROR("fail to restart handle\n");
-                                       break;
-                               }
+                                EXT3_JOURNAL_START(dst->i_sb, handle, 
+                                                   low_credits + needed, err);
+                                if(err) break;
                                handle->h_ref = save_ref;
                        }
                }
@@ -557,7 +642,7 @@ static handle_t * ext3_copy_data(handle_t *handle, struct inode *dst,
                cur_blks += dst->i_sb->s_blocksize / 512;
        }
        
-        dst->i_size = dst->u.ext3_i.i_disksize = src->i_size;
+        dst->i_size = EXT3_I(dst)->i_disksize = src->i_size;
        RETURN(handle);
 }
 /*Here delete the data of that pri inode 
@@ -568,15 +653,14 @@ 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);
+       double_lock_inode(inode, tmp);
         ext3_migrate_data(handle, tmp, inode);
-       double_up(&inode->i_sem, &tmp->i_sem);
+       double_unlock_inode(inode, tmp);
         tmp->i_nlink = 0;
         iput(tmp);     
         RETURN(0);
@@ -603,11 +687,11 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
 {
        struct inode *ind = NULL;
        handle_t *handle = NULL;
-       int err = 0;
+        int err = 0;
        int has_orphan = 0;
         ENTRY;
         
-       if( pri == pri->i_sb->u.ext3_sb.s_journal_inode ){
+       if( pri == EXT3_SB(pri->i_sb)->s_journal_inode ){
                CERROR("TRY TO COW JOUNRAL\n");
                RETURN(ERR_PTR(-EINVAL));
        }
@@ -615,12 +699,11 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
               pri->i_ino, index, del ? "deleting" : "preserve");
 
        ind = fsfilt_ext3_get_indirect(pri, NULL, index);
-
-       handle = ext3_journal_start(pri, SNAP_CREATEIND_TRANS_BLOCKS);
-       if( !handle ) {
-                CERROR("handle not NULL\n");
-               RETURN(ERR_PTR(-EINVAL));
-        }
+        
+        EXT3_JOURNAL_START(pri->i_sb, handle, SNAP_CREATEIND_TRANS_BLOCKS,
+                           err);
+        if(err) 
+                RETURN(ERR_PTR(err));
        /* XXX ? We should pass an err argument to get_indirect and precisely
         * detect the errors, for some errors, we should exit right away.
         */
@@ -639,7 +722,7 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
                                 GOTO(exit, err);
                         pri->i_nlink = 1;
                }
-               pri->u.ext3_i.i_dtime = CURRENT_TIME;
+               EXT3_I(pri)->i_dtime = LTIME_S(CURRENT_TIME);
                ext3_mark_inode_dirty(handle, pri);
                GOTO(exit, err=0);
        }
@@ -653,6 +736,7 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
        
         /* XXX: check this, ext3_new_inode, the first arg should be "dir" */ 
        ind = ext3_new_inode(handle, pri, (int)pri->i_mode, 0);
+
        if (IS_ERR(ind))
                GOTO(exit, err);
        CDEBUG(D_INODE, "got new inode %lu\n", ind->i_ino);
@@ -696,11 +780,11 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
                                GOTO(exit_unlock, err= -EINVAL);
                }
 
-               pri->u.ext3_i.i_flags |= EXT3_DEL_FL;
-               ind->u.ext3_i.i_flags |= EXT3_COW_FL;
+               EXT3_I(pri)->i_flags |= EXT3_DEL_FL;
+               EXT3_I(ind)->i_flags |= EXT3_COW_FL;
                if(S_ISREG(pri->i_mode)) pri->i_nlink = 1;
-               pri->u.ext3_i.i_dtime = CURRENT_TIME;
-               //pri->u.ext3_i.i_generation++;
+               EXT3_I(pri)->i_dtime = LTIME_S(CURRENT_TIME);
+               //EXT3_I(pri)->i_generation++;
                ext3_mark_inode_dirty(handle, pri);
                ext3_mark_inode_dirty(handle, ind);
                up(&ind->i_sem);
@@ -743,8 +827,8 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
                        }
                }
                /* set cow flag for ind */
-               ind->u.ext3_i.i_flags |= EXT3_COW_FL;
-               pri->u.ext3_i.i_flags &= ~EXT3_COW_FL;
+               EXT3_I(ind)->i_flags |= EXT3_COW_FL;
+               EXT3_I(pri)->i_flags &= ~EXT3_COW_FL;
 
                ext3_mark_inode_dirty(handle, pri);
                ext3_mark_inode_dirty(handle, ind);
@@ -758,10 +842,10 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
        if (!EXT3_HAS_COMPAT_FEATURE(pri->i_sb,
                                     EXT3_FEATURE_COMPAT_SNAPFS)) {
                lock_super(pri->i_sb);
-               ext3_journal_get_write_access(handle, pri->i_sb->u.ext3_sb.s_sbh);
-               pri->i_sb->u.ext3_sb.s_es->s_feature_compat |=
+               ext3_journal_get_write_access(handle, EXT3_SB(pri->i_sb)->s_sbh);
+               EXT3_SB(pri->i_sb)->s_es->s_feature_compat |=
                        cpu_to_le32(EXT3_FEATURE_COMPAT_SNAPFS);
-               ext3_journal_dirty_metadata(handle, pri->i_sb->u.ext3_sb.s_sbh);
+               ext3_journal_dirty_metadata(handle, EXT3_SB(pri->i_sb)->s_sbh);
                pri->i_sb->s_dirt = 1;
                unlock_super(pri->i_sb);
        }
@@ -770,7 +854,7 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index,
                       ind->i_ino, ind->i_nlink);
                ext3_orphan_del(handle, ind);
        }
-       ext3_journal_stop(handle, pri);
+       journal_stop(handle);
 
        RETURN(ind);
 
@@ -784,7 +868,7 @@ exit:
                ext3_orphan_del(handle, ind);
        }
        iput(ind);
-       ext3_journal_stop(handle, pri);
+       journal_stop(handle);
         
         RETURN(ERR_PTR(err));
 }
@@ -797,24 +881,20 @@ static int fsfilt_ext3_snap_feature (struct super_block *sb, int feature, int op
        
        switch (op) {
                 case SNAP_SET_FEATURE:
-                        handle = ext3_journal_start(sb->s_root->d_inode, 1);
-                        lock_super(sb);
-                        ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh);
-                        SB_FEATURE_COMPAT(sb) |= cpu_to_le32(feature);
-                        sb->s_dirt = 1;
-                        ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
-                        unlock_super(sb);
-                        ext3_journal_stop(handle, sb->s_root->d_inode);
-                        break;
                 case SNAP_CLEAR_FEATURE:
-                        handle = ext3_journal_start(sb->s_root->d_inode, 1);
+                        EXT3_JOURNAL_START(sb, handle, 1, rc);
+                        if(rc)
+                                RETURN(rc);
                         lock_super(sb);
                         ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh);
-                        SB_FEATURE_COMPAT(sb) &= ~cpu_to_le32(feature);
-                        ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
+                        if (op == SNAP_SET_FEATURE) 
+                                SB_FEATURE_COMPAT(sb) |= cpu_to_le32(feature);
+                        else 
+                                SB_FEATURE_COMPAT(sb) &= ~cpu_to_le32(feature);
                         sb->s_dirt = 1;
+                        ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
                         unlock_super(sb);
-                        ext3_journal_stop(handle, sb->s_root->d_inode);
+                        journal_stop(handle);
                         break;
                 case SNAP_HAS_FEATURE:
                         /*FIXME should lock super or not*/
@@ -867,7 +947,7 @@ static ino_t fsfilt_ext3_get_indirect_ino(struct super_block *sb,
         ino_t ino = 0;
         int err;
         ENTRY;                                                                                                                                                                                             
-        if (index < 0 || index > EXT3_MAX_SNAPS || !primary)
+        if (index < 0 || index > EXT3_MAX_SNAPS)
                 RETURN(0);
         primary = iget(sb, primary_ino);   
        
@@ -878,8 +958,8 @@ static ino_t fsfilt_ext3_get_indirect_ino(struct super_block *sb,
         }                                                                                                                                                                                              
         err = ext3_xattr_get(primary, EXT3_SNAP_INDEX, EXT3_SNAP_ATTR,
                              buf, EXT3_MAX_SNAP_DATA);
-        if (err == -ENOATTR) {
-                GOTO(err_free, ino = -ENOATTR);
+        if (err == -ENODATA) {
+                GOTO(err_free, ino = -ENODATA);
         } else if (err < 0) {
                 CERROR(" attribute read error err=%d\n", err);
                 GOTO(err_free, ino = err);
@@ -928,9 +1008,6 @@ static int ext3_migrate_block(handle_t *handle, struct inode * dst,
        int i1_d=0, i1_s=0, i2_d=0, i2_s=0, i3_d=0, i3_s=0;
        int addr_per_block = EXT3_ADDR_PER_BLOCK(src->i_sb);
        int addr_per_block_bits = EXT3_ADDR_PER_BLOCK_BITS(src->i_sb);
-       unsigned long blksz = src->i_sb->s_blocksize;
-       kdev_t ddev = dst->i_dev;
-       kdev_t sdev = src->i_dev;
        int physical = 0;
         ENTRY;        
 
@@ -972,18 +1049,18 @@ static int ext3_migrate_block(handle_t *handle, struct inode * dst,
                        else 
                                RETURN(0);
                }
-               if(block_bmap(bread(ddev, i1_d, blksz), block)) 
+               if(block_bmap(sb_bread(dst->i_sb, i1_d), block)) 
                        RETURN(0);
 
                i1_s = inode_bmap (src, EXT3_IND_BLOCK);
                if( !i1_s)      RETURN(0);
 
-               physical = block_bmap(bread(sdev, i1_s, blksz), block);
+               physical = block_bmap(sb_bread(src->i_sb, i1_s), block);
 
                if( physical) {
-                       block_setbmap(handle, bread(ddev, i1_d, blksz),block,
+                       block_setbmap(handle, sb_bread(dst->i_sb, i1_d),block,
                                       physical); 
-                       block_setbmap(handle, bread(sdev, i1_s, blksz),block,0);
+                       block_setbmap(handle, sb_bread(src->i_sb, i1_s),block,0);
                        RETURN(1); 
                }
                else 
@@ -1003,41 +1080,41 @@ static int ext3_migrate_block(handle_t *handle, struct inode * dst,
                        else 
                                RETURN(0);
                }
-               i2_d = block_bmap (bread (ddev, i1_d, blksz),
+               i2_d = block_bmap (sb_bread (dst->i_sb, i1_d),
                                block >> addr_per_block_bits);
 
                if (!i2_d) {
                        
                        if(!i1_s)       RETURN(0);
 
-                       physical = block_bmap(bread (sdev, i1_s, blksz),
+                       physical = block_bmap(sb_bread (src->i_sb, i1_s),
                                               block >> addr_per_block_bits);
                        if(physical) {
-                               block_setbmap(handle, bread (ddev, i1_d,blksz), 
+                               block_setbmap(handle, sb_bread(dst->i_sb, i1_d), 
                                              block >> addr_per_block_bits, 
                                               physical);
-                               block_setbmap(handle, bread (sdev, i1_s,blksz), 
+                               block_setbmap(handle, sb_bread(src->i_sb, i1_s), 
                                              block >> addr_per_block_bits, 0);
                                RETURN(1);
                        }
                        else
                                RETURN(0);
                }
-               physical = block_bmap(bread (ddev, i2_d, blksz),
+               physical = block_bmap(sb_bread(dst->i_sb, i2_d),
                                      block & (addr_per_block - 1));
                if(physical) 
                                RETURN(0);
                else {
-                       i2_s =  block_bmap (bread (sdev, i1_s, blksz),
+                       i2_s =  block_bmap (sb_bread(src->i_sb, i1_s),
                                block >> addr_per_block_bits);
                        if(!i2_s)       RETURN(0);
        
-                       physical = block_bmap(bread (sdev, i2_s, blksz),
+                       physical = block_bmap(sb_bread(src->i_sb, i2_s),
                                   block & (addr_per_block - 1));
                        if(physical) {
-                               block_setbmap(handle, bread (ddev, i2_d, blksz),
+                               block_setbmap(handle, sb_bread(dst->i_sb, i2_d),
                                   block & (addr_per_block - 1), physical);
-                               block_setbmap(handle, bread (sdev, i2_s, blksz),
+                               block_setbmap(handle, sb_bread(src->i_sb, i2_s),
                                   block & (addr_per_block - 1), 0);
                                RETURN(1);
                        }
@@ -1056,41 +1133,41 @@ static int ext3_migrate_block(handle_t *handle, struct inode * dst,
                else 
                        RETURN(0);
        }
-       i2_d = block_bmap(bread (ddev, i1_d, blksz),
+       i2_d = block_bmap(sb_bread (dst->i_sb, i1_d),
                           block >> (addr_per_block_bits * 2));
 
-       if(i1_s) i2_s = block_bmap(bread(sdev, i1_s, blksz),
+       if(i1_s) i2_s = block_bmap(sb_bread(src->i_sb, i1_s),
                                   block >> (addr_per_block_bits * 2));
 
        if (!i2_d) {
                if( !i1_s)      RETURN(0);
                
-                physical = block_bmap(bread (sdev, i1_s, blksz),
+                physical = block_bmap(sb_bread (src->i_sb, i1_s),
                                       block >> (addr_per_block_bits * 2));
                if(physical) {
-                       block_setbmap(handle, bread (ddev, i1_d, blksz),
+                       block_setbmap(handle, sb_bread (dst->i_sb, i1_d),
                                      block >> (addr_per_block_bits * 2), physical);
-                       block_setbmap(handle, bread (sdev, i1_s, blksz),
+                       block_setbmap(handle, sb_bread (src->i_sb, i1_s),
                                      block >> (addr_per_block_bits * 2), 0);
                        RETURN(1);
                }
                else
                        RETURN(0);
        }
-       i3_d = block_bmap (bread (ddev, i2_d, blksz),
+       i3_d = block_bmap (sb_bread (dst->i_sb, i2_d),
                        (block >> addr_per_block_bits) & (addr_per_block - 1));
-       if( i2_s) i3_s = block_bmap (bread (sdev, i2_s, blksz),
+       if( i2_s) i3_s = block_bmap (sb_bread (src->i_sb, i2_s),
                        (block >> addr_per_block_bits) & (addr_per_block - 1));
        
        if (!i3_d) {
                if (!i2_s)      RETURN(0);      
-               physical = block_bmap (bread (sdev, i2_s, blksz),
+               physical = block_bmap (sb_bread (src->i_sb, i2_s),
                        (block >> addr_per_block_bits) & (addr_per_block - 1));
                if( physical) {
-                       block_setbmap (handle, bread (ddev, i2_d, blksz),
+                       block_setbmap (handle, sb_bread (dst->i_sb, i2_d),
                                       (block >> addr_per_block_bits) & 
                                        (addr_per_block - 1), physical);
-                       block_setbmap (handle, bread (sdev, i2_s, blksz),
+                       block_setbmap (handle, sb_bread (src->i_sb, i2_s),
                                       (block >> addr_per_block_bits) & 
                                        (addr_per_block - 1),0);
                        RETURN(1);
@@ -1098,19 +1175,19 @@ static int ext3_migrate_block(handle_t *handle, struct inode * dst,
                else
                        RETURN(0);
        }
-       physical = block_bmap (bread (ddev, i3_d, blksz),
+       physical = block_bmap (sb_bread (dst->i_sb, i3_d),
                           block & (addr_per_block - 1)) ;
        if(physical)    
                 RETURN(0);
        else {
                if(!i3_s)       
                         RETURN(0);     
-               physical = block_bmap(bread(sdev, i3_s, blksz),
+               physical = block_bmap(sb_bread(src->i_sb, i3_s),
                                      block & (addr_per_block - 1));
                if(physical) {
-                       block_setbmap (handle, bread (ddev, i3_d, blksz),
+                       block_setbmap (handle, sb_bread (dst->i_sb, i3_d),
                                       block & (addr_per_block - 1), physical);
-                       block_setbmap (handle, bread (sdev, i3_s, blksz),
+                       block_setbmap (handle, sb_bread (src->i_sb, i3_s),
                                       block & (addr_per_block - 1), 0); 
                        RETURN(1);
                }
@@ -1202,13 +1279,12 @@ static int fsfilt_ext3_destroy_indirect(struct inode *pri, int index,
        struct inode *ind;
        int save = 0, i=0, err = 0;
        handle_t *handle=NULL;
-       time_t ctime;
         ENTRY;
 
        if (index < 0 || index > EXT3_MAX_SNAPS)
                RETURN(0);
 
-       if( pri == pri->i_sb->u.ext3_sb.s_journal_inode ){
+       if( pri == EXT3_SB(pri->i_sb)->s_journal_inode ){
                CERROR("TRY TO DESTROY JOURNAL'S IND\n");
                RETURN(-EINVAL);
        }
@@ -1237,11 +1313,11 @@ static int fsfilt_ext3_destroy_indirect(struct inode *pri, int index,
 
        CDEBUG(D_INODE, "iget ind %lu, ref count = %d\n", 
               ind->i_ino, atomic_read(&ind->i_count));
-
-       handle = ext3_journal_start(pri, SNAP_DESTROY_TRANS_BLOCKS);
-       if (!handle) {
+        
+        EXT3_JOURNAL_START(pri->i_sb, handle, SNAP_DESTROY_TRANS_BLOCKS, err);
+       if (err) {
                iput(ind);
-               RETURN(-EINVAL);
+               RETURN(err);
        }
        /* if it's block level cow, first copy the blocks back */       
        if (EXT3_HAS_COMPAT_FEATURE(pri->i_sb, EXT3_FEATURE_COMPAT_BLOCKCOW) &&
@@ -1252,7 +1328,7 @@ static int fsfilt_ext3_destroy_indirect(struct inode *pri, int index,
                        next_ind = pri;
                        down(&ind->i_sem);
                } else {
-                       double_down(&next_ind->i_sem, &ind->i_sem);
+                       double_lock_inode(next_ind, ind);
                }
                blocks = (next_ind->i_size + next_ind->i_sb->s_blocksize-1) 
                          >> next_ind->i_sb->s_blocksize_bits;
@@ -1275,8 +1351,7 @@ static int fsfilt_ext3_destroy_indirect(struct inode *pri, int index,
                if (next_ind == pri) 
                        up(&ind->i_sem);
                else 
-                       double_up(&next_ind->i_sem, &ind->i_sem);
-
+                        double_unlock_inode(next_ind, ind);
        }
        
        CDEBUG(D_INODE, "delete indirect ino %lu\n", ind->i_ino);
@@ -1298,7 +1373,7 @@ static int fsfilt_ext3_destroy_indirect(struct inode *pri, int index,
         * Otherwise, if we are deleting the last indirect inode remove the
         * snaptable from the inode.    XXX
         */
-       if (!save && pri->u.ext3_i.i_dtime) {
+       if (!save && EXT3_I(pri)->i_dtime) {
                CDEBUG(D_INODE, "deleting primary %lu\n", pri->i_ino);
                pri->i_nlink = 0;
                /* reset err to 0 now */
@@ -1306,15 +1381,12 @@ static int fsfilt_ext3_destroy_indirect(struct inode *pri, int index,
        } else {
                CDEBUG(D_INODE, "%s redirector table\n", 
                        save ? "saving" : "deleting");
-               /* XXX: since set ea will modify i_ctime of pri, 
-                       so save/restore i_ctime. Need this necessary ? */
-               ctime = pri->i_ctime;   
-               err = ext3_xattr_set(handle, pri, EXT3_SNAP_INDEX, EXT3_SNAP_ATTR,
-                                    save ? buf : NULL, EXT3_MAX_SNAP_DATA, 0);
-               pri->i_ctime = ctime;
+               err = ext3_xattr_set_handle(handle, pri, EXT3_SNAP_INDEX, 
+                                            EXT3_SNAP_ATTR, save ? buf : NULL, 
+                                            EXT3_MAX_SNAP_DATA, 0);
                ext3_mark_inode_dirty(handle, pri);
        }
-       ext3_journal_stop(handle, pri);
+       journal_stop(handle);
        
         RETURN(err);
 }
@@ -1330,7 +1402,7 @@ static int fsfilt_ext3_restore_indirect(struct inode *pri, int index)
        if (index < 0 || index > EXT3_MAX_SNAPS)
                RETURN(-EINVAL);
 
-       if( pri == pri->i_sb->u.ext3_sb.s_journal_inode ){
+       if( pri == EXT3_SB(pri->i_sb)->s_journal_inode ){
                CERROR("TRY TO RESTORE JOURNAL\n");
                RETURN(-EINVAL);
        }
@@ -1343,9 +1415,9 @@ static int fsfilt_ext3_restore_indirect(struct inode *pri, int index)
 
        CDEBUG(D_INODE, "restore ino %lu to %lu\n", pri->i_ino, ind->i_ino);
 
-       handle = ext3_journal_start(pri, SNAP_RESTORE_TRANS_BLOCKS);
-       if( !handle )
-               RETURN(-EINVAL);
+        EXT3_JOURNAL_START(pri->i_sb, handle, SNAP_RESTORE_TRANS_BLOCKS, err); 
+       if(err)
+               RETURN(err);
        /* first destroy all the data blocks in primary inode */
        /* XXX: check this, ext3_new_inode, the first arg should be "dir" */
         err = ext3_throw_inode_data(handle, pri);
@@ -1353,15 +1425,15 @@ static int fsfilt_ext3_restore_indirect(struct inode *pri, int index)
                CERROR("restore_indirect, new_inode err\n");
                 RETURN(err);
         }      
-       double_down(&pri->i_sem, &ind->i_sem);
+       double_lock_inode(pri, ind);
        ext3_migrate_data(handle, pri, ind);
-       pri->u.ext3_i.i_flags &= ~EXT3_COW_FL;
+       EXT3_I(pri)->i_flags &= ~EXT3_COW_FL;
        ext3_mark_inode_dirty(handle, pri);
-       double_up(&pri->i_sem, &ind->i_sem);
+       double_unlock_inode(pri, ind);
        iput(ind);
         
         //fsfilt_ext3_destroy_indirect(pri, index);
-       ext3_journal_stop(handle, pri);
+       journal_stop(handle);
        
         RETURN(err);
 }
@@ -1432,51 +1504,47 @@ static int ext3_iterate_all(struct super_block *sb,
        ibase = gstart * EXT3_INODES_PER_GROUP(sb);
        for (gnum = gstart; gnum < EXT3_SB(sb)->s_groups_count;
             gnum++, ibase += EXT3_INODES_PER_GROUP(sb)) {
+               struct buffer_head *bitmap_bh = NULL;
                struct ext3_group_desc * gdp;
-               int bitmap_nr, ibyte;
-               char *bitmap;
-
+                ino_t  ino;
+                
                gdp = ext3_get_group_desc (sb, gnum, NULL);
                if (!gdp || le16_to_cpu(gdp->bg_free_inodes_count) ==
                    EXT3_INODES_PER_GROUP(sb))
                        continue;
-
-               bitmap_nr = ext3_load_inode_bitmap(sb, gnum);
-               if (bitmap_nr < 0)
-                       continue;
-
-               bitmap = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr]->b_data;
-               for (ibyte = istart >> 3; ibyte < EXT3_INODES_PER_GROUP(sb) >> 3;
-                    ibyte++) {
-                       int i, bit;
-
-                       if (!bitmap[ibyte])
-                               continue;
-
-                       /* FIXME need to verify if bit endianness will
-                        *       work properly here for all architectures.
-                        */
-                       for (i = 1, bit = 1; i <= 8; i++, bit <<= 1) {
-                               ino_t ino = ibase + (ibyte << 3) + i;
-
-                               if ((bitmap[ibyte] & bit) == 0)
+                bitmap_bh = read_inode_bitmap(sb, gnum);
+
+                if (!bitmap_bh)
+                        continue;
+                ino = 0;
+repeat:
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+                ino = find_next_bit((unsigned long *)bitmap_bh->b_data, 
+                                    EXT3_INODES_PER_GROUP(sb), ino);
+#else
+                ino = find_next_bit((unsigned long *)bitmap_bh->b_data, 
+                                    EXT3_INODES_PER_GROUP(sb), ino);
+#warning"FIXME-WANGDI need to port find_next_bit to 2.4" 
+#endif                
+                if (ino < EXT3_INODES_PER_GROUP(sb)) { 
+                        ino_t inum = ino + gnum * EXT3_INODES_PER_GROUP(sb) + 1;
+                        if (*start) {
+                               if (inum < (*start)->i_ino)
                                        continue;
-                               if (*start) {
-                                       if (ino < (*start)->i_ino)
-                                               continue;
-                               } else {
-                                       *start = iget(sb, ino);
-                                       if (!*start) 
-                                               GOTO(exit, err = -ENOMEM);
-                                       if (is_bad_inode(*start)) 
-                                               GOTO(exit, err = -EIO);
-                               }
-                               if ((err = (*repeat)(*start, priv)) != 0)
-                                       GOTO(exit, err);
-                               iput(*start);
-                               *start = NULL;
+                       } else {
+                               *start = iget(sb, inum);
+                               if (!*start) 
+                                       GOTO(exit, err = -ENOMEM);
+                               if (is_bad_inode(*start)) 
+                                       GOTO(exit, err = -EIO);
                        }
-               }
+                       if ((err = (*repeat)(*start, priv)) != 0)
+                               GOTO(exit, err);
+                       iput(*start);
+                       *start = NULL;
+                        if (++ino < EXT3_INODES_PER_GROUP(sb))
+                                goto repeat;
+                }
                istart = 0;
        }
 exit:
@@ -1521,15 +1589,43 @@ static int fsfilt_ext3_get_snap_info(struct inode *inode, void *key,
         } else if (keylen >= strlen(SNAP_GENERATION) 
                    && strcmp(key, SNAP_GENERATION) == 0) {
                 
-                rc = ext3_xattr_get(inode, EXT3_SNAP_INDEX,EXT3_SNAP_GENERATION,
-                                    (char *)val, *vallen);
-                if (rc == -ENOATTR) {
+                rc = ext3_xattr_get(inode, EXT3_SNAP_INDEX,
+                                    EXT3_SNAP_GENERATION, (char *)val, *vallen);
+                if (rc == -ENODATA) {
+                        *((__u32 *)val) = 0; 
+                        *vallen = sizeof(int);
+                        rc = 0;
+                }
+                if (rc > 0) {
+                        rc = 0;
+                        *vallen = rc;
+                }
+                RETURN(rc);
+        } else if (keylen >= strlen(SNAP_COUNT) && 
+                   strcmp(key, SNAP_COUNT) == 0) {
+                rc = ext3_xattr_get(inode, EXT3_SNAP_INDEX,
+                                    EXT3_SNAP_COUNT, val, *vallen);
+                if (rc == -ENODATA) {
                         *((__u32 *)val) = 0; 
                         *vallen = sizeof(int);
                         rc = 0;
                 }
+                if (rc > 0) {
+                        rc = 0;
+                        *vallen = rc;
+                }
                 RETURN(rc);
-        } 
+        } else if (keylen >= strlen(SNAP_ROOT_INO) && 
+                   (strcmp(key, SNAP_ROOT_INO) == 0)) {
+                
+                rc = ext3_xattr_get(inode, EXT3_SNAP_INDEX,
+                                    EXT3_SNAP_ROOT_INO, val, *vallen);
+                if (rc > 0) {
+                        rc = 0;
+                        *vallen = rc;
+                }
+                RETURN(rc);
+        }
         RETURN(-EINVAL);
 } 
 
@@ -1548,13 +1644,13 @@ static int fsfilt_ext3_set_snap_info(struct inode *inode, void *key,
         if (keylen >= strlen(SNAPTABLE_INFO) 
             && strcmp(key, SNAPTABLE_INFO) == 0) {
                 handle_t *handle;
-                handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
-                if( !handle )
-                        RETURN(-EINVAL);
-                rc = ext3_xattr_set(handle, inode, EXT3_SNAP_INDEX, 
-                                    EXT3_SNAPTABLE_EA, val, *vallen, 0); 
-               ext3_journal_stop(handle, inode);
+                EXT3_JOURNAL_START(inode->i_sb, handle, EXT3_XATTR_TRANS_BLOCKS,
+                                    rc); 
+                if(rc)
+                        RETURN(rc);
+                rc = ext3_xattr_set_handle(handle, inode, EXT3_SNAP_INDEX, 
+                                           EXT3_SNAPTABLE_EA, val, *vallen, 0); 
+               journal_stop(handle);
                 
                 RETURN(rc);
         } else if (keylen >= strlen(SNAP_GENERATION) 
@@ -1563,7 +1659,32 @@ static int fsfilt_ext3_set_snap_info(struct inode *inode, void *key,
                 rc = ext3_set_generation(inode, *(int*)val);
                 
                 RETURN(rc); 
-        }
+        } else if (keylen >= strlen(SNAP_COUNT) && 
+                   (strcmp(key, SNAP_COUNT) == 0)) {
+                handle_t *handle;
+                EXT3_JOURNAL_START(inode->i_sb, handle, 
+                                   EXT3_XATTR_TRANS_BLOCKS, rc); 
+                if(rc)
+                        RETURN(rc);
+                rc = ext3_xattr_set_handle(handle, inode, EXT3_SNAP_INDEX, 
+                                           EXT3_SNAP_COUNT, val, *vallen, 0); 
+               journal_stop(handle);
+                
+                RETURN(rc);
+        } else if (keylen >= strlen(SNAP_ROOT_INO) && 
+                   (strcmp(key, SNAP_ROOT_INO) == 0)) {
+                handle_t *handle;
+                EXT3_JOURNAL_START(inode->i_sb, handle, 
+                                   EXT3_XATTR_TRANS_BLOCKS, rc); 
+                if(rc)
+                        RETURN(rc);
+                rc = ext3_xattr_set_handle(handle, inode, EXT3_SNAP_INDEX, 
+                                           EXT3_SNAP_ROOT_INO, val, *vallen, 0); 
+               journal_stop(handle);
+                
+                RETURN(rc);
+        }       
         RETURN(-EINVAL);
 }
 static int fsfilt_ext3_dir_ent_size(char *name)
@@ -1591,8 +1712,6 @@ static int fsfilt_ext3_set_dir_ent(struct super_block *sb, char *name,
                 de1 = (struct ext3_dir_entry_2 *)(buf + buf_off); 
                 int rlen, nlen;
  
-                LASSERT(nlen == EXT3_DIR_REC_LEN_DE(de));
-                
                 rlen = le16_to_cpu(de->rec_len);
                 de->rec_len = cpu_to_le16(nlen);
                 
@@ -1600,6 +1719,7 @@ static int fsfilt_ext3_set_dir_ent(struct super_block *sb, char *name,
                 de1->name_len = strlen(name);
                 memcpy (de1->name, name, de->name_len);
                 nlen = EXT3_DIR_REC_LEN_DE(de1); 
+                LASSERT(nlen == EXT3_DIR_REC_LEN_DE(de));
                 RETURN(nlen);
         }