diff -rup -X dontdiff linux/fs/reiserfs/dir.c linux.patched/fs/reiserfs/dir.c
--- linux/fs/reiserfs/dir.c     Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/dir.c     Wed Nov 21 15:21:36 2001
@@ -170,7 +170,7 @@ static int reiserfs_readdir (struct file
       }

       /* directory continues in the right neighboring block */
-       set_cpu_key_k_offset (&pos_key, le_key_k_offset (ITEM_VERSION_1, rkey));
+       set_cpu_key_k_offset (&pos_key, le_key_k_offset (KEY_FORMAT_3_5, rkey));

    } /* while */

diff -rup -X dontdiff linux/fs/reiserfs/file.c linux.patched/fs/reiserfs/file.c
--- linux/fs/reiserfs/file.c    Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/file.c    Wed Nov 21 15:22:24 2001
@@ -33,7 +33,7 @@ static int reiserfs_file_release (struct

    /* fast out for when nothing needs to be done */
    if ((atomic_read(&inode->i_count) > 1 ||
-         !inode->u.reiserfs_i.i_pack_on_close ||
+         !(inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) ||
         !tail_has_to_be_packed(inode))       &&
       inode->u.reiserfs_i.i_prealloc_count <= 0) {
       return 0;
@@ -50,7 +50,7 @@ static int reiserfs_file_release (struct
    journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;

    if (atomic_read(&inode->i_count) <= 1 &&
-       inode->u.reiserfs_i.i_pack_on_close &&
+       (inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) &&
        tail_has_to_be_packed (inode)) {
       /* if regular file is released by last holder and it has been
          appended (we append by unformatted node only) or its direct
@@ -97,7 +97,7 @@ static int reiserfs_setattr(struct dentr
       /* version 2 items will be caught by the s_maxbytes check
       ** done for us in vmtruncate
       */
-        if (inode_items_version(inode) == ITEM_VERSION_1 &&
+       if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 &&
           attr->ia_size > MAX_NON_LFS)
            return -EFBIG ;

diff -rup -X dontdiff linux/fs/reiserfs/inode.c linux.patched/fs/reiserfs/inode.c
--- linux/fs/reiserfs/inode.c   Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/inode.c   Wed Nov 21 15:22:24 2001
@@ -42,11 +42,13 @@ void reiserfs_delete_inode (struct inode

       reiserfs_delete_object (&th, inode);
       pop_journal_writer(windex) ;
-       reiserfs_release_objectid (&th, inode->i_ino);

       journal_end(&th, inode->i_sb, jbegin_count) ;

-       up (&inode->i_sem);
+        up (&inode->i_sem);
+
+        /* all items of file are deleted, so we can remove "save" link */
+       remove_save_link (inode, 0/* not truncate */);
    } else {
       /* no object items are in the tree */
       ;
@@ -74,9 +76,9 @@ static void _make_cpu_key (struct cpu_ke
void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset,
             int type, int length )
{
-  _make_cpu_key (key, inode_items_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
-                  le32_to_cpu (INODE_PKEY (inode)->k_objectid),
-                  offset, type, length);
+  _make_cpu_key (key, get_inode_item_key_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
+                le32_to_cpu (INODE_PKEY (inode)->k_objectid),
+                offset, type, length);
}


@@ -219,7 +221,7 @@ static inline void set_block_dev_mapped
//
int file_capable (struct inode * inode, long block)
{
-    if (inode_items_version (inode) != ITEM_VERSION_1 || // it is new file.
+    if (get_inode_item_key_version (inode) != KEY_FORMAT_3_5 || // it is new file.
       block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb
       return 1;

@@ -542,7 +544,7 @@ static int reiserfs_get_block (struct in
                               /* bad.... */
    lock_kernel() ;
    th.t_trans_id = 0 ;
-    version = inode_items_version (inode);
+    version = get_inode_item_key_version (inode);

    if (block < 0) {
       unlock_kernel();
@@ -566,7 +568,7 @@ static int reiserfs_get_block (struct in
       return ret;
    }

-    inode->u.reiserfs_i.i_pack_on_close = 1 ;
+    inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask;

    windex = push_journal_writer("reiserfs_get_block") ;

@@ -882,7 +884,8 @@ static void init_inode (struct inode * i
       struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
       unsigned long blocks;

-       inode_items_version (inode) = ITEM_VERSION_1;
+       set_inode_item_key_version (inode, KEY_FORMAT_3_5);
+        set_inode_sd_version (inode, STAT_DATA_V1);
       inode->i_mode  = sd_v1_mode(sd);
       inode->i_nlink = sd_v1_nlink(sd);
       inode->i_uid   = sd_v1_uid(sd);
@@ -931,13 +934,13 @@ static void init_inode (struct inode * i
            inode->i_generation = sd_v2_generation(sd);

       if (S_ISDIR (inode->i_mode) || S_ISLNK (inode->i_mode))
-           inode_items_version (inode) = ITEM_VERSION_1;
+           set_inode_item_key_version (inode, KEY_FORMAT_3_5);
       else
-           inode_items_version (inode) = ITEM_VERSION_2;
+            set_inode_item_key_version (inode, KEY_FORMAT_3_6);
    }

    /* nopack = 0, by default */
-    inode->u.reiserfs_i.nopack = 0;
+    inode->u.reiserfs_i.i_flags &= ~i_nopack_mask;

    pathrelse (path);
    if (S_ISREG (inode->i_mode)) {
@@ -1117,7 +1120,7 @@ void reiserfs_read_inode2 (struct inode

    /* set version 1, version 2 could be used too, because stat data
       key is the same in both versions */
-    key.version = ITEM_VERSION_1;
+    key.version = KEY_FORMAT_3_5;
    key.on_disk_key.k_dir_id = dirino;
    key.on_disk_key.k_objectid = inode->i_ino;
    key.on_disk_key.u.k_offset_v1.k_offset = SD_OFFSET;
@@ -1347,20 +1350,20 @@ static int reiserfs_new_directory (struc
    struct cpu_key key;
    int retval;

-    _make_cpu_key (&key, ITEM_VERSION_1, le32_to_cpu (ih->ih_key.k_dir_id),
+    _make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id),
                  le32_to_cpu (ih->ih_key.k_objectid), DOT_OFFSET, TYPE_DIRENTRY, 3/*key length*/);

    /* compose item head for new item. Directories consist of items of
       old type (ITEM_VERSION_1). Do not set key (second arg is 0), it
       is done by reiserfs_new_inode */
    if (old_format_only (sb)) {
-       make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
+       make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);

       make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
                               INODE_PKEY (dir)->k_dir_id,
                               INODE_PKEY (dir)->k_objectid );
    } else {
-       make_le_item_head (ih, 0, ITEM_VERSION_1, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
+       make_le_item_head (ih, 0, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);

       make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
                               INODE_PKEY (dir)->k_dir_id,
@@ -1396,12 +1399,12 @@ static int reiserfs_new_symlink (struct
    struct cpu_key key;
    int retval;

-    _make_cpu_key (&key, ITEM_VERSION_1,
+    _make_cpu_key (&key, KEY_FORMAT_3_5,
                  le32_to_cpu (ih->ih_key.k_dir_id),
                  le32_to_cpu (ih->ih_key.k_objectid),
                  1, TYPE_DIRECT, 3/*key length*/);

-    make_le_item_head (ih, 0, ITEM_VERSION_1, 1, TYPE_DIRECT, item_len, 0/*free_space*/);
+    make_le_item_head (ih, 0, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/);

    /* look for place in the tree for new item */
    retval = search_item (sb, &key, path);
@@ -1472,13 +1475,13 @@ struct inode * reiserfs_new_inode (struc
      inode->i_generation = ++event;
#endif
    if (old_format_only (sb))
-       make_le_item_head (&ih, 0, ITEM_VERSION_1, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
+       make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
    else
-       make_le_item_head (&ih, 0, ITEM_VERSION_2, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
+       make_le_item_head (&ih, 0, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);


    /* key to search for correct place for new stat data */
-    _make_cpu_key (&key, ITEM_VERSION_2, le32_to_cpu (ih.ih_key.k_dir_id),
+    _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id),
                  le32_to_cpu (ih.ih_key.k_objectid), SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);

    /* find proper place for inserting of stat data */
@@ -1529,10 +1532,14 @@ struct inode * reiserfs_new_inode (struc
    // format, other new objects will consist of new items)
    memcpy (INODE_PKEY (inode), &(ih.ih_key), KEY_SIZE);
    if (old_format_only (sb) || S_ISDIR(mode) || S_ISLNK(mode))
-       inode_items_version (inode) = ITEM_VERSION_1;
+        set_inode_item_key_version (inode, KEY_FORMAT_3_5);
    else
-       inode_items_version (inode) = ITEM_VERSION_2;
-
+        set_inode_item_key_version (inode, KEY_FORMAT_3_6);
+    if (old_format_only (sb))
+       set_inode_sd_version (inode, STAT_DATA_V1);
+    else
+       set_inode_sd_version (inode, STAT_DATA_V2);
+
    /* insert the stat data into the tree */
    retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
    if (retval) {
@@ -1692,12 +1699,23 @@ void reiserfs_truncate_file(struct inode
    ** because the truncate might pack the item anyway
    ** (it will unmap bh if it packs).
    */
-    journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 ) ;
+    /* it is enough to reserve space in transaction for 2 balancings:
+       one for "save" link adding and another for the first
+       cut_from_item. 1 is for update_sd */
+    journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
    reiserfs_update_inode_transaction(p_s_inode) ;
    windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
+    if (update_timestamps)
+           /* we are doing real truncate: if the system crashes before the last
+              transaction of truncating gets committed - on reboot the file
+              either appears truncated properly or not truncated at all */
+           add_save_link (&th, p_s_inode, 1);
    reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
    pop_journal_writer(windex) ;
-    journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 ) ;
+    journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
+
+    if (update_timestamps)
+       remove_save_link (p_s_inode, 1/* truncate */);

    if (page) {
        length = offset & (blocksize - 1) ;
diff -rup -X dontdiff linux/fs/reiserfs/ioctl.c linux.patched/fs/reiserfs/ioctl.c
--- linux/fs/reiserfs/ioctl.c   Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/ioctl.c   Wed Nov 21 15:21:36 2001
@@ -46,7 +46,7 @@ int reiserfs_unpack (struct inode * inod
        return -EINVAL ;
    }
    /* ioctl already done */
-    if (inode->u.reiserfs_i.nopack) {
+    if (inode->u.reiserfs_i.i_flags & i_nopack_mask) {
        return 0 ;
    }
    lock_kernel();
@@ -59,7 +59,7 @@ int reiserfs_unpack (struct inode * inod
    write_from = inode->i_size & (blocksize - 1) ;
    /* if we are on a block boundary, we are already unpacked.  */
    if ( write_from == 0) {
-       inode->u.reiserfs_i.nopack = 1;
+       inode->u.reiserfs_i.i_flags |= i_nopack_mask;
       goto out ;
    }

@@ -79,7 +79,7 @@ int reiserfs_unpack (struct inode * inod

    /* conversion can change page contents, must flush */
    flush_dcache_page(page) ;
-    inode->u.reiserfs_i.nopack = 1;
+    inode->u.reiserfs_i.i_flags |= i_nopack_mask;
    kunmap(page) ; /* mapped by prepare_write */

out_unlock:
diff -rup -X dontdiff linux/fs/reiserfs/journal.c linux.patched/fs/reiserfs/journal.c
--- linux/fs/reiserfs/journal.c Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/journal.c Wed Nov 21 15:22:10 2001
@@ -92,6 +92,8 @@ static int do_journal_end(struct reiserf
static int flush_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ;
static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall)  ;
static int can_dirty(struct reiserfs_journal_cnode *cn) ;
+static int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed);
+static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks);

static void init_journal_hash(struct super_block *p_s_sb) {
  memset(SB_JOURNAL(p_s_sb)->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ;
@@ -2083,7 +2085,7 @@ relock:
}


-int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
+static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
  return do_journal_begin_r(th, p_s_sb, nblocks, 1) ;
}

@@ -2238,7 +2240,7 @@ int journal_end(struct reiserfs_transact
**
** returns 1 if it cleaned and relsed the buffer. 0 otherwise
*/
-int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) {
+static int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) {
  struct buffer_head *bh ;
  struct reiserfs_journal_cnode *cn ;
  int ret = 0;
@@ -2279,7 +2281,7 @@ int remove_from_transaction(struct super
}

/* removes from a specific journal list hash */
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) {
+static int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) {
  remove_journal_hash(SB_JOURNAL(s)->j_list_hash_table, jl, bh, remove_freed) ;
  return 0 ;
}
diff -rup -X dontdiff linux/fs/reiserfs/lbalance.c linux.patched/fs/reiserfs/lbalance.c
--- linux/fs/reiserfs/lbalance.c        Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/lbalance.c        Tue Nov 20 22:47:11 2001
@@ -63,7 +63,7 @@ static void leaf_copy_dir_entries (struc

       /* form item header */
       memcpy (&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
-       put_ih_version( &new_ih, ITEM_VERSION_1 );
+       put_ih_version( &new_ih, KEY_FORMAT_3_5 );
       /* calculate item len */
       put_ih_item_len( &new_ih, DEH_SIZE * copy_count + copy_records_len );
       put_ih_entry_count( &new_ih, 0 );
@@ -78,7 +78,7 @@ static void leaf_copy_dir_entries (struc
               set_le_ih_k_offset (&new_ih, U32_MAX);
               /* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */
           }
-           set_le_key_k_type (ITEM_VERSION_1, &(new_ih.ih_key), TYPE_DIRENTRY);
+           set_le_key_k_type (KEY_FORMAT_3_5, &(new_ih.ih_key), TYPE_DIRENTRY);
       }

       /* insert item into dest buffer */
diff -rup -X dontdiff linux/fs/reiserfs/namei.c linux.patched/fs/reiserfs/namei.c
--- linux/fs/reiserfs/namei.c   Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/namei.c   Tue Nov 20 22:47:11 2001
@@ -94,7 +94,7 @@ static inline void store_de_entry_key (s
       BUG ();

    /* store key of the found entry */
-    de->de_entry_key.version = ITEM_VERSION_1;
+    de->de_entry_key.version = KEY_FORMAT_3_5;
    de->de_entry_key.on_disk_key.k_dir_id = le32_to_cpu (de->de_ih->ih_key.k_dir_id);
    de->de_entry_key.on_disk_key.k_objectid = le32_to_cpu (de->de_ih->ih_key.k_objectid);
    set_cpu_key_k_offset (&(de->de_entry_key), deh_offset (deh));
@@ -702,11 +702,14 @@ static int reiserfs_rmdir (struct inode
    struct inode * inode;
    int windex ;
    struct reiserfs_transaction_handle th ;
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;
+    int jbegin_count;
    INITIALIZE_PATH (path);
    struct reiserfs_dir_entry de;


+    /* we will be doing 2 balancings and update 2 stat data */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
+
    journal_begin(&th, dir->i_sb, jbegin_count) ;
    windex = push_journal_writer("reiserfs_rmdir") ;

@@ -750,6 +753,9 @@ static int reiserfs_rmdir (struct inode
    dir->i_blocks = ((dir->i_size + 511) >> 9);
    reiserfs_update_sd (&th, dir);

+    /* prevent empty directory from getting lost */
+    add_save_link (&th, inode, 0/* not truncate */);
+
    pop_journal_writer(windex) ;
    journal_end(&th, dir->i_sb, jbegin_count) ;
    reiserfs_check_path(&path) ;
@@ -781,7 +787,13 @@ static int reiserfs_unlink (struct inode
    INITIALIZE_PATH (path);
    int windex ;
    struct reiserfs_transaction_handle th ;
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;
+    int jbegin_count;
+
+    inode = dentry->d_inode;
+
+    /* in this transaction we can be doing at max two balancings and update
+       two stat datas */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;

    journal_begin(&th, dir->i_sb, jbegin_count) ;
    windex = push_journal_writer("reiserfs_unlink") ;
@@ -791,7 +803,6 @@ static int reiserfs_unlink (struct inode
       retval = -ENOENT;
       goto end_unlink;
    }
-    inode = dentry->d_inode;

    reiserfs_update_inode_transaction(inode) ;
    reiserfs_update_inode_transaction(dir) ;
@@ -822,6 +833,10 @@ static int reiserfs_unlink (struct inode
    dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    reiserfs_update_sd (&th, dir);

+    if (!inode->i_nlink)
+       /* prevent file from getting lost */
+       add_save_link (&th, inode, 0/* not truncate */);
+
    pop_journal_writer(windex) ;
    journal_end(&th, dir->i_sb, jbegin_count) ;
    reiserfs_check_path(&path) ;
@@ -1032,8 +1047,13 @@ static int reiserfs_rename (struct inode
    struct inode * old_inode, * new_inode;
    int windex ;
    struct reiserfs_transaction_handle th ;
-    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;
+    int jbegin_count ;
+

+    /* two balancings: old name removal, new name insertion or "save" link,
+       stat data updates: old directory and new directory and maybe block
+       containing ".." of renamed directory */
+    jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 3;

    old_inode = old_dentry->d_inode;
    new_inode = new_dentry->d_inode;
@@ -1176,29 +1196,25 @@ static int reiserfs_rename (struct inode
    if (new_inode) {
       // adjust link number of the victim
       if (S_ISDIR(new_inode->i_mode)) {
-         DEC_DIR_INODE_NLINK(new_inode)
+           new_inode->i_nlink  = 0;
       } else {
-         new_inode->i_nlink--;
+           new_inode->i_nlink--;
       }
       new_inode->i_ctime = CURRENT_TIME;
    }

    if (S_ISDIR(old_inode->i_mode)) {
-      //if (dot_dot_de.de_bh) {
-       // adjust ".." of renamed directory
+       // adjust ".." of renamed directory
       set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
       journal_mark_dirty (&th, new_dir->i_sb, dot_dot_de.de_bh);
-
-       DEC_DIR_INODE_NLINK(old_dir)
-       if (new_inode) {
-           if (S_ISDIR(new_inode->i_mode)) {
-               DEC_DIR_INODE_NLINK(new_inode)
-           } else {
-               new_inode->i_nlink--;
-           }
-       } else {
-           INC_DIR_INODE_NLINK(new_dir)
-       }
+
+        if (!new_inode)
+           /* there (in new_dir) was no directory, so it got new link
+              (".."  of renamed directory) */
+           INC_DIR_INODE_NLINK(new_dir);
+
+       /* old directory lost one link - ".. " of renamed directory */
+       DEC_DIR_INODE_NLINK(old_dir);
    }

    // looks like in 2.3.99pre3 brelse is atomic. so we can use pathrelse
@@ -1216,13 +1232,19 @@ static int reiserfs_rename (struct inode

    reiserfs_update_sd (&th, old_dir);
    reiserfs_update_sd (&th, new_dir);
-    if (new_inode)
+
+    if (new_inode) {
+       if (new_inode->i_nlink == 0)
+           add_save_link (&th, new_inode, 0/* not truncate */);
       reiserfs_update_sd (&th, new_inode);
+    }

    pop_journal_writer(windex) ;
    journal_end(&th, old_dir->i_sb, jbegin_count) ;
    return 0;
}
+
+

/*
 * directories can handle most operations...
diff -rup -X dontdiff linux/fs/reiserfs/objectid.c linux.patched/fs/reiserfs/objectid.c
--- linux/fs/reiserfs/objectid.c        Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/objectid.c        Tue Nov 20 22:47:11 2001
@@ -162,7 +162,7 @@ void reiserfs_release_objectid (struct r
       i += 2;
    }

-    reiserfs_warning ("vs-15010: reiserfs_release_objectid: tried to free free object id (%lu)",
+    reiserfs_warning ("vs-15011: reiserfs_release_objectid: tried to free free object id (%lu)\n",
                     ( long unsigned ) objectid_to_release);
}

diff -rup -X dontdiff linux/fs/reiserfs/prints.c linux.patched/fs/reiserfs/prints.c
--- linux/fs/reiserfs/prints.c  Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/prints.c  Tue Nov 20 22:47:11 2001
@@ -109,7 +109,7 @@ static void sprintf_de_head( char *buf,
static void sprintf_item_head (char * buf, struct item_head * ih)
{
    if (ih) {
-       sprintf (buf, "%s", (ih_version (ih) == ITEM_VERSION_2) ? "*NEW* " : "*OLD*");
+       sprintf (buf, "%s", (ih_version (ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*");
       sprintf_le_key (buf + strlen (buf), &(ih->ih_key));
       sprintf (buf + strlen (buf), ", item_len %d, item_location %d, "
                "free_space(entry_count) %d",
diff -rup -X dontdiff linux/fs/reiserfs/stree.c linux.patched/fs/reiserfs/stree.c
--- linux/fs/reiserfs/stree.c   Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/stree.c   Tue Nov 20 22:47:11 2001
@@ -225,7 +225,7 @@ inline void le_key2cpu_key (struct cpu_k

    // find out version of the key
    to->version = le_key_version (from);
-    if (to->version == ITEM_VERSION_1) {
+    if (to->version == KEY_FORMAT_3_5) {
       to->on_disk_key.u.k_offset_v1.k_offset = le32_to_cpu (from->u.k_offset_v1.k_offset);
       to->on_disk_key.u.k_offset_v1.k_uniqueness = le32_to_cpu (from->u.k_offset_v1.k_uniqueness);
    } else {
@@ -727,7 +727,11 @@ int search_by_key (struct super_block *
           continue;
       }

-       RFALSE( ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
+        /* only check that the key is in the buffer if p_s_key is not
+           equal to the MAX_KEY. Latter case is only possible in
+           "finish_unfinished()" processing during mount. */
+        RFALSE( COMP_KEYS( &MAX_KEY, p_s_key ) &&
+                ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
               "PAP-5130: key is not in the buffer");
#ifdef CONFIG_REISERFS_CHECK
       if ( cur_tb ) {
@@ -917,7 +921,7 @@ static inline int prepare_for_direct_ite
    }

    // new file gets truncated
-    if (inode_items_version (inode) == ITEM_VERSION_2) {
+    if (get_inode_item_key_version (inode) == KEY_FORMAT_3_6) {
       //
       round_len = ROUND_UP (new_file_length);
       /* this was n_new_file_length < le_ih ... */
@@ -1314,8 +1318,8 @@ int reiserfs_delete_item (struct reiserf


/* this deletes item which never gets split */
-static void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
-                                       struct key * key)
+void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
+                                struct key * key)
{
    struct tree_balance tb;
    INITIALIZE_PATH (path);
@@ -1408,7 +1412,7 @@ static int maybe_indirect_to_direct (str
    */
    if (atomic_read(&p_s_inode->i_count) > 1 ||
        !tail_has_to_be_packed (p_s_inode) ||
-       !page || p_s_inode->u.reiserfs_i.nopack) {
+        !page || (p_s_inode->u.reiserfs_i.i_flags & i_nopack_mask)) {
       // leave tail in an unformatted node
       *p_c_mode = M_SKIP_BALANCING;
       cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1));
@@ -1610,7 +1614,7 @@ int reiserfs_cut_from_item (struct reise
       ** be flushed before the transaction commits, so we don't need to
       ** deal with it here.
       */
-       p_s_inode->u.reiserfs_i.i_pack_on_close = 0 ;
+       p_s_inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask;
    }
    return n_ret_value;
}
@@ -1619,14 +1623,14 @@ int reiserfs_cut_from_item (struct reise
static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode)
{
    if (inode->i_nlink)
-       reiserfs_warning ("vs-5655: truncate_directory: link count != 0");
+       reiserfs_warning ("vs-5655: truncate_directory: link count != 0\n");

-    set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), DOT_OFFSET);
-    set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_DIRENTRY);
+    set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET);
+    set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY);
    reiserfs_delete_solid_item (th, INODE_PKEY (inode));

-    set_le_key_k_offset (ITEM_VERSION_1, INODE_PKEY (inode), SD_OFFSET);
-    set_le_key_k_type (ITEM_VERSION_1, INODE_PKEY (inode), TYPE_STAT_DATA);
+    set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), SD_OFFSET);
+    set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA);
}


@@ -1699,6 +1703,7 @@ void reiserfs_do_truncate (struct reiser
       pathrelse(&s_search_path);
       return;
    }
+
    /* Update key to search for the last file item. */
    set_cpu_key_k_offset (&s_item_key, n_file_size);

@@ -1735,7 +1740,6 @@ void reiserfs_do_truncate (struct reiser

         if (update_timestamps) {
             p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME;
-             // FIXME: sd gets wrong size here
         }
         reiserfs_update_sd(th, p_s_inode) ;

diff -rup -X dontdiff linux/fs/reiserfs/super.c linux.patched/fs/reiserfs/super.c
--- linux/fs/reiserfs/super.c   Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/super.c   Wed Nov 21 15:25:49 2001
@@ -76,6 +76,245 @@ void reiserfs_unlockfs(struct super_bloc
  reiserfs_allow_writes(s) ;
}

+extern const struct key  MAX_KEY;
+
+
+/* this is used to delete "save link" when there are no items of a
+   file it points to. It can either happen if unlink is completed but
+   "save unlink" removal, or if file has both unlink and truncate
+   pending and as unlink completes first (because key of "save link"
+   protecting unlink is bigger that a key lf "save link" which
+   protects truncate), so there left no items to make truncate
+   completion on */
+static void remove_save_link_only (struct super_block * s, struct key * key)
+{
+    struct reiserfs_transaction_handle th;
+
+     /* we are going to do one balancing */
+     journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT + 1);
+
+     reiserfs_delete_solid_item (&th, key);
+     if (is_direct_le_key (KEY_FORMAT_3_5, key))
+        /* removals are protected by direct items */
+        reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
+
+     journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
+}
+
+
+/* look for uncompleted unlinks and truncates and complete them */
+static void finish_unfinished (struct super_block * s)
+{
+    INITIALIZE_PATH (path);
+    struct cpu_key max_cpu_key, obj_key;
+    struct key save_link_key;
+    int retval;
+    struct item_head * ih;
+    struct buffer_head * bh;
+    int item_pos;
+    char * item;
+    int done;
+    struct inode * inode;
+    int truncate;
+
+
+    /* compose key to look for "save" links */
+    max_cpu_key.version = KEY_FORMAT_3_5;
+    max_cpu_key.on_disk_key = MAX_KEY;
+    max_cpu_key.key_length = 3;
+
+    done = 0;
+    while (1) {
+        retval = search_item (s, &max_cpu_key, &path);
+        if (retval != ITEM_NOT_FOUND) {
+            reiserfs_warning ("vs-2140: finish_unfinished: search_by_key returned %d\n",
+                              retval);
+            break;
+        }
+
+        bh = get_last_bh (&path);
+        item_pos = get_item_pos (&path);
+        if (item_pos != B_NR_ITEMS (bh)) {
+            reiserfs_warning ("vs-2060: finish_unfinished: wrong position found\n");
+            break;
+        }
+        item_pos --;
+        ih = B_N_PITEM_HEAD (bh, item_pos);
+
+        if (le32_to_cpu (ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)
+            /* there are no "save" links anymore */
+            break;
+
+        save_link_key = ih->ih_key;
+        if (is_indirect_le_ih (ih))
+            truncate = 1;
+        else
+            truncate = 0;
+
+        /* reiserfs_iget needs k_dirid and k_objectid only */
+        item = B_I_PITEM (bh, ih);
+        obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item);
+        obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid);
+       obj_key.on_disk_key.u.k_offset_v1.k_offset = 0;
+       obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0;
+
+        pathrelse (&path);
+
+        inode = reiserfs_iget (s, &obj_key);
+        if (!inode) {
+            /* the unlink almost completed, it just did not manage to remove
+              "save" link and release objectid */
+            reiserfs_warning ("vs-2180: finish_unfinished: iget failed for %K\n",
+                              &obj_key);
+            remove_save_link_only (s, &save_link_key);
+            continue;
+        }
+
+       if (!truncate && inode->i_nlink) {
+           /* file is not unlinked */
+            reiserfs_warning ("vs-2185: finish_unfinished: file %K is not unlinked\n",
+                              &obj_key);
+            remove_save_link_only (s, &save_link_key);
+            continue;
+       }
+
+        if (truncate) {
+            inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask;
+            /* not completed truncate found. New size was committed together
+              with "save" link */
+            reiserfs_warning ("Truncating %k to %Ld ..",
+                              INODE_PKEY (inode), inode->i_size);
+            reiserfs_truncate_file (inode, 0/*don't update modification time*/);
+            remove_save_link (inode, truncate);
+        } else {
+            inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask;
+            /* not completed unlink (rmdir) found */
+            reiserfs_warning ("Removing %k..", INODE_PKEY (inode));
+            /* removal gets completed in iput */
+        }
+
+        iput (inode);
+        reiserfs_warning ("done\n");
+        done ++;
+    }
+
+    pathrelse (&path);
+    if (done)
+        reiserfs_warning ("There were %d uncompleted unlinks/truncates. "
+                          "Completed\n", done);
+}
+
+/* to protect file being unlinked from getting lost we "safe" link files
+   being unlinked. This link will be deleted in the same transaction with last
+   item of file. mounting the filesytem we scan all these links and remove
+   files which almost got lost */
+void add_save_link (struct reiserfs_transaction_handle * th,
+                   struct inode * inode, int truncate)
+{
+    INITIALIZE_PATH (path);
+    int retval;
+    struct cpu_key key;
+    struct item_head ih;
+    __u32 link;
+
+    /* file can only get one "save link" of each kind */
+    RFALSE( truncate &&
+           ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ),
+           "saved link already exists for truncated inode %lx",
+           ( long ) inode -> i_ino );
+    RFALSE( !truncate &&
+           ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ),
+           "saved link already exists for unlinked inode %lx",
+           ( long ) inode -> i_ino );
+
+    /* setup key of "save" link */
+    key.version = KEY_FORMAT_3_5;
+    key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID;
+    key.on_disk_key.k_objectid = inode->i_ino;
+    if (!truncate) {
+       /* unlink, rmdir, rename */
+       set_cpu_key_k_offset (&key, 1 + inode->i_sb->s_blocksize);
+       set_cpu_key_k_type (&key, TYPE_DIRECT);
+
+       /* item head of "safe" link */
+       make_le_item_head (&ih, &key, key.version, 1 + inode->i_sb->s_blocksize, TYPE_DIRECT,
+                          4/*length*/, 0xffff/*free space*/);
+    } else {
+       /* truncate */
+       set_cpu_key_k_offset (&key, 1);
+       set_cpu_key_k_type (&key, TYPE_INDIRECT);
+
+       /* item head of "safe" link */
+       make_le_item_head (&ih, &key, key.version, 1, TYPE_INDIRECT,
+                          4/*length*/, 0/*free space*/);
+    }
+    key.key_length = 3;
+
+    /* look for its place in the tree */
+    retval = search_item (inode->i_sb, &key, &path);
+    if (retval != ITEM_NOT_FOUND) {
+       reiserfs_warning ("vs-2100: add_save_link:"
+                         "search_by_key (%K) returned %d\n", &key, retval);
+       pathrelse (&path);
+       return;
+    }
+
+    /* body of "save" link */
+    link = cpu_to_le32 (INODE_PKEY (inode)->k_dir_id);
+
+    /* put "save" link inot tree */
+    retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link);
+    if (retval)
+       reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n",
+                         retval);
+    else {
+       if( truncate )
+           inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask;
+       else
+           inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask;
+    }
+}
+
+
+/* this opens transaction unlike add_save_link */
+void remove_save_link (struct inode * inode, int truncate)
+{
+    struct reiserfs_transaction_handle th;
+    struct key key;
+
+
+    /* we are going to do one balancing only */
+    journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+
+    /* setup key of "save" link */
+    key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID);
+    key.k_objectid = INODE_PKEY (inode)->k_objectid;
+    if (!truncate) {
+        /* unlink, rmdir, rename */
+        set_le_key_k_offset (KEY_FORMAT_3_5, &key,
+                            1 + inode->i_sb->s_blocksize);
+        set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_DIRECT);
+    } else {
+        /* truncate */
+        set_le_key_k_offset (KEY_FORMAT_3_5, &key, 1);
+        set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_INDIRECT);
+    }
+
+    if( ( truncate &&
+          ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ) ) ||
+        ( !truncate &&
+          ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ) ) )
+       reiserfs_delete_solid_item (&th, &key);
+    if (!truncate) {
+       reiserfs_release_objectid (&th, inode->i_ino);
+       inode -> u.reiserfs_i.i_flags &= ~i_link_saved_unlink_mask;
+    } else
+       inode -> u.reiserfs_i.i_flags &= ~i_link_saved_truncate_mask;
+
+    journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+}
+
+
//
// a portion of this function, particularly the VFS interface portion,
// was derived from minix or ext2's analog and evolved as the
@@ -307,6 +546,10 @@ static int reiserfs_remount (struct supe
  /* this will force a full flush of all journal lists */
  SB_JOURNAL(s)->j_must_wait = 1 ;
  journal_end(&th, s, 10) ;
+
+  if (!( *flags & MS_RDONLY ) )
+    finish_unfinished( s );
+
  return 0;
}

@@ -767,6 +1010,10 @@ static struct super_block * reiserfs_rea

       journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
       journal_end(&th, s, 1) ;
+
+       /* look for files which were to be removed in previous session */
+       finish_unfinished (s);
+
       s->s_dirt = 0;
    } else {
       struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
@@ -858,6 +1105,7 @@ static void __exit exit_reiserfs_fs(void
       reiserfs_proc_info_global_done();
        unregister_filesystem(&reiserfs_fs_type);
}
+

module_init(init_reiserfs_fs) ;
module_exit(exit_reiserfs_fs) ;
diff -rup -X dontdiff linux/fs/reiserfs/tail_conversion.c linux.patched/fs/reiserfs/tail_conversion.c
--- linux/fs/reiserfs/tail_conversion.c Wed Nov 21 15:23:20 2001
+++ linux.patched/fs/reiserfs/tail_conversion.c Tue Nov 20 22:47:11 2001
@@ -240,7 +240,7 @@ int indirect2direct (struct reiserfs_tra


    /* Set direct item header to insert. */
-    make_le_item_head (&s_ih, 0, inode_items_version (p_s_inode), pos1 + 1,
+    make_le_item_head (&s_ih, 0, get_inode_item_key_version (p_s_inode), pos1 + 1,
                      TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/);

    /* we want a pointer to the first byte of the tail in the page.
Only in linux.patched/include/linux: modules
diff -rup -X dontdiff linux/include/linux/reiserfs_fs.h linux.patched/include/linux/reiserfs_fs.h
--- linux/include/linux/reiserfs_fs.h   Wed Nov 21 15:23:20 2001
+++ linux.patched/include/linux/reiserfs_fs.h   Wed Nov 21 15:34:18 2001
@@ -144,10 +144,35 @@ struct unfm_nodeinfo {
    unsigned short unfm_freespace;
};

-// this says about version of all items (but stat data) the object
-// consists of
-#define inode_items_version(inode) ((inode)->u.reiserfs_i.i_version)

+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
+
+/* there are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+/** this says about version of key of all items (but stat data) the
+    object consists of */
+#define get_inode_item_key_version( inode )                                    \
+    (((inode)->u.reiserfs_i.i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version( inode, version )                           \
+         ({ if((version)==KEY_FORMAT_3_6)                                      \
+                (inode)->u.reiserfs_i.i_flags |= i_item_key_version_mask;      \
+            else                                                               \
+                (inode)->u.reiserfs_i.i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode)                                            \
+    (((inode)->u.reiserfs_i.i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version)                                   \
+         ({ if((version)==STAT_DATA_V2)                                        \
+                (inode)->u.reiserfs_i.i_flags |= i_stat_data_version_mask;     \
+            else                                                               \
+                (inode)->u.reiserfs_i.i_flags &= ~i_stat_data_version_mask; })

/* This is an aggressive tail suppression policy, I am hoping it
   improves our benchmarks. The principle behind it is that percentage
@@ -186,18 +211,6 @@ struct unfm_nodeinfo {
/***************************************************************************/

//
-// we do support for old format of reiserfs: the problem is to
-// distinuquish keys with 32 bit offset and keys with 60 bit ones. On
-// leaf level we use ih_version of struct item_head (was
-// ih_reserved). For all old items it is set to 0
-// (ITEM_VERSION_1). For new items it is ITEM_VERSION_2. On internal
-// levels we have to know version of item key belongs to.
-//
-#define ITEM_VERSION_1 0
-#define ITEM_VERSION_2 1
-
-
-//
// directories use this key as well as old files
//
struct offset_v1 {
@@ -364,8 +377,8 @@ struct item_head

#define unreachable_item(ih) (ih_version(ih) & (1 << 15))

-#define get_ih_free_space(ih) (ih_version (ih) == ITEM_VERSION_2 ? 0 : ih_free_space (ih))
-#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == ITEM_VERSION_2) ? 0 : (val)))
+#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
+#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val)))

/* these operate on indirect items, where you've got an array of ints
** at a possibly unaligned location.  These are a noop on ia32
@@ -437,7 +450,7 @@ static inline __u32 type2uniqueness (int
//
static inline loff_t le_key_k_offset (int version, const struct key * key)
{
-    return (version == ITEM_VERSION_1) ?
+    return (version == KEY_FORMAT_3_5) ?
        le32_to_cpu( key->u.k_offset_v1.k_offset ) :
       offset_v2_k_offset( &(key->u.k_offset_v2) );
}
@@ -449,7 +462,7 @@ static inline loff_t le_ih_k_offset (con

static inline loff_t le_key_k_type (int version, const struct key * key)
{
-    return (version == ITEM_VERSION_1) ?
+    return (version == KEY_FORMAT_3_5) ?
        uniqueness2type( le32_to_cpu( key->u.k_offset_v1.k_uniqueness)) :
       offset_v2_k_type( &(key->u.k_offset_v2) );
}
@@ -462,20 +475,21 @@ static inline loff_t le_ih_k_type (const

static inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
{
-    (version == ITEM_VERSION_1) ?
+    (version == KEY_FORMAT_3_5) ?
        (key->u.k_offset_v1.k_offset = cpu_to_le32 (offset)) : /* jdm check */
       (set_offset_v2_k_offset( &(key->u.k_offset_v2), offset ));
}
+
+
static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
{
    set_le_key_k_offset (ih_version (ih), &(ih->ih_key), offset);
}


-
static inline void set_le_key_k_type (int version, struct key * key, int type)
{
-    (version == ITEM_VERSION_1) ?
+    (version == KEY_FORMAT_3_5) ?
        (key->u.k_offset_v1.k_uniqueness = cpu_to_le32(type2uniqueness(type))):
       (set_offset_v2_k_type( &(key->u.k_offset_v2), type ));
}
@@ -505,21 +519,21 @@ static inline void set_le_ih_k_type (str
//
static inline loff_t cpu_key_k_offset (const struct cpu_key * key)
{
-    return (key->version == ITEM_VERSION_1) ?
+    return (key->version == KEY_FORMAT_3_5) ?
        key->on_disk_key.u.k_offset_v1.k_offset :
       key->on_disk_key.u.k_offset_v2.k_offset;
}

static inline loff_t cpu_key_k_type (const struct cpu_key * key)
{
-    return (key->version == ITEM_VERSION_1) ?
+    return (key->version == KEY_FORMAT_3_5) ?
        uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
       key->on_disk_key.u.k_offset_v2.k_type;
}

static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
{
-    (key->version == ITEM_VERSION_1) ?
+    (key->version == KEY_FORMAT_3_5) ?
        (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
       (key->on_disk_key.u.k_offset_v2.k_offset = offset);
}
@@ -527,14 +541,15 @@ static inline void set_cpu_key_k_offset

static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
{
-    (key->version == ITEM_VERSION_1) ?
+    (key->version == KEY_FORMAT_3_5) ?
        (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)):
       (key->on_disk_key.u.k_offset_v2.k_type = type);
}

+
static inline void cpu_key_k_offset_dec (struct cpu_key * key)
{
-    if (key->version == ITEM_VERSION_1)
+    if (key->version == KEY_FORMAT_3_5)
       key->on_disk_key.u.k_offset_v1.k_offset --;
    else
       key->on_disk_key.u.k_offset_v2.k_offset --;
@@ -677,7 +692,7 @@ struct stat_data_v1
} __attribute__ ((__packed__));

#define SD_V1_SIZE              (sizeof(struct stat_data_v1))
-#define stat_data_v1(ih)        (ih_version (ih) == ITEM_VERSION_1)
+#define stat_data_v1(ih)        (ih_version (ih) == KEY_FORMAT_3_5)
#define sd_v1_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
#define set_sd_v1_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
#define sd_v1_nlink(sdp)        (le16_to_cpu((sdp)->sd_nlink))
@@ -731,11 +746,11 @@ struct stat_data {
  } __attribute__ ((__packed__)) u;
} __attribute__ ((__packed__));
//
-// this is 40 bytes long
+// this is 44 bytes long
//
#define SD_SIZE (sizeof(struct stat_data))
#define SD_V2_SIZE              SD_SIZE
-#define stat_data_v2(ih)        (ih_version (ih) == ITEM_VERSION_2)
+#define stat_data_v2(ih)        (ih_version (ih) == KEY_FORMAT_3_6)
#define sd_v2_mode(sdp)         (le16_to_cpu((sdp)->sd_mode))
#define set_sd_v2_mode(sdp,v)   ((sdp)->sd_mode = cpu_to_le16(v))
/* sd_reserved */
@@ -1111,9 +1126,10 @@ struct path var = {ILLEGAL_PATH_ELEMENT_

// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
#define U32_MAX (~(__u32)0)
+
static inline loff_t max_reiserfs_offset (const struct inode * inode)
{
-    if (inode_items_version (inode) == ITEM_VERSION_1)
+    if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
       return (loff_t)U32_MAX;

    return (loff_t)((~(__u64)0) >> 4);
@@ -1368,11 +1384,7 @@ extern struct item_operations * item_ops

#define COMP_KEYS comp_keys
#define COMP_SHORT_KEYS comp_short_keys
-#define keys_of_same_object comp_short_keys
-
-/*#define COMP_KEYS(p_s_key1, p_s_key2)                comp_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2))
-#define COMP_SHORT_KEYS(p_s_key1, p_s_key2)    comp_short_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2))*/
-
+/*#define keys_of_same_object comp_short_keys*/

/* number of blocks pointed to by the indirect item */
#define I_UNFM_NUM(p_s_ih)     ( ih_item_len(p_s_ih) / UNFM_P_SIZE )
@@ -1507,18 +1519,12 @@ int journal_mark_dirty_nolog(struct reis
int journal_mark_freed(struct reiserfs_transaction_handle *, struct super_block *, unsigned long blocknr) ;
int push_journal_writer(char *w) ;
int pop_journal_writer(int windex) ;
-int journal_lock_dobalance(struct super_block *p_s_sb) ;
-int journal_unlock_dobalance(struct super_block *p_s_sb) ;
int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev, unsigned long bl, int size, int searchall, unsigned long *next) ;
int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
-int journal_join(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
struct super_block *reiserfs_get_super(kdev_t dev) ;
void flush_async_commits(struct super_block *p_s_sb) ;

-int remove_from_transaction(struct super_block *p_s_sb, unsigned long blocknr, int already_cleaned) ;
-int remove_from_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_head *bh, int remove_freed) ;
-
int buffer_journaled(const struct buffer_head *bh) ;
int mark_buffer_journal_new(struct buffer_head *bh) ;
int reiserfs_sync_all_buffers(kdev_t dev, int wait) ;
@@ -1557,6 +1563,10 @@ static inline int mark_buffer_notjournal
  return 0 ;
}

+void add_save_link (struct reiserfs_transaction_handle * th,
+                                       struct inode * inode, int truncate);
+void remove_save_link (struct inode * inode, int truncate);
+
/* objectid.c */
__u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th);
void reiserfs_release_objectid (struct reiserfs_transaction_handle *th, __u32 objectid_to_release);
@@ -1594,16 +1604,16 @@ static inline int le_key_version (const

    type = offset_v2_k_type( &(key->u.k_offset_v2));
    if (type != TYPE_DIRECT && type != TYPE_INDIRECT && type != TYPE_DIRENTRY)
-       return ITEM_VERSION_1;
+       return KEY_FORMAT_3_5;

-    return ITEM_VERSION_2;
+    return KEY_FORMAT_3_6;

}


static inline void copy_key (struct key *to, const struct key *from)
{
-  memcpy (to, from, KEY_SIZE);
+    memcpy (to, from, KEY_SIZE);
}


@@ -1647,7 +1657,8 @@ int reiserfs_delete_item (struct reiserf
                         struct inode * inode,
                         struct buffer_head  * p_s_un_bh);

-
+void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
+                                                                struct key * key);
void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
                          struct  inode * p_s_inode, struct page *,
diff -rup -X dontdiff linux/include/linux/reiserfs_fs_i.h linux.patched/include/linux/reiserfs_fs_i.h
--- linux/include/linux/reiserfs_fs_i.h Wed Nov 21 15:23:20 2001
+++ linux.patched/include/linux/reiserfs_fs_i.h Wed Nov 21 15:21:36 2001
@@ -3,50 +3,47 @@

#include <linux/list.h>

+/** bitmasks for i_flags field in reiserfs-specific part of inode */
+typedef enum {
+    /** this says what format of key do all items (but stat data) of
+       an object have.  If this is set, that format is 3.6 otherwise
+       - 3.5 */
+    i_item_key_version_mask    =  0x0001,
+    /** If this is unset, object has 3.5 stat data, otherwise, it has
+       3.6 stat data with 64bit size, 32bit nlink etc. */
+    i_stat_data_version_mask   =  0x0002,
+    /** file might need tail packing on close */
+    i_pack_on_close_mask       =  0x0004,
+    /** don't pack tail of file */
+    i_nopack_mask              =  0x0008,
+    /** If those is set, "safe link" was created for this file during
+       truncate or unlink. Safe link is used to avoid leakage of disk
+       space on crash with some files open, but unlinked. */
+    i_link_saved_unlink_mask   =  0x0010,
+    i_link_saved_truncate_mask =  0x0020
+} reiserfs_inode_flags;
+
+
struct reiserfs_inode_info {
-  __u32 i_key [4];/* key is still 4 32 bit integers */
+    __u32 i_key [4];/* key is still 4 32 bit integers */

-                               /* this comment will be totally
-                                   cryptic to readers not familiar
-                                   with 3.5/3.6 format conversion, and
-                                   it does not consider that that 3.6
-                                   might not be the last version */
-  int i_version;  // this says whether file is old or new
-
-  int i_pack_on_close ; // file might need tail packing on close
-
-  __u32 i_first_direct_byte; // offset of first byte stored in direct item.
-
-                               /* My guess is this contains the first
-                                   unused block of a sequence of
-                                   blocks plus the length of the
-                                   sequence, which I think is always
-                                   at least two at the time of the
-                                   preallocation.  I really prefer
-                                   allocate on flush conceptually.....
-
-                                  You know, it really annoys me when
-                                  code is this badly commented that I
-                                  have to guess what it does.
-                                  Neither I nor anyone else has time
-                                  for guessing what your
-                                  datastructures mean.  -Hans */
-  //For preallocation
-  int i_prealloc_block;
-  int i_prealloc_count;
-  struct list_head i_prealloc_list;    /* per-transaction list of inodes which
-                                * have preallocated blocks */
-                               /* I regret that you think the below
-                                   is a comment you should make.... -Hans */
-  //nopack-attribute
-  int nopack;
+    /** transient inode flags that are never stored on disk. Bitmasks
+       for this field are defined above. */
+    __u32 i_flags;
+
+    __u32 i_first_direct_byte; // offset of first byte stored in direct item.
+
+    int i_prealloc_block; /* first unused block of a sequence of unused blocks */
+    int i_prealloc_count; /* length of that sequence */
+    struct list_head i_prealloc_list;  /* per-transaction list of inodes which
+                                        * have preallocated blocks */

-  /* we use these for fsync or O_SYNC to decide which transaction needs
-  ** to be committed in order for this inode to be properly flushed
-  */
-  unsigned long i_trans_id ;
-  unsigned long i_trans_index ;
+    /* we use these for fsync or O_SYNC to decide which transaction
+    ** needs to be committed in order for this inode to be properly
+    ** flushed */
+    unsigned long i_trans_id ;
+    unsigned long i_trans_index ;
};

-
#endif
+