-
- /* setup description block */
- d_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + journal->j_start) ;
- set_buffer_uptodate(d_bh);
- desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ;
- memset(d_bh->b_data, 0, d_bh->b_size) ;
- memcpy(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8) ;
- set_desc_trans_id(desc, journal->j_trans_id) ;
-
- /* setup commit block. Don't write (keep it clean too) this one until after everyone else is written */
- c_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- ((journal->j_start + journal->j_len + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
- commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
- memset(c_bh->b_data, 0, c_bh->b_size) ;
- set_commit_trans_id(commit, journal->j_trans_id) ;
- set_buffer_uptodate(c_bh) ;
-
- /* init this journal list */
- jl = journal->j_current_jl;
-
- /* we lock the commit before doing anything because
- * we want to make sure nobody tries to run flush_commit_list until
- * the new transaction is fully setup, and we've already flushed the
- * ordered bh list
- */
- down(&jl->j_commit_lock);
-
- /* save the transaction id in case we need to commit it later */
- commit_trans_id = jl->j_trans_id;
-
- atomic_set(&jl->j_older_commits_done, 0) ;
- jl->j_trans_id = journal->j_trans_id ;
- jl->j_timestamp = journal->j_trans_start_time ;
- jl->j_commit_bh = c_bh ;
- jl->j_start = journal->j_start ;
- jl->j_len = journal->j_len ;
- atomic_set(&jl->j_nonzerolen, journal->j_len) ;
- atomic_set(&jl->j_commit_left, journal->j_len + 2);
- jl->j_realblock = NULL ;
-
- /* The ENTIRE FOR LOOP MUST not cause schedule to occur.
- ** for each real block, add it to the journal list hash,
- ** copy into real block index array in the commit or desc block
- */
- trans_half = journal_trans_half(p_s_sb->s_blocksize);
- for (i = 0, cn = journal->j_first ; cn ; cn = cn->next, i++) {
- if (buffer_journaled (cn->bh)) {
- jl_cn = get_cnode(p_s_sb) ;
- if (!jl_cn) {
- reiserfs_panic(p_s_sb, "journal-1676, get_cnode returned NULL\n") ;
- }
- if (i == 0) {
- jl->j_realblock = jl_cn ;
- }
- jl_cn->prev = last_cn ;
- jl_cn->next = NULL ;
- if (last_cn) {
- last_cn->next = jl_cn ;
- }
- last_cn = jl_cn ;
- /* make sure the block we are trying to log is not a block
- of journal or reserved area */
-
- if (is_block_in_log_or_reserved_area(p_s_sb, cn->bh->b_blocknr)) {
- reiserfs_panic(p_s_sb, "journal-2332: Trying to log block %lu, which is a log block\n", cn->bh->b_blocknr) ;
- }
- jl_cn->blocknr = cn->bh->b_blocknr ;
- jl_cn->state = 0 ;
- jl_cn->sb = p_s_sb;
- jl_cn->bh = cn->bh ;
- jl_cn->jlist = jl;
- insert_journal_hash(journal->j_list_hash_table, jl_cn) ;
- if (i < trans_half) {
- desc->j_realblock[i] = cpu_to_le32(cn->bh->b_blocknr) ;
- } else {
- commit->j_realblock[i - trans_half] = cpu_to_le32(cn->bh->b_blocknr) ;
- }
- } else {
- i-- ;
- }
- }
- set_desc_trans_len(desc, journal->j_len) ;
- set_desc_mount_id(desc, journal->j_mount_id) ;
- set_desc_trans_id(desc, journal->j_trans_id) ;
- 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();
- }
-
- /* 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
- * others are on disk
- */
- mark_buffer_dirty(d_bh);
-
- /* first data block is j_start + 1, so add one to cur_write_start wherever you use it */
- cur_write_start = journal->j_start ;
- cn = journal->j_first ;
- jindex = 1 ; /* start at one so we don't get the desc again */
- while(cn) {
- clear_buffer_journal_new (cn->bh);
- /* copy all the real blocks into log area. dirty log blocks */
- if (buffer_journaled (cn->bh)) {
- struct buffer_head *tmp_bh ;
- char *addr;
- struct page *page;
- tmp_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
- set_buffer_uptodate(tmp_bh);
- page = cn->bh->b_page;
- addr = kmap(page);
- memcpy(tmp_bh->b_data, addr + offset_in_page(cn->bh->b_data),
- cn->bh->b_size);
- kunmap(page);
- mark_buffer_dirty(tmp_bh);
- jindex++ ;
- set_buffer_journal_dirty (cn->bh);
- clear_buffer_journaled (cn->bh);
- } else {
- /* JDirty cleared sometime during transaction. don't log this one */
- reiserfs_warning(p_s_sb, "journal-2048: do_journal_end: BAD, buffer in journal hash, but not JDirty!") ;
- brelse(cn->bh) ;
- }
- next = cn->next ;
- free_cnode(p_s_sb, cn) ;
- cn = next ;
- cond_resched();
- }
-
- /* we are done with both the c_bh and d_bh, but
- ** c_bh must be written after all other commit blocks,
- ** so we dirty/relse c_bh in flush_commit_list, with commit_left <= 1.
- */
-
- journal->j_current_jl = alloc_journal_list(p_s_sb);
-
- /* now it is safe to insert this transaction on the main list */
- list_add_tail(&jl->j_list, &journal->j_journal_list);
- list_add_tail(&jl->j_working_list, &journal->j_working_list);
- journal->j_num_work_lists++;
-
- /* reset journal values for the next transaction */
- old_start = journal->j_start ;
- journal->j_start = (journal->j_start + journal->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb);
- atomic_set(&(journal->j_wcount), 0) ;
- journal->j_bcount = 0 ;
- journal->j_last = NULL ;
- journal->j_first = NULL ;
- journal->j_len = 0 ;
- journal->j_trans_start_time = 0 ;
- journal->j_trans_id++ ;
- journal->j_current_jl->j_trans_id = journal->j_trans_id;
- journal->j_must_wait = 0 ;
- journal->j_len_alloc = 0 ;
- journal->j_next_full_flush = 0 ;
- journal->j_next_async_flush = 0 ;
- init_journal_hash(p_s_sb) ;
-
- // make sure reiserfs_add_jh sees the new current_jl before we
- // write out the tails
- smp_mb();
-
- /* tail conversion targets have to hit the disk before we end the
- * transaction. Otherwise a later transaction might repack the tail
- * before this transaction commits, leaving the data block unflushed and
- * clean, if we crash before the later transaction commits, the data block
- * is lost.
- */
- if (!list_empty(&jl->j_tail_bh_list)) {
- unlock_kernel();
- write_ordered_buffers(&journal->j_dirty_buffers_lock,
- journal, jl, &jl->j_tail_bh_list);
- lock_kernel();
- }
- if (!list_empty(&jl->j_tail_bh_list))
- BUG();
- up(&jl->j_commit_lock);
-
- /* honor the flush wishes from the caller, simple commits can
- ** be done outside the journal lock, they are done below
- **
- ** if we don't flush the commit list right now, we put it into
- ** the work queue so the people waiting on the async progress work
- ** queue don't wait for this proc to flush journal lists and such.
- */
- if (flush) {
- flush_commit_list(p_s_sb, jl, 1) ;
- flush_journal_list(p_s_sb, jl, 1) ;
- } else if (!(jl->j_state & LIST_COMMIT_PENDING))
- queue_delayed_work(commit_wq, &journal->j_work, HZ/10);
-
-
- /* if the next transaction has any chance of wrapping, flush
- ** transactions that might get overwritten. If any journal lists are very
- ** old flush them as well.
- */
-first_jl:
- list_for_each_safe(entry, safe, &journal->j_journal_list) {
- temp_jl = JOURNAL_LIST_ENTRY(entry);
- if (journal->j_start <= temp_jl->j_start) {
- if ((journal->j_start + journal->j_trans_max + 1) >=
- temp_jl->j_start)
- {
- flush_used_journal_lists(p_s_sb, temp_jl);
- goto first_jl;
- } else if ((journal->j_start +
- journal->j_trans_max + 1) <
- SB_ONDISK_JOURNAL_SIZE(p_s_sb))
- {
- /* if we don't cross into the next transaction and we don't
- * wrap, there is no way we can overlap any later transactions
- * break now
- */
- break;
- }
- } else if ((journal->j_start +
- journal->j_trans_max + 1) >
- SB_ONDISK_JOURNAL_SIZE(p_s_sb))
- {
- if (((journal->j_start + journal->j_trans_max + 1) %
- SB_ONDISK_JOURNAL_SIZE(p_s_sb)) >= temp_jl->j_start)
- {
- flush_used_journal_lists(p_s_sb, temp_jl);
- goto first_jl;
- } else {
- /* we don't overlap anything from out start to the end of the
- * log, and our wrapped portion doesn't overlap anything at
- * the start of the log. We can break
- */
- break;
- }
- }
- }
- flush_old_journal_lists(p_s_sb);
-
- journal->j_current_jl->j_list_bitmap = get_list_bitmap(p_s_sb, journal->j_current_jl) ;
-
- if (!(journal->j_current_jl->j_list_bitmap)) {
- reiserfs_panic(p_s_sb, "journal-1996: do_journal_end, could not get a list bitmap\n") ;
- }
-
- atomic_set(&(journal->j_jlock), 0) ;
- unlock_journal(p_s_sb) ;
- /* wake up any body waiting to join. */
- clear_bit(J_WRITERS_QUEUED, &journal->j_state);
- wake_up(&(journal->j_join_wait)) ;
-
- if (!flush && wait_on_commit &&
- journal_list_still_alive(p_s_sb, commit_trans_id)) {
- flush_commit_list(p_s_sb, jl, 1) ;
- }
-out:
- reiserfs_check_lock_depth(p_s_sb, "journal end2");
-
- 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;
-}
-
-static 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);