diff -rup linux/fs/reiserfs/dir.c linux.patched/fs/reiserfs/dir.c --- linux/fs/reiserfs/dir.c Wed Nov 14 15:18:52 2001 +++ linux.patched/fs/reiserfs/dir.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/file.c linux.patched/fs/reiserfs/file.c --- linux/fs/reiserfs/file.c Wed Nov 14 15:18:52 2001 +++ linux.patched/fs/reiserfs/file.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/inode.c linux.patched/fs/reiserfs/inode.c --- linux/fs/reiserfs/inode.c Wed Nov 14 15:18:52 2001 +++ linux.patched/fs/reiserfs/inode.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/ioctl.c linux.patched/fs/reiserfs/ioctl.c --- linux/fs/reiserfs/ioctl.c Sat Sep 8 23:05:32 2001 +++ linux.patched/fs/reiserfs/ioctl.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/journal.c linux.patched/fs/reiserfs/journal.c --- linux/fs/reiserfs/journal.c Wed Nov 14 15:18:52 2001 +++ linux.patched/fs/reiserfs/journal.c Wed Nov 14 15:53:37 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 linux/fs/reiserfs/lbalance.c linux.patched/fs/reiserfs/lbalance.c --- linux/fs/reiserfs/lbalance.c Wed Oct 31 02:11:34 2001 +++ linux.patched/fs/reiserfs/lbalance.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/namei.c linux.patched/fs/reiserfs/namei.c --- linux/fs/reiserfs/namei.c Wed Nov 14 15:18:52 2001 +++ linux.patched/fs/reiserfs/namei.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/objectid.c linux.patched/fs/reiserfs/objectid.c --- linux/fs/reiserfs/objectid.c Wed Nov 14 15:18:29 2001 +++ linux.patched/fs/reiserfs/objectid.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/prints.c linux.patched/fs/reiserfs/prints.c --- linux/fs/reiserfs/prints.c Wed Nov 14 15:18:29 2001 +++ linux.patched/fs/reiserfs/prints.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/stree.c linux.patched/fs/reiserfs/stree.c --- linux/fs/reiserfs/stree.c Wed Nov 14 15:18:52 2001 +++ linux.patched/fs/reiserfs/stree.c Wed Nov 14 15:25:05 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 linux/fs/reiserfs/super.c linux.patched/fs/reiserfs/super.c --- linux/fs/reiserfs/super.c Wed Nov 14 15:18:52 2001 +++ linux.patched/fs/reiserfs/super.c Wed Nov 14 15:25:05 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 @@ -767,6 +1006,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 +1101,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 linux/fs/reiserfs/tail_conversion.c linux.patched/fs/reiserfs/tail_conversion.c --- linux/fs/reiserfs/tail_conversion.c Wed Oct 31 02:11:34 2001 +++ linux.patched/fs/reiserfs/tail_conversion.c Wed Nov 14 15:25:05 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. diff -rup linux/include/linux/reiserfs_fs.h linux.patched/include/linux/reiserfs_fs.h --- linux/include/linux/reiserfs_fs.h Wed Nov 14 15:18:52 2001 +++ linux.patched/include/linux/reiserfs_fs.h Wed Nov 14 15:50:29 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 linux/include/linux/reiserfs_fs_i.h linux.patched/include/linux/reiserfs_fs_i.h --- linux/include/linux/reiserfs_fs_i.h Mon Nov 5 23:42:13 2001 +++ linux.patched/include/linux/reiserfs_fs_i.h Wed Nov 14 15:42:15 2001 @@ -3,50 +3,47 @@ #include +/** 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 + .