diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/buffer.c linux/fs/buffer.c --- linux.0.18/fs/buffer.c Wed Nov 28 14:26:13 2001 +++ linux/fs/buffer.c Wed Dec 5 08:18:43 2001 @@ -1353,7 +1353,7 @@ /* * Called when truncating a buffer on a page completely. */ -static void discard_buffer(struct buffer_head * bh) +void discard_buffer(struct buffer_head * bh) { if (buffer_mapped(bh)) { mark_buffer_clean(bh); diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/intermezzo/journal_reiserfs.c linux/fs/intermezzo/journal_reiserfs.c --- linux.0.18/fs/intermezzo/journal_reiserfs.c Wed Nov 28 14:24:49 2001 +++ linux/fs/intermezzo/journal_reiserfs.c Wed Dec 5 08:18:43 2001 @@ -20,7 +20,6 @@ #include #include #include -#if 0 #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) #include #include @@ -83,7 +82,8 @@ CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks); lock_kernel(); - //journal_begin(th, inode->i_sb, jblocks); + journal_begin(th, inode->i_sb, jblocks); + reiserfs_set_handle_restartable(th) ; unlock_kernel(); return th; } @@ -91,21 +91,23 @@ void presto_reiserfs_trans_commit(struct presto_file_set *fset, void *handle) { int jblocks; + struct reiserfs_transaction_handle *th ; + jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4; lock_kernel(); - //journal_end(handle, fset->fset_cache->cache_sb, jblocks); + th = handle ; + if (th->t_refcount != 1) { + BUG() ; + } + journal_end(handle, fset->fset_cache->cache_sb, jblocks); unlock_kernel(); PRESTO_FREE(handle, sizeof(struct reiserfs_transaction_handle)); } void presto_reiserfs_journal_file_data(struct inode *inode) { -#ifdef EXT3_JOURNAL_DATA_FL - inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL; -#else -#warning You must have a facility to enable journaled writes for recovery! -#endif + inode->u.reiserfs_i.i_data_mode |= REISERFS_FILE_DATA_LOG ; } struct journal_ops presto_reiserfs_journal_ops = { @@ -115,5 +117,4 @@ tr_journal_data: presto_reiserfs_journal_file_data }; -#endif #endif diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/intermezzo/methods.c linux/fs/intermezzo/methods.c --- linux.0.18/fs/intermezzo/methods.c Wed Nov 28 14:25:33 2001 +++ linux/fs/intermezzo/methods.c Wed Dec 5 08:18:43 2001 @@ -152,8 +152,7 @@ if ( strlen(cache_type) == strlen("reiserfs") && memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) { -#if 0 - /* #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) */ +#if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE) ops->o_trops = &presto_reiserfs_journal_ops; #else ops->o_trops = NULL; diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/Makefile linux/fs/reiserfs/Makefile --- linux.0.18/fs/reiserfs/Makefile Wed Nov 28 14:26:13 2001 +++ linux/fs/reiserfs/Makefile Wed Dec 5 08:18:43 2001 @@ -7,6 +7,7 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +export-objs := super.o O_TARGET := reiserfs.o obj-y := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o super.o prints.o objectid.o \ lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o version.o item_ops.o ioctl.o procfs.o diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/file.c linux/fs/reiserfs/file.c --- linux.0.18/fs/reiserfs/file.c Wed Nov 7 12:20:37 2001 +++ linux/fs/reiserfs/file.c Wed Dec 5 08:18:43 2001 @@ -100,6 +100,17 @@ if (inode_items_version(inode) == ITEM_VERSION_1 && attr->ia_size > MAX_NON_LFS) return -EFBIG ; + + /* During a truncate, we have to make sure the new i_size is in + ** the transaction before we start dropping updates to data logged + ** or ordered write data pages. + */ + if (attr->ia_size < inode->i_size && reiserfs_file_data_log(inode)) { + struct reiserfs_transaction_handle th ; + journal_begin(&th, inode->i_sb, 1) ; + reiserfs_update_sd_size(&th, inode, attr->ia_size) ; + journal_end(&th, inode->i_sb, 1) ; + } } error = inode_change_ok(inode, attr) ; diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c --- linux.0.18/fs/reiserfs/fix_node.c Wed Nov 28 14:24:49 2001 +++ linux/fs/reiserfs/fix_node.c Wed Dec 5 08:18:43 2001 @@ -2131,7 +2131,8 @@ static void clear_all_dirty_bits(struct super_block *s, struct buffer_head *bh) { - reiserfs_prepare_for_journal(s, bh, 0) ; + // reiserfs_prepare_for_journal(s, bh, 0) ; + set_bit(BH_JPrepared, &bh->b_state) ; } static int wait_tb_buffers_until_unlocked (struct tree_balance * p_s_tb) diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c --- linux.0.18/fs/reiserfs/inode.c Wed Nov 7 12:24:31 2001 +++ linux/fs/reiserfs/inode.c Wed Dec 5 08:18:43 2001 @@ -17,6 +17,8 @@ #define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */ #define GET_BLOCK_NO_ISEM 8 /* i_sem is not held, don't preallocate */ +static int reiserfs_commit_write(struct file *, struct page *, + unsigned from, unsigned to) ; // // initially this function was derived from minix or ext2's analog and // evolved as the prototype did @@ -224,15 +226,15 @@ return 0; } -/*static*/ void restart_transaction(struct reiserfs_transaction_handle *th, +static void restart_transaction(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *path) { - struct super_block *s = th->t_super ; - int len = th->t_blocks_allocated ; - + /* we cannot restart while nested unless the parent allows it */ + if (!reiserfs_restartable_handle(th) && th->t_refcount > 1) { + return ; + } pathrelse(path) ; reiserfs_update_sd(th, inode) ; - journal_end(th, s, len) ; - journal_begin(th, s, len) ; + reiserfs_restart_transaction(th) ; reiserfs_update_inode_transaction(inode) ; } @@ -439,7 +441,6 @@ struct buffer_head *bh_result, loff_t tail_offset) { unsigned long index ; - unsigned long tail_end ; unsigned long tail_start ; struct page * tail_page ; struct page * hole_page = bh_result->b_page ; @@ -450,7 +451,6 @@ /* always try to read until the end of the block */ tail_start = tail_offset & (PAGE_CACHE_SIZE - 1) ; - tail_end = (tail_start | (bh_result->b_size - 1)) + 1 ; index = tail_offset >> PAGE_CACHE_SHIFT ; if (index != hole_page->index) { @@ -472,16 +472,13 @@ ** data that has been read directly into the page, and block_prepare_write ** won't trigger a get_block in this case. */ - fix_tail_page_for_writing(tail_page) ; - retval = block_prepare_write(tail_page, tail_start, tail_end, - reiserfs_get_block) ; + retval = reiserfs_prepare_write(NULL, tail_page, tail_start, tail_start) ; if (retval) goto unlock ; /* tail conversion might change the data in the page */ flush_dcache_page(tail_page) ; - - retval = generic_commit_write(NULL, tail_page, tail_start, tail_end) ; + retval = reiserfs_commit_write(NULL, tail_page, tail_start, tail_start) ; unlock: if (tail_page != hole_page) { @@ -526,7 +523,7 @@ int done; int fs_gen; int windex ; - struct reiserfs_transaction_handle th ; + struct reiserfs_transaction_handle *th = NULL ; /* space reserved in transaction batch: . 3 balancings in direct->indirect conversion . 1 block involved into reiserfs_update_sd() @@ -534,12 +531,10 @@ can incur (much) more that 3 balancings. */ int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1; int version; - int transaction_started = 0 ; loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; /* bad.... */ lock_kernel() ; - th.t_trans_id = 0 ; version = inode_items_version (inode); if (block < 0) { @@ -564,17 +559,23 @@ return ret; } - inode->u.reiserfs_i.i_pack_on_close = 1 ; - windex = push_journal_writer("reiserfs_get_block") ; /* set the key of the first byte in the 'block'-th block of file */ make_cpu_key (&key, inode, new_offset, TYPE_ANY, 3/*key length*/); + + /* reiserfs_commit_write will close any transaction currently + ** running. So, if we are nesting into someone else, we have to + ** make sure and bump the refcount + */ if ((new_offset + inode->i_sb->s_blocksize - 1) > inode->i_size) { - journal_begin(&th, inode->i_sb, jbegin_count) ; + th = reiserfs_persistent_transaction(inode->i_sb, jbegin_count) ; + if (IS_ERR(th)) { + retval = PTR_ERR(th) ; + goto failure ; + } reiserfs_update_inode_transaction(inode) ; - transaction_started = 1 ; } research: @@ -595,23 +596,26 @@ if (allocation_needed (retval, allocated_block_nr, ih, item, pos_in_item)) { /* we have to allocate block for the unformatted node */ tag = find_tag (bh, ih, item, pos_in_item); - if (!transaction_started) { + if (!reiserfs_active_handle(th)) { pathrelse(&path) ; - journal_begin(&th, inode->i_sb, jbegin_count) ; + th = reiserfs_persistent_transaction(inode->i_sb, jbegin_count) ; + if (IS_ERR(th)) { + retval = PTR_ERR(th) ; + goto failure ; + } reiserfs_update_inode_transaction(inode) ; - transaction_started = 1 ; goto research ; } - repeat = _allocate_block(&th, inode, &allocated_block_nr, tag, create); + repeat = _allocate_block(th, inode, &allocated_block_nr, tag, create); if (repeat == NO_DISK_SPACE) { /* restart the transaction to give the journal a chance to free ** some blocks. releases the path, so we have to go back to ** research if we succeed on the second try */ - restart_transaction(&th, inode, &path) ; - repeat = _allocate_block(&th, inode,&allocated_block_nr,tag,create); + restart_transaction(th, inode, &path) ; + repeat = _allocate_block(th, inode,&allocated_block_nr,tag,create); if (repeat != NO_DISK_SPACE) { goto research ; @@ -641,16 +645,18 @@ bh_result->b_state |= (1UL << BH_New); put_block_num(item, pos_in_item, allocated_block_nr) ; unfm_ptr = allocated_block_nr; - journal_mark_dirty (&th, inode->i_sb, bh); + journal_mark_dirty (th, inode->i_sb, bh); inode->i_blocks += (inode->i_sb->s_blocksize / 512) ; - reiserfs_update_sd(&th, inode) ; + reiserfs_update_sd(th, inode) ; } set_block_dev_mapped(bh_result, unfm_ptr, inode); pathrelse (&path); pop_journal_writer(windex) ; - if (transaction_started) - journal_end(&th, inode->i_sb, jbegin_count) ; +#if 0 + if (transaction_started) + journal_end(th, inode->i_sb, jbegin_count) ; +#endif unlock_kernel() ; /* the item was found, so new blocks were not added to the file @@ -660,15 +666,18 @@ return 0; } - if (!transaction_started) { + if (!reiserfs_active_handle(th)) { /* if we don't pathrelse, we could vs-3050 on the buffer if ** someone is waiting for it (they can't finish until the buffer - ** is released, we can start a new transaction until they finish) + ** is released, we can't start a new transaction until they finish) */ pathrelse(&path) ; - journal_begin(&th, inode->i_sb, jbegin_count) ; + th = reiserfs_persistent_transaction(inode->i_sb, jbegin_count) ; + if (IS_ERR(th)) { + retval = PTR_ERR(th) ; + goto failure ; + } reiserfs_update_inode_transaction(inode) ; - transaction_started = 1 ; goto research; } @@ -697,9 +706,9 @@ set_cpu_key_k_offset (&tmp_key, 1); PATH_LAST_POSITION(&path) ++; - retval = reiserfs_insert_item (&th, &path, &tmp_key, &tmp_ih, (char *)&unp); + retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, (char *)&unp); if (retval) { - reiserfs_free_block (&th, allocated_block_nr); + reiserfs_free_block (th, allocated_block_nr); goto failure; // retval == -ENOSPC or -EIO or -EEXIST } if (unp) @@ -723,19 +732,24 @@ node. FIXME: this should also get into page cache */ pathrelse(&path) ; - journal_end(&th, inode->i_sb, jbegin_count) ; - transaction_started = 0 ; + /* ugly, but we should only end the transaction if + ** we aren't nested + */ + if (th->t_refcount == 1) { + journal_end(th, inode->i_sb, jbegin_count) ; + th = NULL ; + } retval = convert_tail_for_hole(inode, bh_result, tail_offset) ; if (retval) { printk("clm-6004: convert tail failed inode %lu, error %d\n", inode->i_ino, retval) ; if (allocated_block_nr) - reiserfs_free_block (&th, allocated_block_nr); + reiserfs_free_block (th, allocated_block_nr); goto failure ; } goto research ; } - retval = direct2indirect (&th, inode, &path, unbh, tail_offset); + retval = direct2indirect (th, inode, &path, unbh, tail_offset); /* it is important the mark_buffer_uptodate is done after ** the direct2indirect. The buffer might contain valid ** data newer than the data on disk (read by readpage, changed, @@ -746,18 +760,23 @@ */ mark_buffer_uptodate (unbh, 1); if (retval) { - reiserfs_free_block (&th, allocated_block_nr); + reiserfs_free_block (th, allocated_block_nr); goto failure; } /* we've converted the tail, so we must ** flush unbh before the transaction commits */ - add_to_flushlist(inode, unbh) ; + if (reiserfs_file_data_log(inode)) { + reiserfs_prepare_for_journal(inode->i_sb, unbh, 1) ; + journal_mark_dirty(th, inode->i_sb, unbh) ; + } else { + add_to_flushlist(inode, unbh) ; - /* mark it dirty now to prevent commit_write from adding - ** this buffer to the inode's dirty buffer list - */ - __mark_buffer_dirty(unbh) ; + /* mark it dirty now to prevent commit_write from adding + ** this buffer to the inode's dirty buffer list + */ + __mark_buffer_dirty(unbh) ; + } //inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); @@ -786,9 +805,9 @@ } else { /* paste hole to the indirect item */ } - retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)&un, UNFM_P_SIZE); + retval = reiserfs_paste_into_item (th, &path, &tmp_key, (char *)&un, UNFM_P_SIZE); if (retval) { - reiserfs_free_block (&th, allocated_block_nr); + reiserfs_free_block (th, allocated_block_nr); goto failure; } if (un.unfm_nodenum) @@ -807,8 +826,8 @@ ** release the path so that anybody waiting on the path before ** ending their transaction will be able to continue. */ - if (journal_transaction_should_end(&th, th.t_blocks_allocated)) { - restart_transaction(&th, inode, &path) ; + if (journal_transaction_should_end(th, th->t_blocks_allocated)) { + restart_transaction(th, inode, &path) ; } /* inserting indirect pointers for a hole can take a ** long time. reschedule if needed @@ -826,7 +845,7 @@ "%k should not be found\n", &key); retval = -EEXIST; if (allocated_block_nr) - reiserfs_free_block (&th, allocated_block_nr); + reiserfs_free_block (th, allocated_block_nr); pathrelse(&path) ; goto failure; } @@ -841,11 +860,17 @@ reiserfs_check_path(&path) ; failure: - if (transaction_started) { - reiserfs_update_sd(&th, inode) ; - journal_end(&th, inode->i_sb, jbegin_count) ; + /* if we had an error, end the transaction */ + if (retval != 0 && !IS_ERR(th) && reiserfs_active_handle(th)) { + reiserfs_update_sd(th, inode) ; + journal_end(th, inode->i_sb, jbegin_count) ; + th = NULL ; } pop_journal_writer(windex) ; + if (retval == 0 && reiserfs_active_handle(th) && + current->journal_info != th) { + BUG() ; + } unlock_kernel() ; reiserfs_check_path(&path) ; return retval; @@ -956,14 +981,14 @@ // update new stat data with inode fields -static void inode2sd (void * sd, struct inode * inode) +static void inode2sd (void * sd, struct inode * inode, loff_t new_size) { struct stat_data * sd_v2 = (struct stat_data *)sd; set_sd_v2_mode(sd_v2, inode->i_mode ); set_sd_v2_nlink(sd_v2, inode->i_nlink ); set_sd_v2_uid(sd_v2, inode->i_uid ); - set_sd_v2_size(sd_v2, inode->i_size ); + set_sd_v2_size(sd_v2, new_size); set_sd_v2_gid(sd_v2, inode->i_gid ); set_sd_v2_mtime(sd_v2, inode->i_mtime ); set_sd_v2_atime(sd_v2, inode->i_atime ); @@ -980,7 +1005,7 @@ // used to copy inode's fields to old stat data -static void inode2sd_v1 (void * sd, struct inode * inode) +static void inode2sd_v1 (void * sd, struct inode * inode, loff_t new_size) { struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd; @@ -988,7 +1013,7 @@ set_sd_v1_uid(sd_v1, inode->i_uid ); set_sd_v1_gid(sd_v1, inode->i_gid ); set_sd_v1_nlink(sd_v1, inode->i_nlink ); - set_sd_v1_size(sd_v1, inode->i_size ); + set_sd_v1_size(sd_v1, new_size); set_sd_v1_atime(sd_v1, inode->i_atime ); set_sd_v1_ctime(sd_v1, inode->i_ctime ); set_sd_v1_mtime(sd_v1, inode->i_mtime ); @@ -1006,7 +1031,8 @@ /* NOTE, you must prepare the buffer head before sending it here, ** and then log it after the call */ -static void update_stat_data (struct path * path, struct inode * inode) +static void update_stat_data (struct path * path, struct inode * inode, + loff_t new_size) { struct buffer_head * bh; struct item_head * ih; @@ -1020,17 +1046,16 @@ if (stat_data_v1 (ih)) { // path points to old stat data - inode2sd_v1 (B_I_PITEM (bh, ih), inode); + inode2sd_v1 (B_I_PITEM (bh, ih), inode, new_size); } else { - inode2sd (B_I_PITEM (bh, ih), inode); + inode2sd (B_I_PITEM (bh, ih), inode, new_size); } return; } - -void reiserfs_update_sd (struct reiserfs_transaction_handle *th, - struct inode * inode) +void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th, + struct inode *inode, loff_t new_size) { struct cpu_key key; INITIALIZE_PATH(path); @@ -1080,7 +1105,7 @@ } break; } - update_stat_data (&path, inode); + update_stat_data (&path, inode, new_size); journal_mark_dirty(th, th->t_super, bh) ; pathrelse (&path); return; @@ -1513,9 +1538,9 @@ INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ; if (old_format_only (sb)) - inode2sd_v1 (&sd, inode); + inode2sd_v1 (&sd, inode, inode->i_size); else - inode2sd (&sd, inode); + inode2sd (&sd, inode, inode->i_size); // these do not go to on-disk stat data inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid); @@ -1669,6 +1694,7 @@ unsigned length ; struct page *page = NULL ; int error ; + int need_balance_dirty = 0 ; struct buffer_head *bh = NULL ; if (p_s_inode->i_size > 0) { @@ -1695,7 +1721,6 @@ windex = push_journal_writer("reiserfs_vfs_truncate_file") ; 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 ) ; if (page) { length = offset & (blocksize - 1) ; @@ -1706,13 +1731,27 @@ flush_dcache_page(page) ; kunmap(page) ; if (buffer_mapped(bh) && bh->b_blocknr != 0) { - mark_buffer_dirty(bh) ; + if (reiserfs_file_data_log(p_s_inode)) { + reiserfs_prepare_for_journal(p_s_inode->i_sb, bh, 1) ; + journal_mark_dirty(&th, p_s_inode->i_sb, bh) ; + } else { + /* it is safe to block here, but it would be faster + ** to balance dirty after the journal lock is dropped + */ + __mark_buffer_dirty(bh) ; + need_balance_dirty = 1; + } } } + } + journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; + if (page) { UnlockPage(page) ; page_cache_release(page) ; } - + if (need_balance_dirty) { + balance_dirty() ; + } return ; } @@ -1807,11 +1846,26 @@ /* this is where we fill in holes in the file. */ if (use_get_block) { + int old_refcount = 0 ; + struct reiserfs_transaction_handle *th ; kmap(bh_result->b_page) ; + if (reiserfs_transaction_running(inode->i_sb)) { + th = current->journal_info ; + old_refcount = th->t_refcount ; + } retval = reiserfs_get_block(inode, block, bh_result, GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM) ; kunmap(bh_result->b_page) ; if (!retval) { + /* did reiserfs_get_block leave us a running transaction? */ + if (reiserfs_transaction_running(inode->i_sb)) { + th = current->journal_info ; + if (old_refcount < th->t_refcount) { + lock_kernel() ; + journal_end(th, th->t_super, th->t_blocks_allocated) ; + unlock_kernel() ; + } + } if (!buffer_mapped(bh_result) || bh_result->b_blocknr == 0) { /* get_block failed to find a mapped unformatted node. */ use_get_block = 0 ; @@ -1825,20 +1879,37 @@ /* helper func to get a buffer head ready for writepage to send to ** ll_rw_block */ -static inline void submit_bh_for_writepage(struct buffer_head **bhp, int nr) { +static void submit_bh_for_writepage(struct page *page, + struct buffer_head **bhp, int nr) { struct buffer_head *bh ; + struct inode *inode = page->mapping->host ; + struct super_block *sb = inode->i_sb ; + struct reiserfs_transaction_handle th ; int i; + + th.t_flags = 0 ; + if (reiserfs_file_data_log(inode)) { + journal_begin(&th, sb, nr) ; + } for(i = 0 ; i < nr ; i++) { bh = bhp[i] ; - lock_buffer(bh) ; - set_buffer_async_io(bh) ; - /* submit_bh doesn't care if the buffer is dirty, but nobody - ** later on in the call chain will be cleaning it. So, we - ** clean the buffer here, it still gets written either way. - */ - clear_bit(BH_Dirty, &bh->b_state) ; - set_bit(BH_Uptodate, &bh->b_state) ; - submit_bh(WRITE, bh) ; + if (reiserfs_active_handle(&th)) { + reiserfs_prepare_for_journal(sb, bh, 1) ; + journal_mark_dirty(&th, sb, bh) ; + } else { + lock_buffer(bh) ; + set_buffer_async_io(bh) ; + /* submit_bh doesn't care if the buffer is dirty, but nobody + ** later on in the call chain will be cleaning it. So, we + ** clean the buffer here, it still gets written either way. + */ + clear_bit(BH_Dirty, &bh->b_state) ; + set_bit(BH_Uptodate, &bh->b_state) ; + submit_bh(WRITE, bh) ; + } + } + if (reiserfs_active_handle(&th)) { + journal_end(&th, sb, nr) ; } } @@ -1909,7 +1980,7 @@ ** nr == 0 without there being any kind of error. */ if (nr) { - submit_bh_for_writepage(arr, nr) ; + submit_bh_for_writepage(page, arr, nr) ; } else { UnlockPage(page) ; } @@ -1920,7 +1991,7 @@ fail: if (nr) { - submit_bh_for_writepage(arr, nr) ; + submit_bh_for_writepage(page, arr, nr) ; } else { UnlockPage(page) ; } @@ -1953,10 +2024,36 @@ // int reiserfs_prepare_write(struct file *f, struct page *page, unsigned from, unsigned to) { + int cur_refcount = 0 ; + int ret ; struct inode *inode = page->mapping->host ; + struct reiserfs_transaction_handle *th ; + reiserfs_wait_on_write_block(inode->i_sb) ; fix_tail_page_for_writing(page) ; - return block_prepare_write(page, from, to, reiserfs_get_block) ; + + /* we look for a running transaction before the block_prepare_write + ** call, and then again afterwards. This lets us know if + ** reiserfs_get_block added any additional transactions, so we can + ** let reiserfs_commit_write know if he needs to close them. + ** this is just nasty + */ + if (reiserfs_transaction_running(inode->i_sb)) { + th = current->journal_info ; + cur_refcount = th->t_refcount ; + } + ret = block_prepare_write(page, from, to, reiserfs_get_block) ; + + /* it is very important that we only set the dangling bit when + ** there is no chance of additional nested transactions. + */ + if (reiserfs_transaction_running(inode->i_sb)) { + th = current->journal_info ; + if (th->t_refcount > cur_refcount) { + reiserfs_set_handle_dangling(th) ; + } + } + return ret ; } @@ -1967,35 +2064,118 @@ return generic_block_bmap(as, block, reiserfs_bmap) ; } +/* taken from fs/buffer.c */ +static int __commit_write(struct reiserfs_transaction_handle *th, + struct inode *inode, struct page *page, + unsigned from, unsigned to) +{ + unsigned block_start, block_end; + int partial = 0, need_balance_dirty = 0; + unsigned blocksize; + struct buffer_head *bh, *head; + int logbh = 0 ; + + blocksize = 1 << inode->i_blkbits; + if (reiserfs_file_data_log(inode)) { + logbh = 1 ; + lock_kernel() ; + /* one for each block + the stat data, the caller closes the handle */ + journal_begin(th, inode->i_sb,(PAGE_CACHE_SIZE >> inode->i_blkbits)+1); + unlock_kernel() ; + } + + for(bh = head = page->buffers, block_start = 0; + bh != head || !block_start; + block_start=block_end, bh = bh->b_this_page) { + block_end = block_start + blocksize; + if (block_end <= from || block_start >= to) { + if (!buffer_uptodate(bh)) + partial = 1; + } else { + set_bit(BH_Uptodate, &bh->b_state); + if (logbh) { + lock_kernel() ; + reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ; + journal_mark_dirty (th, inode->i_sb, bh); + unlock_kernel() ; + } else if (!atomic_set_buffer_dirty(bh)) { + __mark_dirty(bh); + buffer_insert_inode_data_queue(bh, inode); + need_balance_dirty = 1; + } + } + } + + if (need_balance_dirty) + balance_dirty(); + /* + * is this a partial write that happened to make all buffers + * uptodate then we can optimize away a bogus readpage() for + * the next read(). Here we 'discover' wether the page went + * uptodate as a result of this (potentially partial) write. + */ + if (!partial) + SetPageUptodate(page); + return 0; +} + static int reiserfs_commit_write(struct file *f, struct page *page, unsigned from, unsigned to) { struct inode *inode = page->mapping->host ; loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; int ret ; + struct reiserfs_transaction_handle th ; + struct reiserfs_transaction_handle *dth = NULL ; + /* we must do this before anything that might nest a transaction or + ** mess with the handle flags + */ + if (reiserfs_transaction_running(inode->i_sb)) { + dth = current->journal_info ; + if (reiserfs_dangling_handle(dth)) { + reiserfs_clear_handle_dangling(dth) ; + } else { + dth = NULL ; + } + } reiserfs_wait_on_write_block(inode->i_sb) ; + + th.t_flags = 0 ; + ret = __commit_write(&th, inode, page, from, to) ; - /* generic_commit_write does this for us, but does not update the - ** transaction tracking stuff when the size changes. So, we have - ** to do the i_size updates here. - */ if (pos > inode->i_size) { - struct reiserfs_transaction_handle th ; lock_kernel() ; - journal_begin(&th, inode->i_sb, 1) ; + if (!reiserfs_active_handle(&th)) { + journal_begin(&th, inode->i_sb, 1) ; + } reiserfs_update_inode_transaction(inode) ; inode->i_size = pos ; reiserfs_update_sd(&th, inode) ; - journal_end(&th, inode->i_sb, 1) ; + journal_end(&th, th.t_super, th.t_blocks_allocated) ; + unlock_kernel() ; + } else if (reiserfs_active_handle(&th)) { + /* in case commit_write left one running and the i_size update did + ** not close it + */ + lock_kernel() ; + journal_end(&th, th.t_super, th.t_blocks_allocated) ; + unlock_kernel() ; + } + + /* did reiserfs_get_block leave us with a running transaction? + */ + if (dth) { + lock_kernel() ; + journal_end(dth, dth->t_super, dth->t_blocks_allocated) ; unlock_kernel() ; } - ret = generic_commit_write(f, page, from, to) ; + kunmap(page) ; /* we test for O_SYNC here so we can commit the transaction ** for any packed tails the file might have had */ - if (f->f_flags & O_SYNC) { + if (f && f->f_flags & O_SYNC) { lock_kernel() ; reiserfs_commit_for_inode(inode) ; unlock_kernel(); @@ -2003,11 +2183,82 @@ return ret ; } +/* decide if this buffer needs to stay around for data logging or ordered +** write purposes +*/ +static int flushpage_can_drop(struct inode *inode, struct buffer_head *bh) { + int ret = 1 ; + + if (!buffer_mapped(bh)) { + return 1 ; + } + if (reiserfs_file_data_log(inode)) { + lock_kernel() ; + /* very conservative, leave the buffer pinned if anyone might need it. + ** this should be changed to drop the buffer if it is only in the + ** current transaction + */ + if (buffer_journaled(bh) || buffer_journal_dirty(bh)) { + ret = 0 ; + } + unlock_kernel() ; + } + return ret ; +} + +/* stolen from fs/buffer.c:discard_bh_page */ +static int reiserfs_flushpage(struct page *page, unsigned long offset) { + struct buffer_head *head, *bh, *next; + struct inode *inode = page->mapping->host ; + unsigned int curr_off = 0; + int ret = 1; + + if (!PageLocked(page)) + BUG(); + if (!page->buffers) + return 1; + + head = page->buffers; + bh = head; + do { + unsigned int next_off = curr_off + bh->b_size; + next = bh->b_this_page; + + /* is this buffer to be completely truncated away? */ + if (offset <= curr_off) { + if (flushpage_can_drop(inode, bh)) + discard_buffer(bh); + else + ret = 0 ; + } + curr_off = next_off; + bh = next; + } while (bh != head); + + /* + * subtle. We release buffer-heads only if this is + * the 'final' flushpage. We have invalidated the get_block + * cached value unconditionally, so real IO is not + * possible anymore. + * + * If the free doesn't work out, the buffers can be + * left around - they just turn into anonymous buffers + * instead. + */ + if (!offset) { + if (!try_to_release_page(page, 0)) + return 0; + } + + return ret ; +} + struct address_space_operations reiserfs_address_space_operations = { writepage: reiserfs_writepage, readpage: reiserfs_readpage, sync_page: block_sync_page, prepare_write: reiserfs_prepare_write, commit_write: reiserfs_commit_write, - bmap: reiserfs_aop_bmap + bmap: reiserfs_aop_bmap, + flushpage: reiserfs_flushpage, } ; diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/ioctl.c linux/fs/reiserfs/ioctl.c --- linux.0.18/fs/reiserfs/ioctl.c Wed Nov 7 12:20:37 2001 +++ linux/fs/reiserfs/ioctl.c Wed Dec 5 08:18:43 2001 @@ -39,6 +39,7 @@ int retval = 0; int index ; struct page *page ; + struct address_space *mapping ; unsigned long write_from ; unsigned long blocksize = inode->i_sb->s_blocksize ; @@ -68,19 +69,20 @@ ** reiserfs_get_block to unpack the tail for us. */ index = inode->i_size >> PAGE_CACHE_SHIFT ; - page = grab_cache_page(inode->i_mapping, index) ; + mapping = inode->i_mapping ; + page = grab_cache_page(mapping, index) ; retval = -ENOMEM; if (!page) { goto out ; } - retval = reiserfs_prepare_write(NULL, page, write_from, blocksize) ; + retval = mapping->a_ops->prepare_write(NULL, page, write_from, write_from) ; if (retval) goto out_unlock ; /* conversion can change page contents, must flush */ flush_dcache_page(page) ; inode->u.reiserfs_i.nopack = 1; - kunmap(page) ; /* mapped by prepare_write */ + retval = mapping->a_ops->commit_write(NULL, page, write_from, write_from) ; out_unlock: UnlockPage(page) ; diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c --- linux.0.18/fs/reiserfs/journal.c Wed Nov 28 14:24:49 2001 +++ linux/fs/reiserfs/journal.c Wed Dec 5 08:18:43 2001 @@ -41,6 +41,8 @@ ** log blocks to hit disk if it doesn't want to. */ +#define EXPORT_SYMTAB +#include #include #include #include @@ -1962,6 +1964,10 @@ time_t now = CURRENT_TIME ; if (reiserfs_dont_log(th->t_super)) return 0 ; + + /* cannot restart while nested unless the parent allows it */ + if (!reiserfs_restartable_handle(th) && th->t_refcount > 1) + return 0 ; if ( SB_JOURNAL(th->t_super)->j_must_wait > 0 || (SB_JOURNAL(th->t_super)->j_len_alloc + new_alloc) >= JOURNAL_MAX_BATCH || atomic_read(&(SB_JOURNAL(th->t_super)->j_jlock)) || @@ -1972,6 +1978,38 @@ return 0 ; } +int reiserfs_restart_transaction(struct reiserfs_transaction_handle *th) { + int refcount = th->t_refcount ; + struct super_block *s = th->t_super ; + int num = th->t_blocks_allocated ; + int flags = th->t_flags ; + int parent_flags = 0; + struct reiserfs_transaction_handle *saved_th = current->journal_info ; + + /* if refcount is > 1, saved_th is the parent we've nested into, save + ** his flags as well. So far, only intermezzo needs this, 99% of the + ** time it is horribly unsafe. + */ + if (refcount > 1) { + if (!reiserfs_restartable_handle(saved_th)) { + BUG() ; + } + th->t_refcount = 1; + parent_flags = saved_th->t_flags ; + } + th->t_flags = 0 ; + journal_end(th, s, num) ; + journal_begin(th, s, num) ; + th->t_flags = flags; + if (refcount > 1) { + current->journal_info = saved_th ; + th->t_refcount = refcount ; + memcpy(saved_th, th, sizeof(*th)) ; + saved_th->t_flags = parent_flags ; + } + return 0 ; +} + /* this must be called inside a transaction, and requires the ** kernel_lock to be held */ @@ -2017,6 +2055,10 @@ return 0 ; } PROC_INFO_INC( p_s_sb, journal.journal_being ); + /* set here for journal_join */ + th->t_refcount = 1; + th->t_flags = 0 ; + th->t_super = p_s_sb ; relock: lock_journal(p_s_sb) ; @@ -2032,8 +2074,6 @@ ** if this transaction is too old, and we weren't called joinable, wait for it to finish before beginning ** we don't sleep if there aren't other writers */ - - if ( (!join && SB_JOURNAL(p_s_sb)->j_must_wait > 0) || ( !join && (SB_JOURNAL(p_s_sb)->j_len_alloc + nblocks + 2) >= JOURNAL_MAX_BATCH) || (!join && atomic_read(&(SB_JOURNAL(p_s_sb)->j_wcount)) > 0 && SB_JOURNAL(p_s_sb)->j_trans_start_time > 0 && @@ -2074,21 +2114,87 @@ SB_JOURNAL(p_s_sb)->j_len_alloc += nblocks ; th->t_blocks_logged = 0 ; th->t_blocks_allocated = nblocks ; - th->t_super = p_s_sb ; th->t_trans_id = SB_JOURNAL(p_s_sb)->j_trans_id ; - th->t_caller = "Unknown" ; + reiserfs_set_handle_active(th) ; unlock_journal(p_s_sb) ; p_s_sb->s_dirt = 1; return 0 ; } +struct reiserfs_transaction_handle * +reiserfs_persistent_transaction(struct super_block *s, unsigned long nblocks) { + int ret ; + struct reiserfs_transaction_handle *th ; + + /* if we're nesting into an existing transaction. It will be + ** persistent on its own + */ + if (reiserfs_transaction_running(s)) { + th = current->journal_info ; + th->t_refcount++ ; + if (th->t_refcount < 2) { + BUG() ; + } + return th ; + } + th = kmalloc(sizeof(struct reiserfs_transaction_handle), GFP_NOFS) ; + if (!th) { + return ERR_PTR(-ENOMEM) ; + } + ret = journal_begin(th, s, nblocks) ; + if (ret) { + kfree(th) ; + return ERR_PTR(ret) ; + } + /* do_journal_end is now responsible for freeing the handle */ + reiserfs_set_handle_persistent(th) ; + return th ; +} int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { + struct reiserfs_transaction_handle *cur_th = current->journal_info; + + /* this keeps do_journal_end from NULLing out the current->journal_info + ** pointer + */ + th->t_handle_save = cur_th ; + if (cur_th && cur_th->t_refcount > 1) { + BUG() ; + } return do_journal_begin_r(th, p_s_sb, nblocks, 1) ; } int journal_begin(struct reiserfs_transaction_handle *th, struct super_block * p_s_sb, unsigned long nblocks) { - return do_journal_begin_r(th, p_s_sb, nblocks, 0) ; + struct reiserfs_transaction_handle *cur_th = current->journal_info ; + int ret ; + + th->t_handle_save = NULL ; + if (cur_th) { + /* we are nesting into the current transaction */ + if (cur_th->t_super == p_s_sb) { + cur_th->t_refcount++ ; + memcpy(th, cur_th, sizeof(*th)); + th->t_flags = 0 ; + reiserfs_set_handle_active(th) ; + if (th->t_refcount <= 1) + printk("BAD: refcount <= 1, but journal_info != 0\n"); + return 0; + } else { + /* we've ended up with a handle from a different filesystem. + ** save it and restore on journal_end. This should never + ** really happen... + */ + reiserfs_warning("clm-2100: nesting info a different FS\n") ; + th->t_handle_save = current->journal_info ; + current->journal_info = th; + } + } else { + current->journal_info = th; + } + ret = do_journal_begin_r(th, p_s_sb, nblocks, 0) ; + if (current->journal_info != th) + BUG() ; + return ret ; } /* not used at all */ @@ -2210,25 +2316,33 @@ return 0 ; } -/* -** if buffer already in current transaction, do a journal_mark_dirty -** otherwise, just mark it dirty and move on. Used for writes to meta blocks -** that don't need journaling -*/ -int journal_mark_dirty_nolog(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, struct buffer_head *bh) { - if (reiserfs_dont_log(th->t_super) || buffer_journaled(bh) || - buffer_journal_dirty(bh)) { - return journal_mark_dirty(th, p_s_sb, bh) ; - } - if (get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, bh->b_dev,bh->b_blocknr,bh->b_size)) { - return journal_mark_dirty(th, p_s_sb, bh) ; - } - mark_buffer_dirty(bh) ; - return 0 ; -} - int journal_end(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { - return do_journal_end(th, p_s_sb, nblocks, 0) ; + if (!current->journal_info && th->t_refcount > 1) + printk("REISER-NESTING: th NULL, refcount %d\n", th->t_refcount); + if (th->t_refcount > 1) { + struct reiserfs_transaction_handle *cur_th = current->journal_info ; + + /* we aren't allowed to close a nested transaction on a different + ** filesystem from the one in the task struct + */ + if (cur_th->t_super != th->t_super) + BUG() ; + + th->t_refcount--; + if (th != cur_th) { + int flags = cur_th->t_flags ; + /* nested handles are never persistent */ + if (reiserfs_persistent_handle(th)) { + BUG() ; + } + memcpy(cur_th, th, sizeof(*th)); + th->t_flags = 0 ; + cur_th->t_flags = flags ; + } + return 0; + } else { + return do_journal_end(th, p_s_sb, nblocks, 0) ; + } } /* removes from the current transaction, relsing and descrementing any counters. @@ -2331,6 +2445,10 @@ */ int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { + /* you are not allowed to sync while nested, very, very bad */ + if (th->t_refcount > 1) { + BUG() ; + } if (SB_JOURNAL(p_s_sb)->j_len == 0) { reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ; journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ; @@ -2552,16 +2670,12 @@ struct reiserfs_list_bitmap *jb = NULL ; int cleaned = 0 ; - if (reiserfs_dont_log(th->t_super)) { - bh = get_hash_table(p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ; - if (bh && buffer_dirty (bh)) { - printk ("journal_mark_freed(dont_log): dirty buffer on hash list: %lx %ld\n", bh->b_state, blocknr); - BUG (); - } - brelse (bh); - return 0 ; + cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, p_s_sb->s_dev, + blocknr, p_s_sb->s_blocksize) ; + if (cn && cn->bh) { + bh = cn->bh ; + get_bh(bh) ; } - bh = get_hash_table(p_s_sb->s_dev, blocknr, p_s_sb->s_blocksize) ; /* if it is journal new, we just remove it from this transaction */ if (bh && buffer_journal_new(bh)) { mark_buffer_notjournal_new(bh) ; @@ -2576,7 +2690,6 @@ set_bit_in_list_bitmap(p_s_sb, blocknr, jb) ; /* Note, the entire while loop is not allowed to schedule. */ - if (bh) { clear_prepared_bits(bh) ; } @@ -2679,8 +2792,6 @@ int retry_count = 0 ; PROC_INFO_INC( p_s_sb, journal.prepare ); - if (reiserfs_dont_log (p_s_sb)) - return; while(!test_bit(BH_JPrepared, &bh->b_state) || (wait && buffer_locked(bh))) { @@ -2693,7 +2804,7 @@ RFALSE( buffer_locked(bh) && cur_tb != NULL, "waiting while do_balance was running\n") ; wait_on_buffer(bh) ; - } + } PROC_INFO_INC( p_s_sb, journal.prepare_retry ); retry_count++ ; } @@ -2725,8 +2836,12 @@ int wait_on_commit = flags & WAIT ; struct reiserfs_super_block *rs ; + if (th->t_refcount > 1) + BUG() ; + + current->journal_info = th->t_handle_save; if (reiserfs_dont_log(th->t_super)) { - return 0 ; + goto out ; } lock_journal(p_s_sb) ; @@ -2743,7 +2858,7 @@ ** it tells us if we should continue with the journal_end, or just return */ if (!check_journal_end(th, p_s_sb, nblocks, flags)) { - return 0 ; + goto out ; } /* check_journal_end might set these, check again */ @@ -2762,8 +2877,11 @@ } #ifdef REISERFS_PREALLOCATE + /* quota ops might need to nest, setup the journal_info pointer for them */ + current->journal_info = th ; reiserfs_discard_all_prealloc(th); /* it should not involve new blocks into * the transaction */ + current->journal_info = th->t_handle_save ; #endif rs = SB_DISK_SUPER_BLOCK(p_s_sb) ; @@ -2854,7 +2972,7 @@ printk("journal-2020: do_journal_end: BAD desc->j_len is ZERO\n") ; atomic_set(&(SB_JOURNAL(p_s_sb)->j_jlock), 0) ; wake_up(&(SB_JOURNAL(p_s_sb)->j_join_wait)) ; - return 0 ; + goto out ; } /* first data block is j_start + 1, so add one to cur_write_start wherever you use it */ @@ -2986,8 +3104,10 @@ atomic_set(&(SB_JOURNAL(p_s_sb)->j_jlock), 0) ; /* wake up any body waiting to join. */ wake_up(&(SB_JOURNAL(p_s_sb)->j_join_wait)) ; +out: + if (reiserfs_persistent_handle(th)) + kfree(th) ; + else + th->t_flags = 0 ; return 0 ; } - - - diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c --- linux.0.18/fs/reiserfs/namei.c Wed Nov 28 14:24:49 2001 +++ linux/fs/reiserfs/namei.c Wed Dec 5 08:18:43 2001 @@ -532,7 +532,6 @@ return -ENOMEM ; } journal_begin(&th, dir->i_sb, jbegin_count) ; - th.t_caller = "create" ; windex = push_journal_writer("reiserfs_create") ; inode = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode, &retval); if (!inode) { diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c --- linux.0.18/fs/reiserfs/stree.c Wed Nov 28 14:24:49 2001 +++ linux/fs/reiserfs/stree.c Wed Dec 5 08:18:43 2001 @@ -1821,9 +1821,7 @@ // FIXME: sd gets wrong size here } reiserfs_update_sd(th, p_s_inode) ; - - journal_end(th, p_s_inode->i_sb, orig_len_alloc) ; - journal_begin(th, p_s_inode->i_sb, orig_len_alloc) ; + reiserfs_restart_transaction(th) ; reiserfs_update_inode_transaction(p_s_inode) ; } } while ( n_file_size > ROUND_UP (n_new_file_size) && diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/super.c linux/fs/reiserfs/super.c --- linux.0.18/fs/reiserfs/super.c Wed Nov 28 14:24:49 2001 +++ linux/fs/reiserfs/super.c Wed Dec 5 08:18:43 2001 @@ -20,6 +20,9 @@ #include #include +EXPORT_SYMBOL(journal_begin) ; +EXPORT_SYMBOL(journal_end) ; + #define REISERFS_OLD_BLOCKSIZE 4096 #define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20 @@ -186,6 +189,12 @@ printk("reiserfs: resize option requires a value\n"); return 0; } + } else if (!strcmp (this_char, "data")) { + if (value && *value) { + if (!strcmp(value, "journal")) { + set_bit (REISERFS_DATA_LOG, mount_options); + } + } } else if (!strcmp (this_char, "hash")) { if (value && *value) { /* if they specify any hash option, we force detection @@ -824,7 +833,6 @@ MODULE_DESCRIPTION("ReiserFS journaled filesystem"); MODULE_AUTHOR("Hans Reiser "); MODULE_LICENSE("GPL"); -EXPORT_NO_SYMBOLS; // // this is exactly what 2.3.99-pre9's init_ext2_fs is diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c --- linux.0.18/fs/reiserfs/tail_conversion.c Wed Nov 7 12:24:31 2001 +++ linux/fs/reiserfs/tail_conversion.c Wed Dec 5 08:18:43 2001 @@ -134,9 +134,11 @@ /* stolen from fs/buffer.c */ void reiserfs_unmap_buffer(struct buffer_head *bh) { if (buffer_mapped(bh)) { + /* if (buffer_journaled(bh) || buffer_journal_dirty(bh)) { BUG() ; } + */ mark_buffer_clean(bh) ; lock_buffer(bh) ; clear_bit(BH_Mapped, &bh->b_state) ; diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/include/linux/fs.h linux/include/linux/fs.h --- linux.0.18/include/linux/fs.h Wed Nov 28 14:26:24 2001 +++ linux/include/linux/fs.h Wed Dec 5 08:18:43 2001 @@ -1373,6 +1373,7 @@ /* Generic buffer handling for block filesystems.. */ extern int try_to_release_page(struct page * page, int gfp_mask); extern int discard_bh_page(struct page *, unsigned long, int); +extern void discard_buffer(struct buffer_head *bh) ; #define block_flushpage(page, offset) discard_bh_page(page, offset, 1) #define block_invalidate_page(page) discard_bh_page(page, 0, 0) extern int block_symlink(struct inode *, const char *, int); diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h --- linux.0.18/include/linux/reiserfs_fs.h Wed Nov 28 14:24:49 2001 +++ linux/include/linux/reiserfs_fs.h Wed Dec 5 08:18:43 2001 @@ -1623,6 +1623,88 @@ __u32 j_mount_id ; } ; +/* data write mode flags */ +#define REISERFS_FILE_DATA_LOG 1 +#define REISERFS_FILE_DATA_ORDERED 2 + +static inline int +reiserfs_file_data_log(struct inode *inode) { + if (reiserfs_data_log(inode->i_sb) || + inode->u.reiserfs_i.i_data_mode & REISERFS_FILE_DATA_LOG) + { + return 1 ; + } + return 0 ; +} + +/* flags for the nested transaction handle */ +#define REISERFS_PERSISTENT_HANDLE 1 +#define REISERFS_ACTIVE_HANDLE 2 +#define REISERFS_CLOSE_NESTED 4 +#define REISERFS_DANGLING_HANDLE 8 +/* +** transaction handle which is passed around for all journal calls +*/ +struct reiserfs_transaction_handle { + struct super_block *t_super ; /* super for this FS when journal_begin was + called. saves calls to reiserfs_get_super + also used by nested transactions to make + sure they are nesting on the right FS + _must_ be first in the handle + */ + int t_refcount; + int t_blocks_logged ; /* number of blocks this writer has logged */ + int t_blocks_allocated ; /* number of blocks this writer allocated */ + unsigned long t_trans_id ; /* sanity check, equals the current trans id */ + int t_flags ; + void *t_handle_save ; /* save existing current->journal_info */ +} ; + +static inline int +reiserfs_dangling_handle(struct reiserfs_transaction_handle *th) { + return (th && (th->t_flags & REISERFS_DANGLING_HANDLE)) ; +} + +static inline void +reiserfs_set_handle_dangling(struct reiserfs_transaction_handle *th) { + th->t_flags |= REISERFS_DANGLING_HANDLE ; +} + +static inline void +reiserfs_clear_handle_dangling(struct reiserfs_transaction_handle *th) { + th->t_flags &= ~REISERFS_DANGLING_HANDLE ; +} + +static inline int +reiserfs_persistent_handle(struct reiserfs_transaction_handle *th) { + return (th && (th->t_flags & REISERFS_PERSISTENT_HANDLE)) ; +} + +static inline void +reiserfs_set_handle_persistent(struct reiserfs_transaction_handle *th) { + th->t_flags |= REISERFS_PERSISTENT_HANDLE ; +} + +static inline int +reiserfs_active_handle(struct reiserfs_transaction_handle *th) { + return (th && (th->t_flags & REISERFS_ACTIVE_HANDLE)) ; +} + +static inline void +reiserfs_set_handle_active(struct reiserfs_transaction_handle *th) { + th->t_flags |= REISERFS_ACTIVE_HANDLE ; +} + +static inline int +reiserfs_restartable_handle(struct reiserfs_transaction_handle *th) { + return (th && (th->t_flags & REISERFS_CLOSE_NESTED)) ; +} + +static inline void +reiserfs_set_handle_restartable(struct reiserfs_transaction_handle *th) { + th->t_flags |= REISERFS_CLOSE_NESTED ; +} + extern task_queue reiserfs_commit_thread_tq ; extern wait_queue_head_t reiserfs_commit_thread_wait ; @@ -1664,6 +1746,16 @@ void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ; void reiserfs_allow_writes(struct super_block *s) ; void reiserfs_check_lock_depth(char *caller) ; +int journal_mark_dirty(struct reiserfs_transaction_handle *, + struct super_block *, struct buffer_head *bh) ; + +static inline int reiserfs_transaction_running(struct super_block *s) { + struct reiserfs_transaction_handle *th = current->journal_info ; + if (th && th->t_super == s) + return 1 ; + return 0 ; +} + void reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, int wait) ; void reiserfs_restore_prepared_buffer(struct super_block *, struct buffer_head *bh) ; int journal_init(struct super_block *) ; @@ -1678,8 +1770,14 @@ 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_restart_transaction(struct reiserfs_transaction_handle *) ; 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) ; + +/* allocates a transaction handle, and starts a new transaction it */ +struct reiserfs_transaction_handle * +reiserfs_persistent_transaction(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) ; @@ -1877,8 +1975,18 @@ const struct inode * dir, int mode, const char * symname, int item_len, struct dentry *dentry, struct inode *inode, int * err); -int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode); -void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode); +int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, + struct inode * inode); + +void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th, + struct inode * inode, loff_t size); + +static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th, + struct inode *inode) +{ + reiserfs_update_sd_size(th, inode, inode->i_size) ; +} + int reiserfs_inode_setattr(struct dentry *, struct iattr * attr); /* namei.c */ diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h --- linux.0.18/include/linux/reiserfs_fs_i.h Wed Nov 7 12:20:37 2001 +++ linux/include/linux/reiserfs_fs_i.h Wed Dec 5 08:18:43 2001 @@ -46,6 +46,8 @@ */ unsigned long i_trans_id ; unsigned long i_trans_index ; + + int i_data_mode ; /* log data blocks for this file? */ }; diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h --- linux.0.18/include/linux/reiserfs_fs_sb.h Wed Nov 28 14:24:49 2001 +++ linux/include/linux/reiserfs_fs_sb.h Wed Dec 5 08:18:43 2001 @@ -221,19 +221,6 @@ } ; /* -** transaction handle which is passed around for all journal calls -*/ -struct reiserfs_transaction_handle { - /* ifdef it. -Hans */ - char *t_caller ; /* debugging use */ - int t_blocks_logged ; /* number of blocks this writer has logged */ - int t_blocks_allocated ; /* number of blocks this writer allocated */ - unsigned long t_trans_id ; /* sanity check, equals the current trans id */ - struct super_block *t_super ; /* super for this FS when journal_begin was - called. saves calls to reiserfs_get_super */ -} ; - -/* ** one of these for each transaction. The most important part here is the j_realblock. ** this list of cnodes is used to hash all the blocks in all the commits, to mark all the ** real buffer heads dirty once all the commits hit the disk, @@ -455,12 +442,8 @@ #define REISERFS_NO_BORDER 11 #define REISERFS_NO_UNHASHED_RELOCATION 12 #define REISERFS_HASHED_RELOCATION 13 -#define REISERFS_TEST4 14 - -#define REISERFS_TEST1 11 -#define REISERFS_TEST2 12 -#define REISERFS_TEST3 13 -#define REISERFS_TEST4 14 +#define REISERFS_DATA_LOG 14 +#define REISERFS_TEST4 15 #define reiserfs_r5_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_R5_HASH)) #define reiserfs_rupasov_hash(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << FORCE_RUPASOV_HASH)) @@ -469,6 +452,7 @@ #define reiserfs_no_border(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NO_BORDER)) #define reiserfs_no_unhashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION)) #define reiserfs_hashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_HASHED_RELOCATION)) +#define reiserfs_data_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_DATA_LOG)) #define reiserfs_test4(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_TEST4)) #define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL)) @@ -479,7 +463,6 @@ void reiserfs_file_buffer (struct buffer_head * bh, int list); int reiserfs_is_super(struct super_block *s) ; -int journal_mark_dirty(struct reiserfs_transaction_handle *, struct super_block *, struct buffer_head *bh) ; int flush_old_commits(struct super_block *s, int) ; int show_reiserfs_locks(void) ; int reiserfs_resize(struct super_block *, unsigned long) ; diff -urN --exclude=*.orig --exclude=linux.prj --exclude=.*.prcs_aux linux.0.18/kernel/ksyms.c linux/kernel/ksyms.c --- linux.0.18/kernel/ksyms.c Wed Nov 28 14:26:13 2001 +++ linux/kernel/ksyms.c Wed Dec 5 08:18:43 2001 @@ -161,6 +161,7 @@ EXPORT_SYMBOL(d_lookup); EXPORT_SYMBOL(__d_path); EXPORT_SYMBOL(mark_buffer_dirty); +EXPORT_SYMBOL(discard_buffer); /* for FS flushpage funcs */ EXPORT_SYMBOL(set_buffer_async_io); /* for reiserfs_writepage */ EXPORT_SYMBOL(__mark_buffer_dirty); EXPORT_SYMBOL(__mark_inode_dirty);