Commit 6f2fb125 authored by Jeff Mahoney's avatar Jeff Mahoney Committed by Linus Torvalds

[PATCH] ReiserFS: Add I/O error handling to journal operations

This patch allows ReiserFS to handle I/O errors in the journal (or journal
flush) where it would have previously panicked.  The new behavior is to
mark the filesystem read-only, disallow new transactions to be started, and
to allow existing transactions to complete (though not to commit).  The
resultant filesystem can be safely umounted, and checked via normal
mechanisms.  As it is a journaling filesystem, the filesystem itself will
be in a similar state to the power being cut to the machine, once umounted.
Signed-off-by: default avatarJeff Mahoney <jeffm@novell.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5b7b40f5
......@@ -137,6 +137,8 @@ static int scan_bitmap_block (struct reiserfs_transaction_handle *th,
int end, next;
int org = *beg;
BUG_ON (!th->t_trans_id);
RFALSE(bmap_n >= SB_BMAP_NR (s), "Bitmap %d is out of range (0..%d)",bmap_n, SB_BMAP_NR (s) - 1);
PROC_INFO_INC( s, scan_bitmap.bmap );
/* this is unclear and lacks comments, explain how journal bitmaps
......@@ -290,6 +292,8 @@ static int scan_bitmap (struct reiserfs_transaction_handle *th,
int end_bm, end_off;
int off_max = s->s_blocksize << 3;
BUG_ON (!th->t_trans_id);
PROC_INFO_INC( s, scan_bitmap.call );
if ( SB_FREE_BLOCKS(s) <= 0)
return 0; // No point in looking for more free blocks
......@@ -348,6 +352,8 @@ static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
struct reiserfs_bitmap_info *apbi;
int nr, offset;
BUG_ON (!th->t_trans_id);
PROC_INFO_INC( s, free_block );
rs = SB_DISK_SUPER_BLOCK (s);
......@@ -389,6 +395,8 @@ void reiserfs_free_block (struct reiserfs_transaction_handle *th,
{
struct super_block * s = th->t_super;
BUG_ON (!th->t_trans_id);
RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block");
/* mark it before we clear it, just in case */
......@@ -401,6 +409,7 @@ void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th,
struct inode *inode, b_blocknr_t block) {
RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device");
RFALSE(is_reusable (th->t_super, block, 1) == 0, "vs-4070: can not free such block");
BUG_ON (!th->t_trans_id);
_reiserfs_free_block(th, inode, block, 1) ;
}
......@@ -410,6 +419,7 @@ static void __discard_prealloc (struct reiserfs_transaction_handle * th,
unsigned long save = ei->i_prealloc_block ;
int dirty = 0;
struct inode *inode = &ei->vfs_inode;
BUG_ON (!th->t_trans_id);
#ifdef CONFIG_REISERFS_CHECK
if (ei->i_prealloc_count < 0)
reiserfs_warning (th->t_super, "zam-4001:%s: inode has negative prealloc blocks count.", __FUNCTION__ );
......@@ -431,6 +441,7 @@ void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
struct inode *inode)
{
struct reiserfs_inode_info *ei = REISERFS_I(inode);
BUG_ON (!th->t_trans_id);
if (ei->i_prealloc_count)
__discard_prealloc(th, ei);
}
......@@ -439,6 +450,8 @@ void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
{
struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
BUG_ON (!th->t_trans_id);
while (!list_empty(plist)) {
struct reiserfs_inode_info *ei;
ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
......
......@@ -26,10 +26,13 @@ struct file_operations reiserfs_dir_operations = {
int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
struct inode *inode = dentry->d_inode;
int err;
reiserfs_write_lock(inode->i_sb);
reiserfs_commit_for_inode(inode) ;
err = reiserfs_commit_for_inode(inode) ;
reiserfs_write_unlock(inode->i_sb) ;
return 0 ;
if (err < 0)
return err;
return 0;
}
......
......@@ -35,6 +35,8 @@ static int reiserfs_file_release (struct inode * inode, struct file * filp)
{
struct reiserfs_transaction_handle th ;
int err;
int jbegin_failure = 0;
if (!S_ISREG (inode->i_mode))
BUG ();
......@@ -49,26 +51,58 @@ static int reiserfs_file_release (struct inode * inode, struct file * filp)
reiserfs_write_lock(inode->i_sb);
down (&inode->i_sem);
journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
/* freeing preallocation only involves relogging blocks that
* are already in the current transaction. preallocation gets
* freed at the end of each transaction, so it is impossible for
* us to log any additional blocks
*/
err = journal_begin(&th, inode->i_sb, 1);
if (err) {
/* uh oh, we can't allow the inode to go away while there
* is still preallocation blocks pending. Try to join the
* aborted transaction
*/
jbegin_failure = err;
err = journal_join_abort(&th, inode->i_sb, 1);
if (err) {
/* hmpf, our choices here aren't good. We can pin the inode
* which will disallow unmount from every happening, we can
* do nothing, which will corrupt random memory on unmount,
* or we can forcibly remove the file from the preallocation
* list, which will leak blocks on disk. Lets pin the inode
* and let the admin know what is going on.
*/
igrab(inode);
reiserfs_warning(inode->i_sb, "pinning inode %lu because the "
"preallocation can't be freed");
goto out;
}
}
reiserfs_update_inode_transaction(inode) ;
#ifdef REISERFS_PREALLOCATE
reiserfs_discard_prealloc (&th, inode);
#endif
journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
err = journal_end(&th, inode->i_sb, 1);
if (atomic_read(&inode->i_count) <= 1 &&
/* copy back the error code from journal_begin */
if (!err)
err = jbegin_failure;
if (!err && atomic_read(&inode->i_count) <= 1 &&
(REISERFS_I(inode)->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
item(s) had to be converted, then it may have to be
indirect2direct converted */
reiserfs_truncate_file(inode, 0) ;
err = reiserfs_truncate_file(inode, 0) ;
}
out:
up (&inode->i_sem);
reiserfs_write_unlock(inode->i_sb);
return 0;
return err;
}
static void reiserfs_vfs_truncate_file(struct inode *inode) {
......@@ -99,6 +133,8 @@ static int reiserfs_sync_file(
reiserfs_write_unlock(p_s_inode->i_sb);
if (barrier_done != 1)
blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
if (barrier_done < 0)
return barrier_done;
return ( n_err < 0 ) ? -EIO : 0;
}
......@@ -146,7 +182,6 @@ int reiserfs_allocate_blocks_for_region(
// of the fact that we already prepared
// current block for journal
int will_prealloc = 0;
RFALSE(!blocks_to_allocate, "green-9004: tried to allocate zero blocks?");
/* only preallocate if this is a small write */
......@@ -166,7 +201,9 @@ int reiserfs_allocate_blocks_for_region(
/* If we came here, it means we absolutely need to open a transaction,
since we need to allocate some blocks */
reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that.
journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1); // Wish I know if this number enough
res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1); // Wish I know if this number enough
if (res)
goto error_exit;
reiserfs_update_inode_transaction(inode) ;
/* Look for the in-tree position of our write, need path for block allocator */
......@@ -194,7 +231,9 @@ int reiserfs_allocate_blocks_for_region(
/* We flush the transaction in case of no space. This way some
blocks might become free */
SB_JOURNAL(inode->i_sb)->j_must_wait = 1;
restart_transaction(th, inode, &path);
res = restart_transaction(th, inode, &path);
if (res)
goto error_exit;
/* We might have scheduled, so search again */
res = search_for_position_by_key(inode->i_sb, &key, &path);
......@@ -322,8 +361,14 @@ int reiserfs_allocate_blocks_for_region(
}
/* Now we want to check if transaction is too full, and if it is
we restart it. This will also free the path. */
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)) {
res = restart_transaction(th, inode, &path);
if (res) {
pathrelse (&path);
kfree(zeros);
goto error_exit;
}
}
/* Well, need to recalculate path and stuff */
set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + (to_paste << inode->i_blkbits));
......@@ -349,6 +394,7 @@ int reiserfs_allocate_blocks_for_region(
// we are going to overwrite, so there is nothing to scan through for holes.
for ( curr_block = 0, itempos = path.pos_in_item ; curr_block < blocks_to_allocate && res == POSITION_FOUND ; ) {
retry:
if ( itempos >= ih_item_len(ih)/UNFM_P_SIZE ) {
/* We run out of data in this indirect item, let's look for another
one. */
......@@ -526,8 +572,14 @@ int reiserfs_allocate_blocks_for_region(
reiserfs_free_block(th, inode, le32_to_cpu(allocated_blocks[i]), 1);
error_exit:
reiserfs_update_sd(th, inode); // update any changes we made to blk count
journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1);
if (th->t_trans_id) {
int err;
// update any changes we made to blk count
reiserfs_update_sd(th, inode);
err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1);
if (err)
res = err;
}
reiserfs_write_unlock(inode->i_sb);
kfree(allocated_blocks);
......@@ -602,13 +654,16 @@ int reiserfs_commit_page(struct inode *inode, struct page *page,
struct super_block *s = inode->i_sb;
int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
struct reiserfs_transaction_handle th;
th.t_trans_id = 0;
int ret = 0;
th.t_trans_id = 0;
blocksize = 1 << inode->i_blkbits;
if (logit) {
reiserfs_write_lock(s);
journal_begin(&th, s, bh_per_page + 1);
ret = journal_begin(&th, s, bh_per_page + 1);
if (ret)
goto drop_write_lock;
reiserfs_update_inode_transaction(inode);
}
for(bh = head = page_buffers(page), block_start = 0;
......@@ -640,7 +695,8 @@ int reiserfs_commit_page(struct inode *inode, struct page *page,
}
}
if (logit) {
journal_end(&th, s, bh_per_page + 1);
ret = journal_end(&th, s, bh_per_page + 1);
drop_write_lock:
reiserfs_write_unlock(s);
}
/*
......@@ -651,7 +707,7 @@ int reiserfs_commit_page(struct inode *inode, struct page *page,
*/
if (!partial)
SetPageUptodate(page);
return 0;
return ret;
}
......@@ -717,7 +773,9 @@ int reiserfs_submit_file_region_for_write(
reiserfs_write_lock(inode->i_sb);
if (!sd_update)
reiserfs_update_sd(th, inode);
journal_end(th, th->t_super, th->t_blocks_allocated);
status = journal_end(th, th->t_super, th->t_blocks_allocated);
if (status)
retval = status;
reiserfs_write_unlock(inode->i_sb);
}
th->t_trans_id = 0;
......@@ -1100,6 +1158,7 @@ ssize_t reiserfs_file_write( struct file *file, /* the file we are going to writ
size_t already_written = 0; // Number of bytes already written to the file.
loff_t pos; // Current position in the file.
ssize_t res; // return value of various functions that we call.
int err = 0;
struct inode *inode = file->f_dentry->d_inode; // Inode of the file that we are writing to.
/* To simplify coding at this time, we store
locked pages in array for now */
......@@ -1114,24 +1173,40 @@ ssize_t reiserfs_file_write( struct file *file, /* the file we are going to writ
If we will crash while doing direct io, finish_unfinished will
cut the garbage from the file end. */
reiserfs_write_lock(inode->i_sb);
journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
err = journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
if (err) {
reiserfs_write_unlock (inode->i_sb);
return err;
}
reiserfs_update_inode_transaction(inode);
add_save_link (&th, inode, 1 /* Truncate */);
journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
reiserfs_write_unlock(inode->i_sb);
after_file_end = 1;
err = journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
reiserfs_write_unlock(inode->i_sb);
if (err)
return err;
}
result = generic_file_write(file, buf, count, ppos);
if ( after_file_end ) { /* Now update i_size and remove the savelink */
struct reiserfs_transaction_handle th;
reiserfs_write_lock(inode->i_sb);
journal_begin(&th, inode->i_sb, 1);
err = journal_begin(&th, inode->i_sb, 1);
if (err) {
reiserfs_write_unlock (inode->i_sb);
return err;
}
reiserfs_update_inode_transaction(inode);
reiserfs_update_sd(&th, inode);
journal_end(&th, inode->i_sb, 1);
remove_save_link (inode, 1/* truncate */);
err = journal_end(&th, inode->i_sb, 1);
if (err) {
reiserfs_write_unlock (inode->i_sb);
return err;
}
err = remove_save_link (inode, 1/* truncate */);
reiserfs_write_unlock(inode->i_sb);
if (err)
return err;
}
return result;
......@@ -1280,8 +1355,12 @@ ssize_t reiserfs_file_write( struct file *file, /* the file we are going to writ
/* this is only true on error */
if (th.t_trans_id) {
reiserfs_write_lock(inode->i_sb);
journal_end(&th, th.t_super, th.t_blocks_allocated);
err = journal_end(&th, th.t_super, th.t_blocks_allocated);
reiserfs_write_unlock(inode->i_sb);
if (err) {
res = err;
goto out;
}
}
if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
......
......@@ -47,21 +47,32 @@ void reiserfs_delete_inode (struct inode * inode)
reiserfs_delete_xattrs (inode);
journal_begin(&th, inode->i_sb, jbegin_count) ;
if (journal_begin(&th, inode->i_sb, jbegin_count)) {
up (&inode->i_sem);
goto out;
}
reiserfs_update_inode_transaction(inode) ;
reiserfs_delete_object (&th, inode);
if (reiserfs_delete_object (&th, inode)) {
up (&inode->i_sem);
goto out;
}
journal_end(&th, inode->i_sb, jbegin_count) ;
if (journal_end(&th, inode->i_sb, jbegin_count)) {
up (&inode->i_sem);
goto out;
}
up (&inode->i_sem);
/* all items of file are deleted, so we can remove "save" link */
remove_save_link (inode, 0/* not truncate */);
remove_save_link (inode, 0/* not truncate */); /* we can't do anything
* about an error here */
} else {
/* no object items are in the tree */
;
}
out:
clear_inode (inode); /* note this must go after the journal_end to prevent deadlock */
inode->i_blocks = 0;
reiserfs_write_unlock(inode->i_sb);
......@@ -201,20 +212,28 @@ static int file_capable (struct inode * inode, long block)
return 0;
}
/*static*/ void restart_transaction(struct reiserfs_transaction_handle *th,
/*static*/ int 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 ;
int err;
BUG_ON (!th->t_trans_id);
BUG_ON (!th->t_refcount);
/* we cannot restart while nested */
if (th->t_refcount > 1) {
return ;
return 0 ;
}
pathrelse(path) ;
reiserfs_update_sd(th, inode) ;
journal_end(th, s, len) ;
journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
err = journal_end(th, s, len) ;
if (!err) {
err = journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
if (!err)
reiserfs_update_inode_transaction(inode) ;
}
return err;
}
// it is called by get_block when create == 0. Returns block number
......@@ -443,9 +462,11 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode,
ret = reiserfs_get_block(inode, iblock, bh_result,
create | GET_BLOCK_NO_DANGLE) ;
if (ret)
goto out;
/* don't allow direct io onto tail pages */
if (ret == 0 && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
if (buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
/* make sure future calls to the direct io funcs for this offset
** in the file fail by unmapping the buffer
*/
......@@ -455,11 +476,15 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode,
/* Possible unpacked tail. Flush the data before pages have
disappeared */
if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) {
int err;
lock_kernel();
reiserfs_commit_for_inode(inode);
err = reiserfs_commit_for_inode(inode);
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
unlock_kernel();
if (err < 0)
ret = err;
}
out:
return ret ;
}
......@@ -539,6 +564,7 @@ static inline int _allocate_block(struct reiserfs_transaction_handle *th,
b_blocknr_t *allocated_block_nr,
struct path * path,
int flags) {
BUG_ON (!th->t_trans_id);
#ifdef REISERFS_PREALLOCATE
if (!(flags & GET_BLOCK_NO_ISEM)) {
......@@ -551,7 +577,7 @@ static inline int _allocate_block(struct reiserfs_transaction_handle *th,
int reiserfs_get_block (struct inode * inode, sector_t block,
struct buffer_head * bh_result, int create)
{
int repeat, retval;
int repeat, retval = 0;
b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is (unsigned) 32 bit int
INITIALIZE_PATH(path);
int pos_in_item;
......@@ -655,7 +681,9 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
** research if we succeed on the second try
*/
SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1;
restart_transaction(th, inode, &path) ;
retval = restart_transaction(th, inode, &path) ;
if (retval)
goto failure;
repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create);
if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
......@@ -696,8 +724,9 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
}
set_block_dev_mapped(bh_result, unfm_ptr, inode);
pathrelse (&path);
retval = 0;
if (!dangle && th)
reiserfs_end_persistent_transaction(th);
retval = reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb);
......@@ -705,7 +734,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
** there is no need to make sure the inode is updated with this
** transaction
*/
return 0;
return retval;
}
if (!th) {
......@@ -766,9 +795,12 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
* ugly, but we can only end the transaction if
* we aren't nested
*/
BUG_ON (!th->t_refcount);
if (th->t_refcount == 1) {
reiserfs_end_persistent_transaction(th);
retval = reiserfs_end_persistent_transaction(th);
th = NULL;
if (retval)
goto failure;
}
retval = convert_tail_for_hole(inode, bh_result, tail_offset) ;
......@@ -898,7 +930,9 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
** ending their transaction will be able to continue.
*/
if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
restart_transaction(th, inode, &path) ;
retval = restart_transaction(th, inode, &path) ;
if (retval)
goto failure;
}
/* inserting indirect pointers for a hole can take a
** long time. reschedule if needed
......@@ -929,10 +963,15 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
retval = 0;
failure:
if (th && !dangle) {
reiserfs_update_sd(th, inode) ;
reiserfs_end_persistent_transaction(th);
if (th && (!dangle || (retval && !th->t_trans_id))) {
int err;
if (th->t_trans_id)
reiserfs_update_sd(th, inode);
err = reiserfs_end_persistent_transaction(th);
if (err)
retval = err;
}
reiserfs_write_unlock(inode->i_sb);
reiserfs_check_path(&path) ;
return retval;
......@@ -1215,6 +1254,8 @@ void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
struct item_head *ih, tmp_ih ;
int retval;
BUG_ON (!th->t_trans_id);
make_cpu_key (&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3);//key type is unimportant
for(;;) {
......@@ -1508,12 +1549,8 @@ int reiserfs_write_inode (struct inode * inode, int do_sync) {
struct reiserfs_transaction_handle th ;
int jbegin_count = 1 ;
if (inode->i_sb->s_flags & MS_RDONLY) {
reiserfs_warning (inode->i_sb,
"clm-6005: writing inode %lu on readonly FS",
inode->i_ino) ;
if (inode->i_sb->s_flags & MS_RDONLY)
return -EROFS;
}
/* memory pressure can sometimes initiate write_inode calls with sync == 1,
** these cases are just when the system needs ram, not when the
** inode needs to reach disk for safety, and they can safely be
......@@ -1521,9 +1558,10 @@ int reiserfs_write_inode (struct inode * inode, int do_sync) {
*/
if (do_sync && !(current->flags & PF_MEMALLOC)) {
reiserfs_write_lock(inode->i_sb);
journal_begin(&th, inode->i_sb, jbegin_count) ;
if (!journal_begin(&th, inode->i_sb, jbegin_count)) {
reiserfs_update_sd (&th, inode);
journal_end_sync(&th, inode->i_sb, jbegin_count) ;
}
reiserfs_write_unlock(inode->i_sb);
}
return 0;
......@@ -1552,6 +1590,8 @@ static int reiserfs_new_directory (struct reiserfs_transaction_handle *th,
struct cpu_key key;
int retval;
BUG_ON (!th->t_trans_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*/);
......@@ -1602,6 +1642,8 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th,
struct cpu_key key;
int retval;
BUG_ON (!th->t_trans_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),
......@@ -1653,6 +1695,8 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
int retval;
int err;
BUG_ON (!th->t_trans_id);
if (!dir || !dir->i_nlink) {
err = -EPERM;
goto out_bad_inode;
......@@ -1926,7 +1970,7 @@ static int grab_tail_page(struct inode *p_s_inode,
**
** some code taken from block_truncate_page
*/
void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
struct reiserfs_transaction_handle th ;
/* we want the offset for the first byte after the end of the file */
unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1) ;
......@@ -1962,18 +2006,28 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
/* 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 ) ;
error = journal_begin (&th, p_s_inode->i_sb,
JOURNAL_PER_BALANCE_CNT * 2 + 1);
if (error)
goto out;
reiserfs_update_inode_transaction(p_s_inode) ;
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) ;
journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
error = reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
if (error)
goto out;
error = journal_end (&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1);
if (error)
goto out;
if (update_timestamps)
remove_save_link (p_s_inode, 1/* truncate */);
if (update_timestamps) {
error = remove_save_link (p_s_inode, 1/* truncate */);
if (error)
goto out;
}
if (page) {
length = offset & (blocksize - 1) ;
......@@ -1995,6 +2049,14 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
}
reiserfs_write_unlock(p_s_inode->i_sb);
return 0;
out:
if (page) {
unlock_page (page);
page_cache_release (page);
}
reiserfs_write_unlock(p_s_inode->i_sb);
return error;
}
static int map_block_for_writepage(struct inode *inode,
......@@ -2064,7 +2126,9 @@ static int map_block_for_writepage(struct inode *inode,
if (!trans_running) {
/* vs-3050 is gone, no need to drop the path */
journal_begin(&th, inode->i_sb, jbegin_count) ;
retval = journal_begin(&th, inode->i_sb, jbegin_count) ;
if (retval)
goto out;
reiserfs_update_inode_transaction(inode) ;
trans_running = 1;
if (fs_changed(fs_gen, inode->i_sb) && item_moved(&tmp_ih, &path)) {
......@@ -2104,7 +2168,9 @@ static int map_block_for_writepage(struct inode *inode,
out:
pathrelse(&path) ;
if (trans_running) {
journal_end(&th, inode->i_sb, jbegin_count) ;
int err = journal_end(&th, inode->i_sb, jbegin_count) ;
if (err)
retval = err;
trans_running = 0;
}
reiserfs_write_unlock(inode->i_sb);
......@@ -2210,7 +2276,11 @@ static int reiserfs_write_full_page(struct page *page, struct writeback_control
if (checked) {
ClearPageChecked(page);
reiserfs_write_lock(s);
journal_begin(&th, s, bh_per_page + 1);
error = journal_begin(&th, s, bh_per_page + 1);
if (error) {
reiserfs_write_unlock(s);
goto fail;
}
reiserfs_update_inode_transaction(inode);
}
/* now go through and lock any dirty buffers on the page */
......@@ -2245,8 +2315,10 @@ static int reiserfs_write_full_page(struct page *page, struct writeback_control
} while((bh = bh->b_this_page) != head);
if (checked) {
journal_end(&th, s, bh_per_page + 1);
error = journal_end(&th, s, bh_per_page + 1);
reiserfs_write_unlock(s);
if (error)
goto fail;
}
BUG_ON(PageWriteback(page));
set_page_writeback(page);
......@@ -2353,6 +2425,8 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
if (reiserfs_transaction_running(inode->i_sb)) {
struct reiserfs_transaction_handle *th;
th = (struct reiserfs_transaction_handle *)current->journal_info;
BUG_ON (!th->t_refcount);
BUG_ON (!th->t_trans_id);
old_ref = th->t_refcount;
th->t_refcount++;
}
......@@ -2374,9 +2448,12 @@ int reiserfs_prepare_write(struct file *f, struct page *page,
if (old_ref)
th->t_refcount--;
else {
int err;
reiserfs_write_lock(inode->i_sb);
reiserfs_end_persistent_transaction(th);
err = reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb);
if (err)
ret = err;
}
}
}
......@@ -2417,20 +2494,28 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
(have_small_tails (inode->i_sb) && inode->i_size > i_block_size(inode)) )
REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask ;
journal_begin(&myth, inode->i_sb, 1) ;
ret = journal_begin(&myth, inode->i_sb, 1) ;
if (ret) {
reiserfs_write_unlock(inode->i_sb);
goto journal_error;
}
reiserfs_update_inode_transaction(inode) ;
inode->i_size = pos ;
reiserfs_update_sd(&myth, inode) ;
update_sd = 1;
journal_end(&myth, inode->i_sb, 1) ;
ret = journal_end(&myth, inode->i_sb, 1) ;
reiserfs_write_unlock(inode->i_sb);
if (ret)
goto journal_error;
}
if (th) {
reiserfs_write_lock(inode->i_sb);
if (!update_sd)
reiserfs_update_sd(th, inode) ;
reiserfs_end_persistent_transaction(th);
ret = reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb);
if (ret)
goto out;
}
/* we test for O_SYNC here so we can commit the transaction
......@@ -2438,10 +2523,22 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
*/
if (f && (f->f_flags & O_SYNC)) {
reiserfs_write_lock(inode->i_sb);
reiserfs_commit_for_inode(inode) ;
ret = reiserfs_commit_for_inode(inode) ;
reiserfs_write_unlock(inode->i_sb);
}
out:
return ret ;
journal_error:
if (th) {
reiserfs_write_lock(inode->i_sb);
if (!update_sd)
reiserfs_update_sd(th, inode) ;
ret = reiserfs_end_persistent_transaction(th);
reiserfs_write_unlock(inode->i_sb);
}
return ret;
}
void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode )
......@@ -2667,11 +2764,16 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
if (attr->ia_size > inode->i_size) {
error = generic_cont_expand(inode, attr->ia_size) ;
if (REISERFS_I(inode)->i_prealloc_count > 0) {
int err;
struct reiserfs_transaction_handle th ;
/* we're changing at most 2 bitmaps, inode + super */
journal_begin(&th, inode->i_sb, 4) ;
err = journal_begin(&th, inode->i_sb, 4) ;
if (!err) {
reiserfs_discard_prealloc (&th, inode);
journal_end(&th, inode->i_sb, 4) ;
err = journal_end(&th, inode->i_sb, 4) ;
}
if (err)
error = err;
}
if (error)
goto out;
......
......@@ -93,12 +93,6 @@ static struct workqueue_struct *commit_wq;
#define COMMIT_NOW 2 /* end and commit this transaction */
#define WAIT 4 /* wait for the log blocks to hit the disk*/
/* state bits for the journal */
#define WRITERS_BLOCKED 1 /* set when new writers not allowed */
#define WRITERS_QUEUED 2 /* set when log is full due to too many
* writers
*/
static int do_journal_end(struct reiserfs_transaction_handle *,struct super_block *,unsigned long nblocks,int flags) ;
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) ;
......@@ -109,6 +103,18 @@ static int release_journal_dev( struct super_block *super,
static int dirty_one_transaction(struct super_block *s,
struct reiserfs_journal_list *jl);
static void flush_async_commits(void *p);
static void queue_log_writer(struct super_block *s);
/* values for join in do_journal_begin_r */
enum {
JBEGIN_REG = 0, /* regular journal begin */
JBEGIN_JOIN = 1, /* join the running transaction if at all possible */
JBEGIN_ABORT = 2, /* called from cleanup code, ignores aborted flag */
};
static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
struct super_block * p_s_sb,
unsigned long nblocks,int join);
static void init_journal_hash(struct super_block *p_s_sb) {
struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
......@@ -771,7 +777,7 @@ static int write_ordered_buffers(spinlock_t *lock,
{
struct buffer_head *bh;
struct reiserfs_jh *jh;
int ret = 0;
int ret = j->j_errno;
struct buffer_chunk chunk;
struct list_head tmp;
INIT_LIST_HEAD(&tmp);
......@@ -824,8 +830,9 @@ static int write_ordered_buffers(spinlock_t *lock,
wait_on_buffer(bh);
spin_lock(lock);
}
if (!buffer_uptodate(bh))
if (!buffer_uptodate(bh)) {
ret = -EIO;
}
put_bh(bh);
cond_resched_lock(lock);
}
......@@ -917,6 +924,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
unsigned long trans_id = jl->j_trans_id;
struct reiserfs_journal *journal = SB_JOURNAL (s);
int barrier = 0;
int retval = 0;
reiserfs_check_lock_depth(s, "flush_commit_list") ;
......@@ -927,10 +935,8 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
/* before we can put our commit blocks on disk, we have to make sure everyone older than
** us is on disk too
*/
if (jl->j_len <= 0)
BUG();
if (trans_id == journal->j_trans_id)
BUG();
BUG_ON (jl->j_len <= 0);
BUG_ON (trans_id == journal->j_trans_id);
get_journal_list(jl);
if (flushall) {
......@@ -946,8 +952,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
up(&jl->j_commit_lock);
goto put_jl;
}
if (jl->j_trans_id == 0)
BUG();
BUG_ON (jl->j_trans_id == 0);
/* this commit is done, exit */
if (atomic_read(&(jl->j_commit_left)) <= 0) {
......@@ -964,8 +969,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
journal, jl, &jl->j_bh_list);
lock_kernel();
}
if (!list_empty(&jl->j_bh_list))
BUG();
BUG_ON (!list_empty(&jl->j_bh_list));
/*
* for the description block and all the log blocks, submit any buffers
* that haven't already reached the disk
......@@ -975,7 +979,7 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start+i) %
SB_ONDISK_JOURNAL_SIZE(s);
tbh = journal_find_get_block(s, bn) ;
if (buffer_dirty(tbh))
if (buffer_dirty(tbh)) /* redundant, ll_rw_block() checks */
ll_rw_block(WRITE, 1, &tbh) ;
put_bh(tbh) ;
}
......@@ -1003,18 +1007,20 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
// since we're using ll_rw_blk above, it might have skipped over
// a locked buffer. Double check here
//
if (buffer_dirty(tbh))
if (buffer_dirty(tbh)) /* redundant, sync_dirty_buffer() checks */
sync_dirty_buffer(tbh);
if (!buffer_uptodate(tbh)) {
reiserfs_panic(s, "journal-601, buffer write failed\n") ;
if (unlikely (!buffer_uptodate(tbh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(s, "journal-601, buffer write failed") ;
#endif
retval = -EIO;
}
put_bh(tbh) ; /* once for journal_find_get_block */
put_bh(tbh) ; /* once due to original getblk in do_journal_end */
atomic_dec(&(jl->j_commit_left)) ;
}
if (atomic_read(&(jl->j_commit_left)) != 1)
BUG();
BUG_ON (atomic_read(&(jl->j_commit_left)) != 1);
if (!barrier) {
if (buffer_dirty(jl->j_commit_bh))
......@@ -1025,8 +1031,15 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
wait_on_buffer(jl->j_commit_bh);
check_barrier_completion(s, jl->j_commit_bh);
if (!buffer_uptodate(jl->j_commit_bh)) {
reiserfs_panic(s, "journal-615: buffer write failed\n") ;
/* If there was a write error in the journal - we can't commit this
* transaction - it will be invalid and, if successful, will just end
* up propogating the write error out to the filesystem. */
if (unlikely (!buffer_uptodate(jl->j_commit_bh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(s, "journal-615: buffer write failed") ;
#endif
retval = -EIO;
}
bforget(jl->j_commit_bh) ;
if (journal->j_last_commit_id != 0 &&
......@@ -1040,7 +1053,10 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
/* now, every commit block is on the disk. It is safe to allow blocks freed during this transaction to be reallocated */
cleanup_freed_for_journal_list(s, jl) ;
retval = retval ? retval : journal->j_errno;
/* mark the metadata dirty */
if (!retval)
dirty_one_transaction(s, jl);
atomic_dec(&(jl->j_commit_left)) ;
......@@ -1050,7 +1066,10 @@ static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list
up(&jl->j_commit_lock);
put_jl:
put_journal_list(s, jl);
return 0 ;
if (retval)
reiserfs_abort (s, retval, "Journal write error in %s", __FUNCTION__);
return retval;
}
/*
......@@ -1113,11 +1132,18 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reis
static int _update_journal_header_block(struct super_block *p_s_sb, unsigned long offset, unsigned long trans_id) {
struct reiserfs_journal_header *jh ;
struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
if (reiserfs_is_journal_aborted (journal))
return -EIO;
if (trans_id >= journal->j_last_flush_trans_id) {
if (buffer_locked((journal->j_header_bh))) {
wait_on_buffer((journal->j_header_bh)) ;
if (!buffer_uptodate(journal->j_header_bh)) {
reiserfs_panic(p_s_sb, "journal-699: buffer write failed\n") ;
if (unlikely (!buffer_uptodate(journal->j_header_bh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning (p_s_sb, "journal-699: buffer write failed") ;
#endif
return -EIO;
}
}
journal->j_last_flush_trans_id = trans_id ;
......@@ -1154,10 +1180,7 @@ static int _update_journal_header_block(struct super_block *p_s_sb, unsigned lon
static int update_journal_header_block(struct super_block *p_s_sb,
unsigned long offset,
unsigned long trans_id) {
if (_update_journal_header_block(p_s_sb, offset, trans_id)) {
reiserfs_panic(p_s_sb, "journal-712: buffer write failed\n") ;
}
return 0 ;
return _update_journal_header_block(p_s_sb, offset, trans_id);
}
/*
** flush any and all journal lists older than you are
......@@ -1176,8 +1199,12 @@ static int flush_older_journal_lists(struct super_block *p_s_sb,
*/
restart:
entry = journal->j_journal_list.next;
/* Did we wrap? */
if (entry == &journal->j_journal_list)
return 0;
other_jl = JOURNAL_LIST_ENTRY(entry);
if (other_jl->j_trans_id < trans_id) {
BUG_ON (other_jl->j_refcount <= 0);
/* do not flush all */
flush_journal_list(p_s_sb, other_jl, 0) ;
......@@ -1215,17 +1242,15 @@ static int flush_journal_list(struct super_block *s,
struct buffer_head *saved_bh ;
unsigned long j_len_saved = jl->j_len ;
struct reiserfs_journal *journal = SB_JOURNAL (s);
int err = 0;
if (j_len_saved <= 0) {
BUG();
}
BUG_ON (j_len_saved <= 0);
if (atomic_read(&journal->j_wcount) != 0) {
reiserfs_warning(s, "clm-2048: flush_journal_list called with wcount %d",
atomic_read(&journal->j_wcount)) ;
}
if (jl->j_trans_id == 0)
BUG();
BUG_ON (jl->j_trans_id == 0);
/* if flushall == 0, the lock is already held */
if (flushall) {
......@@ -1251,7 +1276,7 @@ static int flush_journal_list(struct super_block *s,
*/
flush_commit_list(s, jl, 1) ;
if (!(jl->j_state & LIST_DIRTY))
if (!(jl->j_state & LIST_DIRTY) && !reiserfs_is_journal_aborted (journal))
BUG();
/* are we done now? */
......@@ -1275,6 +1300,11 @@ static int flush_journal_list(struct super_block *s,
if (cn->blocknr == 0) {
goto free_cnode ;
}
/* This transaction failed commit. Don't write out to the disk */
if (!(jl->j_state & LIST_DIRTY))
goto free_cnode;
pjl = find_newer_jl_for_cn(cn) ;
/* the order is important here. We check pjl to make sure we
** don't clear BH_JDirty_wait if we aren't the one writing this
......@@ -1289,8 +1319,7 @@ static int flush_journal_list(struct super_block *s,
get_bh(saved_bh) ;
if (buffer_journal_dirty(saved_bh)) {
if (!can_dirty(cn))
BUG();
BUG_ON (!can_dirty (cn));
was_jwait = 1 ;
was_dirty = 1 ;
} else if (can_dirty(cn)) {
......@@ -1330,8 +1359,7 @@ static int flush_journal_list(struct super_block *s,
get_bh(saved_bh) ;
set_bit(BLOCK_NEEDS_FLUSH, &cn->state) ;
lock_buffer(saved_bh);
if (cn->blocknr != saved_bh->b_blocknr)
BUG();
BUG_ON (cn->blocknr != saved_bh->b_blocknr);
if (buffer_dirty(saved_bh))
submit_logged_buffer(saved_bh) ;
else
......@@ -1363,14 +1391,16 @@ static int flush_journal_list(struct super_block *s,
if (!cn->bh) {
reiserfs_panic(s, "journal-1012: cn->bh is NULL\n") ;
}
if (!buffer_uptodate(cn->bh)) {
reiserfs_panic(s, "journal-949: buffer write failed\n") ;
if (unlikely (!buffer_uptodate(cn->bh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(s, "journal-949: buffer write failed\n") ;
#endif
err = -EIO;
}
/* note, we must clear the JDirty_wait bit after the up to date
** check, otherwise we race against our flushpage routine
*/
if (!test_clear_buffer_journal_dirty (cn->bh))
BUG();
BUG_ON (!test_clear_buffer_journal_dirty (cn->bh));
/* undo the inc from journal_mark_dirty */
put_bh(cn->bh) ;
......@@ -1380,7 +1410,11 @@ static int flush_journal_list(struct super_block *s,
}
}
if (err)
reiserfs_abort (s, -EIO, "Write error while pushing transaction to disk in %s", __FUNCTION__);
flush_older_and_return:
/* before we can update the journal header block, we _must_ flush all
** real blocks from all older transactions to disk. This is because
** once the header block is updated, this transaction will not be
......@@ -1390,6 +1424,7 @@ static int flush_journal_list(struct super_block *s,
flush_older_journal_lists(s, jl);
}
err = journal->j_errno;
/* before we can remove everything from the hash tables for this
** transaction, we must make sure it can never be replayed
**
......@@ -1398,11 +1433,13 @@ static int flush_journal_list(struct super_block *s,
** we only need to update the journal header block for the last list
** being flushed
*/
if (flushall) {
update_journal_header_block(s, (jl->j_start + jl->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(s), jl->j_trans_id) ;
if (!err && flushall) {
err = update_journal_header_block(s, (jl->j_start + jl->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(s), jl->j_trans_id) ;
if (err)
reiserfs_abort (s, -EIO, "Write error while updating journal header in %s", __FUNCTION__);
}
remove_all_from_journal_list(s, jl, 0) ;
list_del(&jl->j_list);
list_del_init(&jl->j_list);
journal->j_num_lists--;
del_from_work_list(s, jl);
......@@ -1427,7 +1464,7 @@ static int flush_journal_list(struct super_block *s,
put_journal_list(s, jl);
if (flushall)
up(&journal->j_flush_sem);
return 0 ;
return err ;
}
static int write_one_transaction(struct super_block *s,
......@@ -1497,8 +1534,7 @@ static int dirty_one_transaction(struct super_block *s,
pjl = find_newer_jl_for_cn(cn) ;
if (!pjl && cn->blocknr && cn->bh && buffer_journal_dirty(cn->bh))
{
if (!can_dirty(cn))
BUG();
BUG_ON (!can_dirty(cn));
/* if the buffer is prepared, it will either be logged
* or restored. If restored, we need to make sure
* it actually gets marked dirty
......@@ -1543,7 +1579,7 @@ static int kupdate_transactions(struct super_block *s,
(!num_trans && written < num_blocks)) {
if (jl->j_len == 0 || (jl->j_state & LIST_TOUCHED) ||
atomic_read(&jl->j_commit_left))
atomic_read(&jl->j_commit_left) || !(jl->j_state & LIST_DIRTY))
{
del_from_work_list(s, jl);
break;
......@@ -1693,18 +1729,33 @@ static void free_journal_ram(struct super_block *p_s_sb) {
*/
static int do_journal_release(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, int error) {
struct reiserfs_transaction_handle myth ;
int flushed = 0;
struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
/* we only want to flush out transactions if we were called with error == 0
*/
if (!error && !(p_s_sb->s_flags & MS_RDONLY)) {
/* end the current trans */
BUG_ON (!th->t_trans_id);
do_journal_end(th, p_s_sb,10, FLUSH_ALL) ;
/* make sure something gets logged to force our way into the flush code */
journal_join(&myth, p_s_sb, 1) ;
if (!journal_join(&myth, p_s_sb, 1)) {
reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
journal_mark_dirty(&myth, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
do_journal_end(&myth, p_s_sb,1, FLUSH_ALL) ;
flushed = 1;
}
}
/* this also catches errors during the do_journal_end above */
if (!error && reiserfs_is_journal_aborted(journal)) {
memset(&myth, 0, sizeof(myth));
if (!journal_join_abort(&myth, p_s_sb, 1)) {
reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
journal_mark_dirty(&myth, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL) ;
}
}
reiserfs_mounted_fs_count-- ;
......@@ -2314,6 +2365,7 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
INIT_LIST_HEAD (&journal->j_prealloc_list);
INIT_LIST_HEAD(&journal->j_working_list);
INIT_LIST_HEAD(&journal->j_journal_list);
journal->j_persistent_trans = 0;
if (reiserfs_allocate_list_bitmaps(p_s_sb,
journal->j_list_bitmap,
SB_BMAP_NR(p_s_sb)))
......@@ -2492,6 +2544,7 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th, int n
struct reiserfs_journal *journal = SB_JOURNAL (th->t_super);
time_t now = get_seconds() ;
/* cannot restart while nested */
BUG_ON (!th->t_trans_id);
if (th->t_refcount > 1)
return 0 ;
if ( journal->j_must_wait > 0 ||
......@@ -2509,8 +2562,9 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th, int n
*/
void reiserfs_block_writes(struct reiserfs_transaction_handle *th) {
struct reiserfs_journal *journal = SB_JOURNAL (th->t_super);
BUG_ON (!th->t_trans_id);
journal->j_must_wait = 1 ;
set_bit(WRITERS_BLOCKED, &journal->j_state) ;
set_bit(J_WRITERS_BLOCKED, &journal->j_state) ;
return ;
}
......@@ -2519,7 +2573,7 @@ void reiserfs_block_writes(struct reiserfs_transaction_handle *th) {
*/
void reiserfs_allow_writes(struct super_block *s) {
struct reiserfs_journal *journal = SB_JOURNAL (s);
clear_bit(WRITERS_BLOCKED, &journal->j_state) ;
clear_bit(J_WRITERS_BLOCKED, &journal->j_state) ;
wake_up(&journal->j_join_wait) ;
}
......@@ -2529,13 +2583,13 @@ void reiserfs_allow_writes(struct super_block *s) {
void reiserfs_wait_on_write_block(struct super_block *s) {
struct reiserfs_journal *journal = SB_JOURNAL (s);
wait_event(journal->j_join_wait,
!test_bit(WRITERS_BLOCKED, &journal->j_state)) ;
!test_bit(J_WRITERS_BLOCKED, &journal->j_state)) ;
}
static void queue_log_writer(struct super_block *s) {
wait_queue_t wait;
struct reiserfs_journal *journal = SB_JOURNAL (s);
set_bit(WRITERS_QUEUED, &journal->j_state);
set_bit(J_WRITERS_QUEUED, &journal->j_state);
/*
* we don't want to use wait_event here because
......@@ -2544,7 +2598,7 @@ static void queue_log_writer(struct super_block *s) {
init_waitqueue_entry(&wait, current);
add_wait_queue(&journal->j_join_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
if (test_bit(WRITERS_QUEUED, &journal->j_state))
if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
schedule();
current->state = TASK_RUNNING;
remove_wait_queue(&journal->j_join_wait, &wait);
......@@ -2552,7 +2606,7 @@ static void queue_log_writer(struct super_block *s) {
static void wake_queued_writers(struct super_block *s) {
struct reiserfs_journal *journal = SB_JOURNAL (s);
if (test_and_clear_bit(WRITERS_QUEUED, &journal->j_state))
if (test_and_clear_bit(J_WRITERS_QUEUED, &journal->j_state))
wake_up(&journal->j_join_wait);
}
......@@ -2590,10 +2644,9 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
struct reiserfs_transaction_handle myth;
int sched_count = 0;
int retval;
reiserfs_check_lock_depth(p_s_sb, "journal_begin") ;
RFALSE( p_s_sb->s_flags & MS_RDONLY,
"clm-2078: calling journal_begin on readonly FS") ;
PROC_INFO_INC( p_s_sb, journal.journal_being );
/* set here for journal_join */
......@@ -2602,9 +2655,14 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
relock:
lock_journal(p_s_sb) ;
if (join != JBEGIN_ABORT && reiserfs_is_journal_aborted (journal)) {
unlock_journal (p_s_sb);
retval = journal->j_errno;
goto out_fail;
}
journal->j_bcount++;
if (test_bit(WRITERS_BLOCKED, &journal->j_state)) {
if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) {
unlock_journal(p_s_sb) ;
reiserfs_wait_on_write_block(p_s_sb) ;
PROC_INFO_INC( p_s_sb, journal.journal_relock_writers );
......@@ -2647,15 +2705,20 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
}
goto relock;
}
journal_join(&myth, p_s_sb, 1) ;
retval = journal_join(&myth, p_s_sb, 1) ;
if (retval)
goto out_fail;
/* someone might have ended the transaction while we joined */
if (old_trans_id != journal->j_trans_id) {
do_journal_end(&myth, p_s_sb, 1, 0) ;
retval = do_journal_end(&myth, p_s_sb, 1, 0) ;
} else {
do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW) ;
retval = do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW) ;
}
if (retval)
goto out_fail;
PROC_INFO_INC( p_s_sb, journal.journal_relock_wcount );
goto relock ;
}
......@@ -2669,7 +2732,16 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
th->t_blocks_allocated = nblocks ;
th->t_trans_id = journal->j_trans_id ;
unlock_journal(p_s_sb) ;
INIT_LIST_HEAD (&th->t_list);
return 0 ;
out_fail:
memset (th, 0, sizeof (*th));
/* Re-set th->t_super, so we can properly keep track of how many
* persistent transactions there are. We need to do this so if this
* call is part of a failed restart_transaction, we can free it later */
th->t_super = p_s_sb;
return retval;
}
struct reiserfs_transaction_handle *
......@@ -2696,16 +2768,23 @@ reiserfs_persistent_transaction(struct super_block *s, int nblocks) {
reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle), s) ;
return NULL;
}
SB_JOURNAL(s)->j_persistent_trans++;
return th ;
}
int
reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *th) {
struct super_block *s = th->t_super;
int ret;
int ret = 0;
if (th->t_trans_id)
ret = journal_end(th, th->t_super, th->t_blocks_allocated);
if (th->t_refcount == 0)
else
ret = -EIO;
if (th->t_refcount == 0) {
SB_JOURNAL(s)->j_persistent_trans--;
reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle), s) ;
}
return ret;
}
......@@ -2719,7 +2798,20 @@ static int journal_join(struct reiserfs_transaction_handle *th, struct super_blo
if (cur_th && cur_th->t_refcount > 1) {
BUG() ;
}
return do_journal_begin_r(th, p_s_sb, nblocks, 1) ;
return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN) ;
}
int journal_join_abort(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, JBEGIN_ABORT) ;
}
int journal_begin(struct reiserfs_transaction_handle *th, struct super_block * p_s_sb, unsigned long nblocks) {
......@@ -2730,6 +2822,7 @@ int journal_begin(struct reiserfs_transaction_handle *th, struct super_block *
if (cur_th) {
/* we are nesting into the current transaction */
if (cur_th->t_super == p_s_sb) {
BUG_ON (!cur_th->t_refcount);
cur_th->t_refcount++ ;
memcpy(th, cur_th, sizeof(*th));
if (th->t_refcount <= 1)
......@@ -2747,9 +2840,18 @@ int journal_begin(struct reiserfs_transaction_handle *th, struct super_block *
} else {
current->journal_info = th;
}
ret = do_journal_begin_r(th, p_s_sb, nblocks, 0) ;
ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG) ;
if (current->journal_info != th)
BUG() ;
/* I guess this boils down to being the reciprocal of clm-2100 above.
* If do_journal_begin_r fails, we need to put it back, since journal_end
* won't be called to do it. */
if (ret)
current->journal_info = th->t_handle_save;
else
BUG_ON (!th->t_refcount);
return ret ;
}
......@@ -2767,12 +2869,14 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th, struct super_bloc
struct reiserfs_journal_cnode *cn = NULL;
int count_already_incd = 0 ;
int prepared = 0 ;
BUG_ON (!th->t_trans_id);
PROC_INFO_INC( p_s_sb, journal.mark_dirty );
if (th->t_trans_id != journal->j_trans_id) {
reiserfs_panic(th->t_super, "journal-1577: handle trans id %ld != current trans id %ld\n",
th->t_trans_id, journal->j_trans_id);
}
p_s_sb->s_dirt = 1;
prepared = test_clear_buffer_journal_prepared (bh);
......@@ -2860,6 +2964,11 @@ int journal_end(struct reiserfs_transaction_handle *th, struct super_block *p_s_
reiserfs_warning (p_s_sb, "REISER-NESTING: th NULL, refcount %d",
th->t_refcount);
if (!th->t_trans_id) {
WARN_ON (1);
return -EIO;
}
th->t_refcount--;
if (th->t_refcount > 0) {
struct reiserfs_transaction_handle *cur_th = current->journal_info ;
......@@ -2976,6 +3085,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) {
int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
BUG_ON (!th->t_trans_id);
/* you can sync while nested, very, very bad */
if (th->t_refcount > 1) {
BUG() ;
......@@ -3008,7 +3118,7 @@ static void flush_async_commits(void *p) {
* this is a little racey, but there's no harm in missing
* the filemap_fdata_write
*/
if (!atomic_read(&journal->j_async_throttle)) {
if (!atomic_read(&journal->j_async_throttle) && !reiserfs_is_journal_aborted (journal)) {
atomic_inc(&journal->j_async_throttle);
filemap_fdatawrite(p_s_sb->s_bdev->bd_inode->i_mapping);
atomic_dec(&journal->j_async_throttle);
......@@ -3040,7 +3150,7 @@ int reiserfs_flush_old_commits(struct super_block *p_s_sb) {
journal->j_len > 0 &&
(now - journal->j_trans_start_time) > journal->j_max_trans_age)
{
journal_join(&th, p_s_sb, 1) ;
if (!journal_join(&th, p_s_sb, 1)) {
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)) ;
......@@ -3049,6 +3159,7 @@ int reiserfs_flush_old_commits(struct super_block *p_s_sb) {
*/
do_journal_end(&th, p_s_sb,1, COMMIT_NOW | WAIT) ;
}
}
return p_s_sb->s_dirt;
}
......@@ -3073,6 +3184,8 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, struct supe
struct reiserfs_journal_list *jl;
struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
BUG_ON (!th->t_trans_id);
if (th->t_trans_id != journal->j_trans_id) {
reiserfs_panic(th->t_super, "journal-1577: handle trans id %ld != current trans id %ld\n",
th->t_trans_id, journal->j_trans_id);
......@@ -3178,6 +3291,7 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, struct super_bloc
struct buffer_head *bh = NULL ;
struct reiserfs_list_bitmap *jb = NULL ;
int cleaned = 0 ;
BUG_ON (!th->t_trans_id);
cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr);
if (cn && cn->bh) {
......@@ -3269,17 +3383,20 @@ static int __commit_trans_jl(struct inode *inode, unsigned long id,
goto flush_commit_only;
}
journal_begin(&th, sb, 1) ;
ret = journal_begin(&th, sb, 1) ;
if (ret)
return ret;
/* someone might have ended this transaction while we joined */
if (journal->j_trans_id != id) {
reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb), 1) ;
journal_mark_dirty(&th, sb, SB_BUFFER_WITH_SB(sb)) ;
journal_end(&th, sb, 1) ;
ret = journal_end(&th, sb, 1) ;
goto flush_commit_only;
}
journal_end_sync(&th, sb, 1) ;
ret = journal_end_sync(&th, sb, 1) ;
if (!ret)
ret = 1;
} else {
......@@ -3297,6 +3414,8 @@ static int __commit_trans_jl(struct inode *inode, unsigned long id,
if (atomic_read(&jl->j_commit_left) > 1)
ret = 1;
flush_commit_list(sb, jl, 1) ;
if (journal->j_errno)
ret = journal->j_errno;
}
}
/* otherwise the list is gone, and long since committed */
......@@ -3390,6 +3509,9 @@ static void flush_old_journal_lists(struct super_block *s) {
** If no_async, won't return until all commit blocks are on disk.
**
** keep reading, there are comments as you go along
**
** If the journal is aborted, we just clean up. Things like flushing
** journal lists, etc just won't happen.
*/
static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_block * p_s_sb, unsigned long nblocks,
int flags) {
......@@ -3411,8 +3533,8 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
unsigned long commit_trans_id;
int trans_half;
if (th->t_refcount > 1)
BUG() ;
BUG_ON (th->t_refcount > 1);
BUG_ON (!th->t_trans_id);
current->journal_info = th->t_handle_save;
reiserfs_check_lock_depth(p_s_sb, "journal end");
......@@ -3707,7 +3829,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
atomic_set(&(journal->j_jlock), 0) ;
unlock_journal(p_s_sb) ;
/* wake up any body waiting to join. */
clear_bit(WRITERS_QUEUED, &journal->j_state);
clear_bit(J_WRITERS_QUEUED, &journal->j_state);
wake_up(&(journal->j_join_wait)) ;
if (!flush && wait_on_commit &&
......@@ -3716,6 +3838,49 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
}
out:
reiserfs_check_lock_depth(p_s_sb, "journal end2");
th->t_trans_id = 0;
return 0 ;
memset (th, 0, sizeof (*th));
/* Re-set th->t_super, so we can properly keep track of how many
* persistent transactions there are. We need to do this so if this
* call is part of a failed restart_transaction, we can free it later */
th->t_super = p_s_sb;
return journal->j_errno;
}
void
__reiserfs_journal_abort_hard (struct super_block *sb)
{
struct reiserfs_journal *journal = SB_JOURNAL (sb);
if (test_bit (J_ABORTED, &journal->j_state))
return;
printk (KERN_CRIT "REISERFS: Aborting journal for filesystem on %s\n",
reiserfs_bdevname (sb));
sb->s_flags |= MS_RDONLY;
set_bit (J_ABORTED, &journal->j_state);
#ifdef CONFIG_REISERFS_CHECK
dump_stack();
#endif
}
void
__reiserfs_journal_abort_soft (struct super_block *sb, int errno)
{
struct reiserfs_journal *journal = SB_JOURNAL (sb);
if (test_bit (J_ABORTED, &journal->j_state))
return;
if (!journal->j_errno)
journal->j_errno = errno;
__reiserfs_journal_abort_hard (sb);
}
void
reiserfs_journal_abort (struct super_block *sb, int errno)
{
return __reiserfs_journal_abort_soft (sb, errno);
}
......@@ -430,6 +430,7 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in
int buflen, paste_size;
int retval;
BUG_ON (!th->t_trans_id);
/* cannot allow items to be added into a busy deleted directory */
if (!namelen)
......@@ -606,14 +607,19 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode,
if (locked)
reiserfs_write_lock_xattrs (dir->i_sb);
journal_begin(&th, dir->i_sb, jbegin_count) ;
retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode);
if (locked)
reiserfs_write_unlock_xattrs (dir->i_sb);
retval = journal_begin(&th, dir->i_sb, jbegin_count);
if (retval) {
drop_new_inode (inode);
goto out_failed;
}
retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
if (retval)
goto out_failed;
if (locked) {
reiserfs_write_unlock_xattrs (dir->i_sb);
locked = 0;
}
inode->i_op = &reiserfs_file_inode_operations;
......@@ -623,9 +629,12 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode,
retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
inode, 1/*visible*/);
if (retval) {
int err;
inode->i_nlink--;
reiserfs_update_sd (&th, inode);
journal_end(&th, dir->i_sb, jbegin_count) ;
err = journal_end(&th, dir->i_sb, jbegin_count) ;
if (err)
retval = err;
iput (inode);
goto out_failed;
}
......@@ -633,9 +642,11 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode,
reiserfs_update_inode_transaction(dir) ;
d_instantiate(dentry, inode);
journal_end(&th, dir->i_sb, jbegin_count) ;
retval = journal_end(&th, dir->i_sb, jbegin_count) ;
out_failed:
if (locked)
reiserfs_write_unlock_xattrs (dir->i_sb);
reiserfs_write_unlock(dir->i_sb);
return retval;
}
......@@ -666,17 +677,23 @@ static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode,
if (locked)
reiserfs_write_lock_xattrs (dir->i_sb);
journal_begin(&th, dir->i_sb, jbegin_count) ;
retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
if (retval) {
drop_new_inode (inode);
goto out_failed;
}
retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode);
if (locked)
reiserfs_write_unlock_xattrs (dir->i_sb);
if (retval) {
goto out_failed;
}
if (locked) {
reiserfs_write_unlock_xattrs (dir->i_sb);
locked = 0;
}
inode->i_op = &reiserfs_special_inode_operations;
init_special_inode(inode, inode->i_mode, rdev) ;
......@@ -689,17 +706,22 @@ static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode,
retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
inode, 1/*visible*/);
if (retval) {
int err;
inode->i_nlink--;
reiserfs_update_sd (&th, inode);
journal_end(&th, dir->i_sb, jbegin_count) ;
err = journal_end(&th, dir->i_sb, jbegin_count) ;
if (err)
retval = err;
iput (inode);
goto out_failed;
}
d_instantiate(dentry, inode);
journal_end(&th, dir->i_sb, jbegin_count) ;
retval = journal_end(&th, dir->i_sb, jbegin_count) ;
out_failed:
if (locked)
reiserfs_write_unlock_xattrs (dir->i_sb);
reiserfs_write_unlock(dir->i_sb);
return retval;
}
......@@ -730,7 +752,13 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
reiserfs_write_lock(dir->i_sb);
if (locked)
reiserfs_write_lock_xattrs (dir->i_sb);
journal_begin(&th, dir->i_sb, jbegin_count) ;
retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
if (retval) {
drop_new_inode (inode);
goto out_failed;
}
/* inc the link count now, so another writer doesn't overflow it while
** we sleep later on.
......@@ -741,13 +769,16 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
old_format_only (dir->i_sb) ?
EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
dentry, inode);
if (locked)
reiserfs_write_unlock_xattrs (dir->i_sb);
if (retval) {
dir->i_nlink-- ;
goto out_failed;
}
if (locked) {
reiserfs_write_unlock_xattrs (dir->i_sb);
locked = 0;
}
reiserfs_update_inode_transaction(inode) ;
reiserfs_update_inode_transaction(dir) ;
......@@ -758,10 +789,13 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
inode, 1/*visible*/);
if (retval) {
int err;
inode->i_nlink = 0;
DEC_DIR_INODE_NLINK(dir);
reiserfs_update_sd (&th, inode);
journal_end(&th, dir->i_sb, jbegin_count) ;
err = journal_end(&th, dir->i_sb, jbegin_count) ;
if (err)
retval = err;
iput (inode);
goto out_failed;
}
......@@ -770,8 +804,10 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
reiserfs_update_sd (&th, dir);
d_instantiate(dentry, inode);
journal_end(&th, dir->i_sb, jbegin_count) ;
retval = journal_end(&th, dir->i_sb, jbegin_count) ;
out_failed:
if (locked)
reiserfs_write_unlock_xattrs (dir->i_sb);
reiserfs_write_unlock(dir->i_sb);
return retval;
}
......@@ -791,7 +827,7 @@ static inline int reiserfs_empty_dir(struct inode *inode) {
static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
{
int retval;
int retval, err;
struct inode * inode;
struct reiserfs_transaction_handle th ;
int jbegin_count;
......@@ -803,7 +839,9 @@ static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
reiserfs_write_lock(dir->i_sb);
journal_begin(&th, dir->i_sb, jbegin_count) ;
retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
if (retval)
goto out_rmdir;
de.de_gen_number_bit_string = NULL;
if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
......@@ -852,24 +890,25 @@ static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
/* prevent empty directory from getting lost */
add_save_link (&th, inode, 0/* not truncate */);
journal_end(&th, dir->i_sb, jbegin_count) ;
retval = journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_check_path(&path) ;
out_rmdir:
reiserfs_write_unlock(dir->i_sb);
return 0;
return retval;
end_rmdir:
/* we must release path, because we did not call
reiserfs_cut_from_item, or reiserfs_cut_from_item does not
release path if operation was not complete */
pathrelse (&path);
journal_end(&th, dir->i_sb, jbegin_count) ;
err = journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_write_unlock(dir->i_sb);
return retval;
return err ? err : retval;
}
static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
{
int retval;
int retval, err;
struct inode * inode;
struct reiserfs_dir_entry de;
INITIALIZE_PATH (path);
......@@ -884,7 +923,9 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
reiserfs_write_lock(dir->i_sb);
journal_begin(&th, dir->i_sb, jbegin_count) ;
retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
if (retval)
goto out_unlink;
de.de_gen_number_bit_string = NULL;
if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
......@@ -938,15 +979,18 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
/* prevent file from getting lost */
add_save_link (&th, inode, 0/* not truncate */);
journal_end(&th, dir->i_sb, jbegin_count) ;
retval = journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_check_path(&path) ;
reiserfs_write_unlock(dir->i_sb);
return 0;
return retval;
end_unlink:
pathrelse (&path);
journal_end(&th, dir->i_sb, jbegin_count) ;
err = journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_check_path(&path) ;
if (err)
retval = err;
out_unlink:
reiserfs_write_unlock(dir->i_sb);
return retval;
}
......@@ -989,7 +1033,12 @@ static int reiserfs_symlink (struct inode * parent_dir,
/* We would inherit the default ACL here, but symlinks don't get ACLs */
journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
retval = journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
if (retval) {
drop_new_inode (inode);
reiserfs_kfree (name, item_len, parent_dir->i_sb);
goto out_failed;
}
retval = reiserfs_new_inode (&th, parent_dir, mode, name, strlen (symname),
dentry, inode);
......@@ -1011,15 +1060,18 @@ static int reiserfs_symlink (struct inode * parent_dir,
retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name,
dentry->d_name.len, inode, 1/*visible*/);
if (retval) {
int err;
inode->i_nlink--;
reiserfs_update_sd (&th, inode);
journal_end(&th, parent_dir->i_sb, jbegin_count) ;
err = journal_end(&th, parent_dir->i_sb, jbegin_count) ;
if (err)
retval = err;
iput (inode);
goto out_failed;
}
d_instantiate(dentry, inode);
journal_end(&th, parent_dir->i_sb, jbegin_count) ;
retval = journal_end(&th, parent_dir->i_sb, jbegin_count) ;
out_failed:
reiserfs_write_unlock(parent_dir->i_sb);
return retval;
......@@ -1045,7 +1097,12 @@ static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct
/* inc before scheduling so reiserfs_unlink knows we are here */
inode->i_nlink++;
journal_begin(&th, dir->i_sb, jbegin_count) ;
retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
if (retval) {
inode->i_nlink--;
reiserfs_write_unlock (dir->i_sb);
return retval;
}
/* create new entry */
retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
......@@ -1055,10 +1112,11 @@ static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct
reiserfs_update_inode_transaction(dir) ;
if (retval) {
int err;
inode->i_nlink--;
journal_end(&th, dir->i_sb, jbegin_count) ;
err = journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_write_unlock(dir->i_sb);
return retval;
return err ? err : retval;
}
inode->i_ctime = CURRENT_TIME;
......@@ -1066,9 +1124,9 @@ static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct
atomic_inc(&inode->i_count) ;
d_instantiate(dentry, inode);
journal_end(&th, dir->i_sb, jbegin_count) ;
retval = journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_write_unlock(dir->i_sb);
return 0;
return retval;
}
......@@ -1195,7 +1253,12 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
}
}
journal_begin(&th, old_dir->i_sb, jbegin_count) ;
retval = journal_begin(&th, old_dir->i_sb, jbegin_count) ;
if (retval) {
reiserfs_write_unlock (old_dir->i_sb);
return retval;
}
/* add new entry (or find the existing one) */
retval = reiserfs_add_entry (&th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len,
......@@ -1206,9 +1269,9 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
"vs-7050: new entry is found, new inode == 0\n");
}
} else if (retval) {
journal_end(&th, old_dir->i_sb, jbegin_count) ;
int err = journal_end(&th, old_dir->i_sb, jbegin_count) ;
reiserfs_write_unlock(old_dir->i_sb);
return retval;
return err ? err : retval;
}
reiserfs_update_inode_transaction(old_dir) ;
......@@ -1357,9 +1420,9 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
reiserfs_update_sd (&th, new_dentry_inode);
}
journal_end(&th, old_dir->i_sb, jbegin_count) ;
retval = journal_end(&th, old_dir->i_sb, jbegin_count) ;
reiserfs_write_unlock(old_dir->i_sb);
return 0;
return retval;
}
/*
......@@ -1414,5 +1477,3 @@ struct inode_operations reiserfs_special_inode_operations = {
.permission = reiserfs_permission,
};
......@@ -55,6 +55,7 @@ __u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th)
__u32 * map = objectid_map (s, rs);
__u32 unused_objectid;
BUG_ON (!th->t_trans_id);
check_objectid_map (s, map);
......@@ -99,6 +100,7 @@ void reiserfs_release_objectid (struct reiserfs_transaction_handle *th,
__u32 * map = objectid_map (s, rs);
int i = 0;
BUG_ON (!th->t_trans_id);
//return;
check_objectid_map (s, map);
......
......@@ -366,6 +366,49 @@ void reiserfs_panic (struct super_block * sb, const char * fmt, ...)
reiserfs_bdevname (sb), error_buf);
}
static void
do_handle_error (struct super_block *sb, int errno)
{
if (reiserfs_error_panic (sb)) {
panic ("REISERFS: panic (device %s): Panic forced after error\n",
reiserfs_bdevname (sb));
}
if (reiserfs_error_ro (sb)) {
printk (KERN_CRIT "REISERFS: error (device %s): Re-mounting fs "
"readonly\n", reiserfs_bdevname (sb));
reiserfs_journal_abort (sb, errno);
}
}
void
reiserfs_error (struct super_block * sb, int errno, const char *fmt, ...)
{
do_reiserfs_warning (fmt);
printk (KERN_CRIT "REISERFS: error (device %s): %s\n",
reiserfs_bdevname (sb), error_buf);
do_handle_error (sb, errno);
}
void
reiserfs_abort (struct super_block *sb, int errno, const char *fmt, ...)
{
do_reiserfs_warning (fmt);
if (reiserfs_error_panic (sb)) {
panic (KERN_CRIT "REISERFS: panic (device %s): %s\n",
reiserfs_bdevname (sb), error_buf);
}
if (sb->s_flags & MS_RDONLY)
return;
printk (KERN_CRIT "REISERFS: abort (device %s): %s\n",
reiserfs_bdevname (sb), error_buf);
sb->s_flags |= MS_RDONLY;
reiserfs_journal_abort (sb, errno);
}
void print_virtual_node (struct virtual_node * vn)
{
......
......@@ -19,8 +19,10 @@
int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
{
int err = 0;
struct reiserfs_super_block * sb;
struct reiserfs_bitmap_info *bitmap;
struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
struct buffer_head * bh;
struct reiserfs_transaction_handle th;
unsigned int bmap_nr_new, bmap_nr;
......@@ -107,12 +109,19 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
* block pointers */
bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
if (!bitmap) {
/* Journal bitmaps are still supersized, but the memory isn't
* leaked, so I guess it's ok */
printk("reiserfs_resize: unable to allocate memory.\n");
return -ENOMEM;
}
memset (bitmap, 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
for (i = 0; i < bmap_nr; i++)
bitmap[i] = SB_AP_BITMAP(s)[i];
bitmap[i] = old_bitmap[i];
/* This doesn't go through the journal, but it doesn't have to.
* The changes are still atomic: We're synced up when the journal
* transaction begins, and the new bitmaps don't matter if the
* transaction fails. */
for (i = bmap_nr; i < bmap_nr_new; i++) {
bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
......@@ -126,12 +135,16 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
}
/* free old bitmap blocks array */
vfree(SB_AP_BITMAP(s));
SB_AP_BITMAP(s) = bitmap;
vfree (old_bitmap);
}
/* begin transaction */
journal_begin(&th, s, 10);
/* begin transaction, if there was an error, it's fine. Yes, we have
* incorrect bitmaps now, but none of it is ever going to touch the
* disk anyway. */
err = journal_begin(&th, s, 10);
if (err)
return err;
/* correct last bitmap blocks in old and new disk layout */
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
......@@ -165,8 +178,5 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
SB_JOURNAL(s)->j_must_wait = 1;
journal_end(&th, s, 10);
return 0;
return journal_end(&th, s, 10);
}
......@@ -1036,6 +1036,8 @@ static char prepare_for_delete_or_cut(
struct item_head * p_le_ih = PATH_PITEM_HEAD(p_s_path);
struct buffer_head * p_s_bh = PATH_PLAST_BUFFER(p_s_path);
BUG_ON (!th->t_trans_id);
/* Stat_data item. */
if ( is_statdata_le_ih (p_le_ih) ) {
......@@ -1222,6 +1224,9 @@ static void init_tb_struct(
struct path * p_s_path,
int n_size
) {
BUG_ON (!th->t_trans_id);
memset (p_s_tb,'\0',sizeof(struct tree_balance));
p_s_tb->transaction_handle = th ;
p_s_tb->tb_sb = p_s_sb;
......@@ -1290,6 +1295,8 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
int n_iter = 0;
#endif
BUG_ON (!th->t_trans_id);
init_tb_struct(th, &s_del_balance, p_s_sb, p_s_path, 0/*size is unknown*/);
while ( 1 ) {
......@@ -1420,6 +1427,8 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
int retval;
int quota_cut_bytes = 0;
BUG_ON (!th->t_trans_id);
le_key2cpu_key (&cpu_key, key);
while (1) {
......@@ -1474,12 +1483,16 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
}
void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * inode)
int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * inode)
{
int err;
inode->i_size = 0;
BUG_ON (!th->t_trans_id);
/* for directory this deletes item containing "." and ".." */
reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
err = reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
if (err)
return err;
#if defined( USE_INODE_GENERATION_COUNTER )
if( !old_format_only ( th -> t_super ) )
......@@ -1493,6 +1506,8 @@ void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inod
/* USE_INODE_GENERATION_COUNTER */
#endif
reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
return err;
}
static void
......@@ -1542,6 +1557,7 @@ static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th,
struct super_block * p_s_sb = p_s_inode->i_sb;
int n_block_size = p_s_sb->s_blocksize;
int cut_bytes;
BUG_ON (!th->t_trans_id);
if (n_new_file_size != p_s_inode->i_size)
BUG ();
......@@ -1574,6 +1590,7 @@ static void indirect_to_direct_roll_back (struct reiserfs_transaction_handle *th
struct cpu_key tail_key;
int tail_len;
int removed;
BUG_ON (!th->t_trans_id);
make_cpu_key (&tail_key, inode, inode->i_size + 1, TYPE_DIRECT, 4);// !!!!
tail_key.key_length = 4;
......@@ -1624,6 +1641,8 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
int quota_cut_bytes;
loff_t tail_pos = 0;
BUG_ON (!th->t_trans_id);
init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
......@@ -1775,6 +1794,7 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode)
{
BUG_ON (!th->t_trans_id);
if (inode->i_nlink)
reiserfs_warning (inode->i_sb,
"vs-5655: truncate_directory: link count != 0");
......@@ -1792,7 +1812,7 @@ static void truncate_directory (struct reiserfs_transaction_handle *th, struct i
/* Truncate file to the new size. Note, this must be called with a transaction
already started */
void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
struct inode * p_s_inode, /* ->i_size contains new
size */
struct page *page, /* up to date for last block */
......@@ -1808,14 +1828,16 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
n_new_file_size;/* New file size. */
int n_deleted; /* Number of deleted or truncated bytes. */
int retval;
int err = 0;
BUG_ON (!th->t_trans_id);
if ( ! (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode) || S_ISLNK(p_s_inode->i_mode)) )
return;
return 0;
if (S_ISDIR(p_s_inode->i_mode)) {
// deletion of directory - no need to update timestamps
truncate_directory (th, p_s_inode);
return;
return 0;
}
/* Get new file size. */
......@@ -1828,13 +1850,15 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
if (retval == IO_ERROR) {
reiserfs_warning (p_s_inode->i_sb, "vs-5657: reiserfs_do_truncate: "
"i/o failure occurred trying to truncate %K", &s_item_key);
return;
err = -EIO;
goto out;
}
if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
pathrelse (&s_search_path);
reiserfs_warning (p_s_inode->i_sb, "PAP-5660: reiserfs_do_truncate: "
"wrong result %d of search for %K", retval, &s_item_key);
return;
err = -EIO;
goto out;
}
s_search_path.pos_in_item --;
......@@ -1872,7 +1896,7 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
if (n_deleted < 0) {
reiserfs_warning (p_s_inode->i_sb, "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed");
reiserfs_check_path(&s_search_path) ;
return;
return 0;
}
RFALSE( n_deleted > n_file_size,
......@@ -1902,8 +1926,13 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
}
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, JOURNAL_PER_BALANCE_CNT * 6) ;
err = journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
if (err)
goto out;
err = journal_begin (th, p_s_inode->i_sb,
JOURNAL_PER_BALANCE_CNT * 6);
if (err)
goto out;
reiserfs_update_inode_transaction(p_s_inode) ;
}
} while ( n_file_size > ROUND_UP (n_new_file_size) &&
......@@ -1920,7 +1949,9 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
}
reiserfs_update_sd (th, p_s_inode);
out:
pathrelse(&s_search_path) ;
return err;
}
......@@ -1963,6 +1994,8 @@ int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
int retval;
int fs_gen;
BUG_ON (!th->t_trans_id);
fs_gen = get_generation(inode->i_sb) ;
#ifdef REISERQUOTA_DEBUG
......@@ -2035,6 +2068,8 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
int fs_gen = 0 ;
int quota_bytes = 0 ;
BUG_ON (!th->t_trans_id);
if (inode) { /* Do we count quotas for item? */
fs_gen = get_generation(inode->i_sb);
quota_bytes = ih_item_len(p_s_ih);
......
......@@ -24,6 +24,7 @@
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
#include <linux/namespace.h>
struct file_system_type reiserfs_fs_type;
......@@ -66,11 +67,14 @@ static void reiserfs_sync_fs (struct super_block * s)
if (!(s->s_flags & MS_RDONLY)) {
struct reiserfs_transaction_handle th;
reiserfs_write_lock(s);
journal_begin(&th, s, 1);
journal_end_sync(&th, s, 1);
if (!journal_begin(&th, s, 1))
if (!journal_end_sync(&th, s, 1))
reiserfs_flush_old_commits(s);
s->s_dirt = 0;
s->s_dirt = 0; /* Even if it's not true.
* We'll loop forever in sync_supers otherwise */
reiserfs_write_unlock(s);
} else {
s->s_dirt = 0;
}
}
......@@ -84,12 +88,16 @@ static void reiserfs_write_super_lockfs (struct super_block * s)
struct reiserfs_transaction_handle th ;
reiserfs_write_lock(s);
if (!(s->s_flags & MS_RDONLY)) {
journal_begin(&th, s, 1) ;
int err = journal_begin(&th, s, 1) ;
if (err) {
reiserfs_block_writes(&th) ;
} else {
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
reiserfs_block_writes(&th) ;
journal_end_sync(&th, s, 1) ;
}
}
s->s_dirt = 0;
reiserfs_write_unlock(s);
}
......@@ -108,29 +116,32 @@ extern const struct key MAX_KEY;
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, int oid_free)
static int remove_save_link_only (struct super_block * s, struct key * key, int oid_free)
{
struct reiserfs_transaction_handle th;
int err;
/* we are going to do one balancing */
journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
err = journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
if (err)
return err;
reiserfs_delete_solid_item (&th, NULL, key);
if (oid_free)
/* removals are protected by direct items */
reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
return 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)
static int finish_unfinished (struct super_block * s)
{
INITIALIZE_PATH (path);
struct cpu_key max_cpu_key, obj_key;
struct key save_link_key;
int retval;
int retval = 0;
struct item_head * ih;
struct buffer_head * bh;
int item_pos;
......@@ -147,7 +158,7 @@ static void finish_unfinished (struct super_block * s)
done = 0;
REISERFS_SB(s)->s_is_unlinked_ok = 1;
while (1) {
while (!retval) {
retval = search_item (s, &max_cpu_key, &path);
if (retval != ITEM_NOT_FOUND) {
reiserfs_warning (s, "vs-2140: finish_unfinished: search_by_key returned %d",
......@@ -189,7 +200,7 @@ static void finish_unfinished (struct super_block * s)
"save" link and release objectid */
reiserfs_warning (s, "vs-2180: finish_unfinished: iget failed for %K",
&obj_key);
remove_save_link_only (s, &save_link_key, 1);
retval = remove_save_link_only (s, &save_link_key, 1);
continue;
}
......@@ -197,7 +208,7 @@ static void finish_unfinished (struct super_block * s)
/* file is not unlinked */
reiserfs_warning (s, "vs-2185: finish_unfinished: file %K is not unlinked",
&obj_key);
remove_save_link_only (s, &save_link_key, 0);
retval = remove_save_link_only (s, &save_link_key, 0);
continue;
}
......@@ -207,7 +218,7 @@ static void finish_unfinished (struct super_block * s)
then boot into old kernel, remove the file and create dir with
the same key. */
reiserfs_warning(s, "green-2101: impossible truncate on a directory %k. Please report", INODE_PKEY (inode));
remove_save_link_only (s, &save_link_key, 0);
retval = remove_save_link_only (s, &save_link_key, 0);
truncate = 0;
iput (inode);
continue;
......@@ -220,12 +231,13 @@ static void finish_unfinished (struct super_block * s)
reiserfs_info (s, "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);
retval = remove_save_link (inode, truncate);
} else {
REISERFS_I(inode) -> i_flags |= i_link_saved_unlink_mask;
/* not completed unlink (rmdir) found */
reiserfs_info (s, "Removing %k..", INODE_PKEY (inode));
/* removal gets completed in iput */
retval = 0;
}
iput (inode);
......@@ -238,6 +250,7 @@ static void finish_unfinished (struct super_block * s)
if (done)
reiserfs_info (s, "There were %d uncompleted unlinks/truncates. "
"Completed\n", done);
return retval;
}
/* to protect file being unlinked from getting lost we "safe" link files
......@@ -253,6 +266,8 @@ void add_save_link (struct reiserfs_transaction_handle * th,
struct item_head ih;
__u32 link;
BUG_ON (!th->t_trans_id);
/* file can only get one "save link" of each kind */
RFALSE( truncate &&
( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ),
......@@ -317,14 +332,16 @@ void add_save_link (struct reiserfs_transaction_handle * th,
/* this opens transaction unlike add_save_link */
void remove_save_link (struct inode * inode, int truncate)
int remove_save_link (struct inode * inode, int truncate)
{
struct reiserfs_transaction_handle th;
struct key key;
int err;
/* we are going to do one balancing only */
journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
err = journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
if (err)
return err;
/* setup key of "save" link */
key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID);
......@@ -352,7 +369,7 @@ void remove_save_link (struct inode * inode, int truncate)
} else
REISERFS_I(inode) -> i_flags &= ~i_link_saved_truncate_mask;
journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
return journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
}
......@@ -360,6 +377,7 @@ static void reiserfs_put_super (struct super_block * s)
{
int i;
struct reiserfs_transaction_handle th ;
th.t_trans_id = 0;
if (REISERFS_SB(s)->xattr_root) {
d_invalidate (REISERFS_SB(s)->xattr_root);
......@@ -373,11 +391,12 @@ static void reiserfs_put_super (struct super_block * s)
/* change file system state to current state if it was mounted with read-write permissions */
if (!(s->s_flags & MS_RDONLY)) {
journal_begin(&th, s, 10) ;
if (!journal_begin(&th, s, 10)) {
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state );
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
}
}
/* note, journal_release checks for readonly mount, and can decide not
** to do a journal_end
......@@ -461,6 +480,7 @@ static void destroy_inodecache(void)
static void reiserfs_dirty_inode (struct inode * inode) {
struct reiserfs_transaction_handle th ;
int err = 0;
if (inode->i_sb->s_flags & MS_RDONLY) {
reiserfs_warning(inode->i_sb, "clm-6006: writing inode %lu on readonly FS",
inode->i_ino) ;
......@@ -471,7 +491,11 @@ static void reiserfs_dirty_inode (struct inode * inode) {
/* this is really only used for atime updates, so they don't have
** to be included in O_SYNC or fsync
*/
journal_begin(&th, inode->i_sb, 1) ;
err = journal_begin(&th, inode->i_sb, 1) ;
if (err) {
reiserfs_write_unlock (inode->i_sb);
return;
}
reiserfs_update_sd (&th, inode);
journal_end(&th, inode->i_sb, 1) ;
reiserfs_write_unlock(inode->i_sb);
......@@ -575,6 +599,18 @@ static const arg_desc_t tails[] = {
{NULL, 0, 0}
};
static const arg_desc_t error_actions[] = {
{"panic", 1 << REISERFS_ERROR_PANIC,
(1 << REISERFS_ERROR_RO | 1 << REISERFS_ERROR_CONTINUE)},
{"ro-remount", 1 << REISERFS_ERROR_RO,
(1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_CONTINUE)},
#ifdef REISERFS_JOURNAL_ERROR_ALLOWS_NO_LOG
{"continue", 1 << REISERFS_ERROR_CONTINUE,
(1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_RO)},
#endif
{NULL, 0, 0},
};
int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
There might be broken applications that are
confused by this. Use nolargeio mount option
......@@ -725,6 +761,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
{"commit", .arg_required = 'c', .values = NULL},
{"usrquota",},
{"grpquota",},
{"errors", .arg_required = 'e', .values = error_actions},
{NULL,}
};
......@@ -862,6 +899,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
unsigned long safe_mask = 0;
unsigned int commit_max_age = (unsigned int)-1;
struct reiserfs_journal *journal = SB_JOURNAL(s);
int err;
rs = SB_DISK_SUPER_BLOCK (s);
......@@ -882,6 +920,9 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
safe_mask |= 1 << REISERFS_POSIXACL;
safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
safe_mask |= 1 << REISERFS_BARRIER_NONE;
safe_mask |= 1 << REISERFS_ERROR_RO;
safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
safe_mask |= 1 << REISERFS_ERROR_PANIC;
/* Update the bitmask, taking care to keep
* the bits we're not allowed to change here */
......@@ -915,7 +956,10 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
return 0;
}
journal_begin(&th, s, 10) ;
err = journal_begin(&th, s, 10) ;
if (err)
return err;
/* Mounting a rw partition read-only. */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
set_sb_umount_state( rs, REISERFS_SB(s)->s_mount_state );
......@@ -927,11 +971,16 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
return 0; /* We are read-write already */
}
if (reiserfs_is_journal_aborted (journal))
return journal->j_errno;
handle_data_mode(s, mount_options);
handle_barrier_mode(s, mount_options);
REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
journal_begin(&th, s, 10) ;
err = journal_begin(&th, s, 10) ;
if (err)
return err;
/* Mount a partition which is read-only, read-write */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
......@@ -944,7 +993,9 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
}
/* this will force a full flush of all journal lists */
SB_JOURNAL(s)->j_must_wait = 1 ;
journal_end(&th, s, 10) ;
err = journal_end(&th, s, 10) ;
if (err)
return err;
s->s_dirt = 0;
if (!( *mount_flags & MS_RDONLY ) ) {
......@@ -1372,8 +1423,9 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
}
s->s_fs_info = sbi;
memset (sbi, 0, sizeof (struct reiserfs_sb_info));
/* Set default values for options: non-aggressive tails */
REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
/* Set default values for options: non-aggressive tails, RO on errors */
REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL);
REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO);
/* no preallocation minimum, be smart in
reiserfs_file_write instead */
REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
......@@ -1501,7 +1553,12 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
if (!(s->s_flags & MS_RDONLY)) {
journal_begin(&th, s, 1) ;
errval = journal_begin(&th, s, 1) ;
if (errval) {
dput (s->s_root);
s->s_root = NULL;
goto error;
}
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
set_sb_umount_state( rs, REISERFS_ERROR_FS );
......@@ -1531,9 +1588,14 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
}
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
journal_end(&th, s, 1) ;
errval = journal_end(&th, s, 1) ;
if (errval) {
dput (s->s_root);
s->s_root = NULL;
goto error;
}
if (reiserfs_xattr_init (s, s->s_flags)) {
if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
dput (s->s_root);
s->s_root = NULL;
goto error;
......@@ -1546,7 +1608,7 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
reiserfs_info (s, "using 3.5.x disk format\n") ;
}
if (reiserfs_xattr_init (s, s->s_flags)) {
if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
dput (s->s_root);
s->s_root = NULL;
goto error;
......
......@@ -34,6 +34,7 @@ int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inod
that will be inserted in the
tree. */
BUG_ON (!th->t_trans_id);
REISERFS_SB(sb)->s_direct2indirect ++;
......@@ -184,6 +185,8 @@ int indirect2direct (struct reiserfs_transaction_handle *th,
loff_t pos, pos1; /* position of first byte of the tail */
struct cpu_key key;
BUG_ON (!th->t_trans_id);
REISERFS_SB(p_s_sb)->s_indirect2direct ++;
*p_c_mode = M_SKIP_BALANCING;
......
......@@ -1751,6 +1751,7 @@ struct reiserfs_transaction_handle {
void *t_handle_save ; /* save existing current->journal_info */
unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
should be displaced from others */
struct list_head t_list;
} ;
/* used to keep track of ordered and tail writes, attached to the buffer
......@@ -1810,12 +1811,14 @@ int journal_mark_freed(struct reiserfs_transaction_handle *, struct super_block
int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
int reiserfs_in_journal(struct super_block *p_s_sb, int bmap_nr, int bit_nr, int searchall, b_blocknr_t *next) ;
int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
int journal_join_abort(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
void reiserfs_journal_abort (struct super_block *sb, int errno);
void reiserfs_abort (struct super_block *sb, int errno, const char *fmt, ...);
int reiserfs_allocate_list_bitmaps(struct super_block *s, struct reiserfs_list_bitmap *, int) ;
void add_save_link (struct reiserfs_transaction_handle * th,
struct inode * inode, int truncate);
void remove_save_link (struct inode * inode, int truncate);
int remove_save_link (struct inode * inode, int truncate);
/* objectid.c */
__u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th);
......@@ -1911,8 +1914,8 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
struct inode *inode, 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,
int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
struct inode * p_s_inode, struct page *,
int update_timestamps);
......@@ -1926,7 +1929,7 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
void padd_item (char * item, int total_length, int length);
/* inode.c */
void restart_transaction(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *path);
int restart_transaction(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *path);
void reiserfs_read_locked_inode(struct inode * inode, struct reiserfs_iget_args *args) ;
int reiserfs_find_actor(struct inode * inode, void *p) ;
int reiserfs_init_locked_inode(struct inode * inode, void *p) ;
......@@ -1941,7 +1944,7 @@ int reiserfs_encode_fh( struct dentry *dentry, __u32 *data, int *lenp,
int connectable );
int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ;
void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
int reiserfs_truncate_file(struct inode *, int update_timestamps) ;
void make_cpu_key (struct cpu_key * cpu_key, struct inode * inode, loff_t offset,
int type, int key_length);
void make_le_item_head (struct item_head * ih, const struct cpu_key * key,
......
......@@ -242,14 +242,24 @@ struct reiserfs_journal {
struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for all the real buffer heads in all
the transactions */
struct list_head j_prealloc_list; /* list of inodes which have preallocated blocks */
int j_persistent_trans;
unsigned long j_max_trans_size ;
unsigned long j_max_batch_size ;
int j_errno;
/* when flushing ordered buffers, throttle new ordered writers */
struct work_struct j_work;
atomic_t j_async_throttle;
};
enum journal_state_bits {
J_WRITERS_BLOCKED = 1, /* set when new writers not allowed */
J_WRITERS_QUEUED, /* set when log is full due to too many writers */
J_ABORTED, /* set when log is aborted */
};
#define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */
typedef __u32 (*hashf_t) (const signed char *, int);
......@@ -399,6 +409,7 @@ struct reiserfs_sb_info
struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
struct rw_semaphore xattr_dir_sem;
int j_errno;
};
/* Definitions of reiserfs on-disk properties: */
......@@ -447,6 +458,11 @@ enum reiserfs_mount_options {
REISERFS_BARRIER_NONE,
REISERFS_BARRIER_FLUSH,
/* Actions on error */
REISERFS_ERROR_PANIC,
REISERFS_ERROR_RO,
REISERFS_ERROR_CONTINUE,
REISERFS_TEST1,
REISERFS_TEST2,
REISERFS_TEST3,
......@@ -478,6 +494,10 @@ enum reiserfs_mount_options {
#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC))
#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO))
#define reiserfs_error_continue(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_CONTINUE))
void reiserfs_file_buffer (struct buffer_head * bh, int list);
extern struct file_system_type reiserfs_fs_type;
int reiserfs_resize(struct super_block *, unsigned long) ;
......@@ -502,4 +522,10 @@ static inline char *reiserfs_bdevname(struct super_block *s)
return (s == NULL) ? "Null superblock" : s -> s_id;
}
#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
static inline int __reiserfs_is_journal_aborted (struct reiserfs_journal *journal)
{
return test_bit (J_ABORTED, &journal->j_state);
}
#endif /* _LINUX_REISER_FS_SB */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment