X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Freiserfs%2Fjournal.c;h=7280a23ef3444aa4b8370dcb99b8ee46ee246dec;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=5a9d2722fa0adf4d507072e7c5c3db65dd5aff75;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 5a9d2722f..7280a23ef 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -34,7 +34,6 @@ ** from within kupdate, it will ignore the immediate flag */ -#include #include #include @@ -54,6 +53,7 @@ #include #include #include +#include /* gets a struct reiserfs_journal_list * from a list head */ #define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \ @@ -104,7 +104,7 @@ static int release_journal_dev(struct super_block *super, struct reiserfs_journal *journal); static int dirty_one_transaction(struct super_block *s, struct reiserfs_journal_list *jl); -static void flush_async_commits(void *p); +static void flush_async_commits(struct work_struct *work); static void queue_log_writer(struct super_block *s); /* values for join in do_journal_begin_r */ @@ -719,8 +719,7 @@ static int add_to_chunk(struct buffer_chunk *chunk, struct buffer_head *bh, spinlock_t * lock, void (fn) (struct buffer_chunk *)) { int ret = 0; - if (chunk->nr >= CHUNK_SIZE) - BUG(); + BUG_ON(chunk->nr >= CHUNK_SIZE); chunk->bh[chunk->nr++] = bh; if (chunk->nr >= CHUNK_SIZE) { ret = 1; @@ -789,8 +788,7 @@ static inline int __add_jh(struct reiserfs_journal *j, struct buffer_head *bh, /* buffer must be locked for __add_jh, should be able to have * two adds at the same time */ - if (bh->b_private) - BUG(); + BUG_ON(bh->b_private); jh->bh = bh; bh->b_private = jh; } @@ -834,8 +832,7 @@ static int write_ordered_buffers(spinlock_t * lock, get_bh(bh); if (test_set_buffer_locked(bh)) { if (!buffer_dirty(bh)) { - list_del_init(&jh->list); - list_add(&jh->list, &tmp); + list_move(&jh->list, &tmp); goto loop_next; } spin_unlock(lock); @@ -855,8 +852,7 @@ static int write_ordered_buffers(spinlock_t * lock, ret = -EIO; } if (buffer_dirty(bh)) { - list_del_init(&jh->list); - list_add(&jh->list, &tmp); + list_move(&jh->list, &tmp); add_to_chunk(&chunk, bh, lock, write_ordered_chunk); } else { reiserfs_free_jh(bh); @@ -975,7 +971,7 @@ int reiserfs_async_progress_wait(struct super_block *s) DEFINE_WAIT(wait); struct reiserfs_journal *j = SB_JOURNAL(s); if (atomic_read(&j->j_async_throttle)) - blk_congestion_wait(WRITE, HZ / 10); + congestion_wait(WRITE, HZ / 10); return 0; } @@ -1189,6 +1185,21 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct return NULL; } +static int newer_jl_done(struct reiserfs_journal_cnode *cn) +{ + struct super_block *sb = cn->sb; + b_blocknr_t blocknr = cn->blocknr; + + cn = cn->hprev; + while (cn) { + if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist && + atomic_read(&cn->jlist->j_commit_left) != 0) + return 0; + cn = cn->hprev; + } + return 1; +} + static void remove_journal_hash(struct super_block *, struct reiserfs_journal_cnode **, struct reiserfs_journal_list *, unsigned long, @@ -1453,7 +1464,7 @@ static int flush_journal_list(struct super_block *s, } /* if someone has this block in a newer transaction, just make - ** sure they are commited, and don't try writing it to disk + ** sure they are committed, and don't try writing it to disk */ if (pjl) { if (atomic_read(&pjl->j_commit_left)) @@ -1607,6 +1618,31 @@ static int flush_journal_list(struct super_block *s, return err; } +static int test_transaction(struct super_block *s, + struct reiserfs_journal_list *jl) +{ + struct reiserfs_journal_cnode *cn; + + if (jl->j_len == 0 || atomic_read(&jl->j_nonzerolen) == 0) + return 1; + + cn = jl->j_realblock; + while (cn) { + /* if the blocknr == 0, this has been cleared from the hash, + ** skip it + */ + if (cn->blocknr == 0) { + goto next; + } + if (cn->bh && !newer_jl_done(cn)) + return 0; + next: + cn = cn->next; + cond_resched(); + } + return 0; +} + static int write_one_transaction(struct super_block *s, struct reiserfs_journal_list *jl, struct buffer_chunk *chunk) @@ -2227,6 +2263,9 @@ static int journal_read_transaction(struct super_block *p_s_sb, journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb); journal->j_last_flush_trans_id = trans_id; journal->j_trans_id = trans_id + 1; + /* check for trans_id overflow */ + if (journal->j_trans_id == 0) + journal->j_trans_id = 10; brelse(c_bh); brelse(d_bh); kfree(log_blocks); @@ -2450,6 +2489,9 @@ static int journal_read(struct super_block *p_s_sb) journal->j_start = le32_to_cpu(jh->j_first_unflushed_offset); journal->j_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1; + /* check for trans_id overflow */ + if (journal->j_trans_id == 0) + journal->j_trans_id = 10; journal->j_last_flush_trans_id = le32_to_cpu(jh->j_last_flush_trans_id); journal->j_mount_id = le32_to_cpu(jh->j_mount_id) + 1; @@ -2794,7 +2836,8 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, if (reiserfs_mounted_fs_count <= 1) commit_wq = create_workqueue("reiserfs"); - INIT_WORK(&journal->j_work, flush_async_commits, p_s_sb); + INIT_DELAYED_WORK(&journal->j_work, flush_async_commits); + journal->j_work_sb = p_s_sb; return 0; free_and_return: free_journal_ram(p_s_sb); @@ -2924,8 +2967,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, int retval; reiserfs_check_lock_depth(p_s_sb, "journal_begin"); - if (nblocks > journal->j_trans_max) - BUG(); + BUG_ON(nblocks > journal->j_trans_max); PROC_INFO_INC(p_s_sb, journal.journal_being); /* set here for journal_join */ @@ -3041,9 +3083,8 @@ struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct if (reiserfs_transaction_running(s)) { th = current->journal_info; th->t_refcount++; - if (th->t_refcount < 2) { - BUG(); - } + BUG_ON(th->t_refcount < 2); + return th; } th = kmalloc(sizeof(struct reiserfs_transaction_handle), GFP_NOFS); @@ -3083,9 +3124,7 @@ static int journal_join(struct reiserfs_transaction_handle *th, ** pointer */ th->t_handle_save = cur_th; - if (cur_th && cur_th->t_refcount > 1) { - BUG(); - } + BUG_ON(cur_th && cur_th->t_refcount > 1); return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN); } @@ -3098,9 +3137,7 @@ int journal_join_abort(struct reiserfs_transaction_handle *th, ** pointer */ th->t_handle_save = cur_th; - if (cur_th && cur_th->t_refcount > 1) { - BUG(); - } + BUG_ON(cur_th && cur_th->t_refcount > 1); return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT); } @@ -3135,8 +3172,7 @@ int journal_begin(struct reiserfs_transaction_handle *th, current->journal_info = th; } ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG); - if (current->journal_info != th) - BUG(); + BUG_ON(current->journal_info != th); /* 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 @@ -3281,8 +3317,7 @@ int journal_end(struct reiserfs_transaction_handle *th, /* we aren't allowed to close a nested transaction on a different ** filesystem from the one in the task struct */ - if (cur_th->t_super != th->t_super) - BUG(); + BUG_ON(cur_th->t_super != th->t_super); if (th != cur_th) { memcpy(current->journal_info, th, sizeof(*th)); @@ -3350,7 +3385,7 @@ static int remove_from_transaction(struct super_block *p_s_sb, /* ** for any cnode in a journal list, it can only be dirtied of all the -** transactions that include it are commited to disk. +** transactions that include it are committed to disk. ** this checks through each transaction, and returns 1 if you are allowed to dirty, ** and 0 if you aren't ** @@ -3392,7 +3427,7 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) } /* syncs the commit blocks, but does not force the real buffers to disk -** will wait until the current transaction is done/commited before returning +** will wait until the current transaction is done/committed before returning */ int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) @@ -3401,9 +3436,7 @@ int journal_end_sync(struct reiserfs_transaction_handle *th, BUG_ON(!th->t_trans_id); /* you can sync while nested, very, very bad */ - if (th->t_refcount > 1) { - BUG(); - } + BUG_ON(th->t_refcount > 1); if (journal->j_len == 0) { reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1); @@ -3415,10 +3448,11 @@ int journal_end_sync(struct reiserfs_transaction_handle *th, /* ** writeback the pending async commits to disk */ -static void flush_async_commits(void *p) +static void flush_async_commits(struct work_struct *work) { - struct super_block *p_s_sb = p; - struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb); + struct reiserfs_journal *journal = + container_of(work, struct reiserfs_journal, j_work.work); + struct super_block *p_s_sb = journal->j_work_sb; struct reiserfs_journal_list *jl; struct list_head *entry; @@ -3430,16 +3464,6 @@ static void flush_async_commits(void *p) flush_commit_list(p_s_sb, jl, 1); } unlock_kernel(); - /* - * this is a little racey, but there's no harm in missing - * the filemap_fdata_write - */ - 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); - } } /* @@ -3523,9 +3547,8 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, ** will be dealt with by next transaction that actually writes something, but should be taken ** care of in this trans */ - if (journal->j_len == 0) { - BUG(); - } + BUG_ON(journal->j_len == 0); + /* if wcount > 0, and we are called to with flush or commit_now, ** we wait on j_join_wait. We will wake up when the last writer has ** finished the transaction, and started it on its way to the disk. @@ -3559,9 +3582,8 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, unlock_journal(p_s_sb); } } - if (journal->j_trans_id == trans_id) { - BUG(); - } + BUG_ON(journal->j_trans_id == trans_id); + if (commit_now && journal_list_still_alive(p_s_sb, trans_id) && wait_on_commit) { @@ -3841,7 +3863,9 @@ static void flush_old_journal_lists(struct super_block *s) entry = journal->j_journal_list.next; jl = JOURNAL_LIST_ENTRY(entry); /* this check should always be run, to send old lists to disk */ - if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4))) { + if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4)) && + atomic_read(&jl->j_commit_left) == 0 && + test_transaction(s, jl)) { flush_used_journal_lists(s, jl); } else { break; @@ -3873,8 +3897,8 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, int cur_write_start = 0; /* start index of current log write */ int old_start; int i; - int flush = flags & FLUSH_ALL; - int wait_on_commit = flags & WAIT; + int flush; + int wait_on_commit; struct reiserfs_journal_list *jl, *temp_jl; struct list_head *entry, *safe; unsigned long jindex; @@ -3884,6 +3908,13 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, BUG_ON(th->t_refcount > 1); BUG_ON(!th->t_trans_id); + /* protect flush_older_commits from doing mistakes if the + transaction ID counter gets overflowed. */ + if (th->t_trans_id == ~0UL) + flags |= FLUSH_ALL | COMMIT_NOW | WAIT; + flush = flags & FLUSH_ALL; + wait_on_commit = flags & WAIT; + put_fs_excl(); current->journal_info = th->t_handle_save; reiserfs_check_lock_depth(p_s_sb, "journal end"); @@ -4032,9 +4063,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, set_commit_trans_len(commit, journal->j_len); /* special check in case all buffers in the journal were marked for not logging */ - if (journal->j_len == 0) { - BUG(); - } + BUG_ON(journal->j_len == 0); /* we're about to dirty all the log blocks, mark the description block * dirty now too. Don't mark the commit block dirty until all the @@ -4105,7 +4134,9 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, journal->j_first = NULL; journal->j_len = 0; journal->j_trans_start_time = 0; - journal->j_trans_id++; + /* check for trans_id overflow */ + if (++journal->j_trans_id == 0) + journal->j_trans_id = 10; journal->j_current_jl->j_trans_id = journal->j_trans_id; journal->j_must_wait = 0; journal->j_len_alloc = 0; @@ -4129,8 +4160,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, journal, jl, &jl->j_tail_bh_list); lock_kernel(); } - if (!list_empty(&jl->j_tail_bh_list)) - BUG(); + BUG_ON(!list_empty(&jl->j_tail_bh_list)); up(&jl->j_commit_lock); /* honor the flush wishes from the caller, simple commits can