📄 journal.c
字号:
} c_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT)) ; if (!c_bh) { brelse(d_bh) ; return 1 ; } commit = (struct reiserfs_journal_commit *)c_bh->b_data ; if (journal_compare_desc_commit(p_s_sb, desc, commit)) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal_read_transaction, " "commit offset %ld had bad time %d or length %d\n", c_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb), le32_to_cpu(commit->j_trans_id), le32_to_cpu(commit->j_len)); brelse(c_bh) ; brelse(d_bh) ; return 1; } trans_id = le32_to_cpu(desc->j_trans_id) ; /* now we know we've got a good transaction, and it was inside the valid time ranges */ log_blocks = kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS) ; real_blocks = kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS) ; if (!log_blocks || !real_blocks) { brelse(c_bh) ; brelse(d_bh) ; kfree(log_blocks) ; kfree(real_blocks) ; reiserfs_warning("journal-1169: kmalloc failed, unable to mount FS\n") ; return -1 ; } /* get all the buffer heads */ for(i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { log_blocks[i] = sb_getblk(p_s_sb, reiserfs_get_journal_block(p_s_sb) + (trans_offset + 1 + i) % JOURNAL_BLOCK_COUNT); if (i < JOURNAL_TRANS_HALF) { real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(desc->j_realblock[i])) ; } else { real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - JOURNAL_TRANS_HALF])) ; } if (real_blocks[i]->b_blocknr >= reiserfs_get_journal_block(p_s_sb) && real_blocks[i]->b_blocknr < (reiserfs_get_journal_block(p_s_sb)+JOURNAL_BLOCK_COUNT)) { reiserfs_warning("journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block\n") ; brelse_array(log_blocks, i) ; brelse_array(real_blocks, i) ; brelse(c_bh) ; brelse(d_bh) ; kfree(log_blocks) ; kfree(real_blocks) ; return -1 ; } } /* read in the log blocks, memcpy to the corresponding real block */ ll_rw_block(READ, le32_to_cpu(desc->j_len), log_blocks) ; for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { wait_on_buffer(log_blocks[i]) ; if (!buffer_uptodate(log_blocks[i])) { reiserfs_warning("journal-1212: REPLAY FAILURE fsck required! buffer write failed\n") ; brelse_array(log_blocks + i, le32_to_cpu(desc->j_len) - i) ; brelse_array(real_blocks, le32_to_cpu(desc->j_len)) ; brelse(c_bh) ; brelse(d_bh) ; kfree(log_blocks) ; kfree(real_blocks) ; return -1 ; } memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ; mark_buffer_uptodate(real_blocks[i], 1) ; brelse(log_blocks[i]) ; } /* flush out the real blocks */ for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { set_bit(BH_Dirty, &(real_blocks[i]->b_state)) ; ll_rw_block(WRITE, 1, real_blocks + i) ; } for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { wait_on_buffer(real_blocks[i]) ; if (!buffer_uptodate(real_blocks[i])) { reiserfs_warning("journal-1226: REPLAY FAILURE, fsck required! buffer write failed\n") ; brelse_array(real_blocks + i, le32_to_cpu(desc->j_len) - i) ; brelse(c_bh) ; brelse(d_bh) ; kfree(log_blocks) ; kfree(real_blocks) ; return -1 ; } brelse(real_blocks[i]) ; } cur_dblock = reiserfs_get_journal_block(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 2) % JOURNAL_BLOCK_COUNT) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1095: setting journal " "start to offset %ld\n", cur_dblock - reiserfs_get_journal_block(p_s_sb)) ; /* init starting values for the first transaction, in case this is the last transaction to be replayed. */ SB_JOURNAL(p_s_sb)->j_start = cur_dblock - reiserfs_get_journal_block(p_s_sb) ; SB_JOURNAL(p_s_sb)->j_last_flush_trans_id = trans_id ; SB_JOURNAL(p_s_sb)->j_trans_id = trans_id + 1; brelse(c_bh) ; brelse(d_bh) ; kfree(log_blocks) ; kfree(real_blocks) ; return 0 ;}/*** read and replay the log** on a clean unmount, the journal header's next unflushed pointer will be to an invalid** transaction. This tests that before finding all the transactions in the log, whic makes normal mount times fast.**** After a crash, this starts with the next unflushed transaction, and replays until it finds one too old, or invalid.**** On exit, it sets things up so the first transaction will work correctly.*/static int journal_read(struct super_block *p_s_sb) { struct reiserfs_journal_desc *desc ; unsigned long last_flush_trans_id = 0 ; unsigned long oldest_trans_id = 0; unsigned long oldest_invalid_trans_id = 0 ; time_t start ; unsigned long last_flush_start = 0; unsigned long oldest_start = 0; unsigned long cur_dblock = 0 ; unsigned long newest_mount_id = 9 ; struct buffer_head *d_bh ; struct reiserfs_journal_header *jh ; int valid_journal_header = 0 ; int replay_count = 0 ; int continue_replay = 1 ; int ret ; cur_dblock = reiserfs_get_journal_block(p_s_sb) ; printk("reiserfs: checking transaction log (device %s) ...\n", kdevname(p_s_sb->s_dev)) ; start = CURRENT_TIME ; /* step 1, read in the journal header block. Check the transaction it says ** is the first unflushed, and if that transaction is not valid, ** replay is done */ SB_JOURNAL(p_s_sb)->j_header_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + JOURNAL_BLOCK_COUNT) ; if (!SB_JOURNAL(p_s_sb)->j_header_bh) { return 1 ; } jh = (struct reiserfs_journal_header *)(SB_JOURNAL(p_s_sb)->j_header_bh->b_data) ; if (le32_to_cpu(jh->j_first_unflushed_offset) >= 0 && le32_to_cpu(jh->j_first_unflushed_offset) < JOURNAL_BLOCK_COUNT && le32_to_cpu(jh->j_last_flush_trans_id) > 0) { last_flush_start = reiserfs_get_journal_block(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset) ; last_flush_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1153: found in " "header: first_unflushed_offset %d, last_flushed_trans_id " "%lu\n", le32_to_cpu(jh->j_first_unflushed_offset), last_flush_trans_id) ; valid_journal_header = 1 ; /* now, we try to read the first unflushed offset. If it is not valid, ** there is nothing more we can do, and it makes no sense to read ** through the whole log. */ d_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset)) ; ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL) ; if (!ret) { continue_replay = 0 ; } brelse(d_bh) ; } if (continue_replay && is_read_only(p_s_sb->s_dev)) { printk("clm-2076: device is readonly, unable to replay log\n") ; return -1 ; } if (continue_replay && (p_s_sb->s_flags & MS_RDONLY)) { printk("Warning, log replay starting on readonly filesystem\n") ; } /* ok, there are transactions that need to be replayed. start with the first log block, find ** all the valid transactions, and pick out the oldest. */ while(continue_replay && cur_dblock < (reiserfs_get_journal_block(p_s_sb) + JOURNAL_BLOCK_COUNT)) { d_bh = sb_bread(p_s_sb, cur_dblock) ; ret = journal_transaction_is_valid(p_s_sb, d_bh, &oldest_invalid_trans_id, &newest_mount_id) ; if (ret == 1) { desc = (struct reiserfs_journal_desc *)d_bh->b_data ; if (oldest_start == 0) { /* init all oldest_ values */ oldest_trans_id = le32_to_cpu(desc->j_trans_id) ; oldest_start = d_bh->b_blocknr ; newest_mount_id = le32_to_cpu(desc->j_mount_id) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1179: Setting " "oldest_start to offset %lu, trans_id %lu\n", oldest_start - reiserfs_get_journal_block(p_s_sb), oldest_trans_id) ; } else if (oldest_trans_id > le32_to_cpu(desc->j_trans_id)) { /* one we just read was older */ oldest_trans_id = le32_to_cpu(desc->j_trans_id) ; oldest_start = d_bh->b_blocknr ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1180: Resetting " "oldest_start to offset %lu, trans_id %lu\n", oldest_start - reiserfs_get_journal_block(p_s_sb), oldest_trans_id) ; } if (newest_mount_id < le32_to_cpu(desc->j_mount_id)) { newest_mount_id = le32_to_cpu(desc->j_mount_id) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting " "newest_mount_id to %d\n", le32_to_cpu(desc->j_mount_id)); } cur_dblock += le32_to_cpu(desc->j_len) + 2 ; } else { cur_dblock++ ; } brelse(d_bh) ; } /* step three, starting at the oldest transaction, replay */ if (last_flush_start > 0) { oldest_start = last_flush_start ; oldest_trans_id = last_flush_trans_id + 1 ; } cur_dblock = oldest_start ; if (oldest_trans_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1206: Starting replay " "from offset %lu, trans_id %lu\n", cur_dblock - reiserfs_get_journal_block(p_s_sb), oldest_trans_id) ; } replay_count = 0 ; while(continue_replay && oldest_trans_id > 0) { ret = journal_read_transaction(p_s_sb, cur_dblock, oldest_start, oldest_trans_id, newest_mount_id) ; if (ret < 0) { return ret ; } else if (ret != 0) { break ; } cur_dblock = reiserfs_get_journal_block(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start ; replay_count++ ; if (cur_dblock == oldest_start) break; } if (oldest_trans_id == 0) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1225: No valid " "transactions found\n") ; } /* j_start does not get set correctly if we don't replay any transactions. ** if we had a valid journal_header, set j_start to the first unflushed transaction value, ** copy the trans_id from the header */ if (valid_journal_header && replay_count == 0) { SB_JOURNAL(p_s_sb)->j_start = le32_to_cpu(jh->j_first_unflushed_offset) ; SB_JOURNAL(p_s_sb)->j_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1; SB_JOURNAL(p_s_sb)->j_last_flush_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) ; SB_JOURNAL(p_s_sb)->j_mount_id = le32_to_cpu(jh->j_mount_id) + 1; } else { SB_JOURNAL(p_s_sb)->j_mount_id = newest_mount_id + 1 ; } reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting " "newest_mount_id to %lu\n", SB_JOURNAL(p_s_sb)->j_mount_id) ; SB_JOURNAL(p_s_sb)->j_first_unflushed_offset = SB_JOURNAL(p_s_sb)->j_start ; if (replay_count > 0) { printk("reiserfs: replayed %d transactions in %lu seconds\n", replay_count, CURRENT_TIME - start) ; } if (!is_read_only(p_s_sb->s_dev) && _update_journal_header_block(p_s_sb, SB_JOURNAL(p_s_sb)->j_start, SB_JOURNAL(p_s_sb)->j_last_flush_trans_id)) { /* replay failed, caller must call free_journal_ram and abort ** the mount */ return -1 ; } return 0 ;}struct reiserfs_journal_commit_task { struct super_block *p_s_sb ; int jindex ; int wake_on_finish ; /* if this is one, we wake the task_done queue, if it ** is zero, we free the whole struct on finish */ struct reiserfs_journal_commit_task *self ; struct wait_queue *task_done ; struct tq_struct task ;} ;static void reiserfs_journal_commit_task_func(struct reiserfs_journal_commit_task *ct) { struct reiserfs_journal_list *jl ; jl = SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex ; flush_commit_list(ct->p_s_sb, SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex, 1) ; if (jl->j_len > 0 && atomic_read(&(jl->j_nonzerolen)) > 0 && atomic_read(&(jl->j_commit_left)) == 0) { kupdate_one_transaction(ct->p_s_sb, jl) ; } kfree(ct->self) ;}static void setup_commit_task_arg(struct reiserfs_journal_commit_task *ct, struct super_block *p_s_sb, int jindex) { if (!ct) { reiserfs_panic(NULL, "journal-1360: setup_commit_task_arg called with NULL struct\n") ; } ct->p_s_sb = p_s_sb ; ct->jindex = jindex ; ct->task_done = NULL ; INIT_LIST_HEAD(&ct->task.list) ; ct->task.sync = 0 ; ct->task.routine = (void *)(void *)reiserfs_journal_commit_task_func ; ct->self = ct ; ct->task.data = (void *)ct ;}static void commit_flush_async(struct super_block *p_s_sb, int jindex) { struct reiserfs_journal_commit_task *ct ; /* using GFP_NOFS, GFP_KERNEL could try to flush inodes, which will try ** to start/join a transaction, which will deadlock */ ct = kmalloc(sizeof(struct reiserfs_journal_commit_task), GFP_NOFS) ; if (ct) { setup_commit_task_arg(ct, p_s_sb, jindex) ; queue_task(&(ct->task), &reiserfs_commit_thread_tq); wake_up(&reiserfs_commit_thread_wait) ; } else {#ifdef CONFIG_REISERFS_CHECK reiserfs_warning("journal-1540: kmalloc failed, doing sync commit\n") ;#endif flush_commit_list(p_s_sb, SB_JOURNAL_LIST(p_s_sb) + jindex, 1) ; }}/*** this is the commit thread. It is started with kernel_thread on** FS mount, and journal_release() waits for it to exit.**** It could do a periodic commit, but there is a lot code for that** elsewhere right now, and I only wanted to implement this little** piece for starters.**** All we do here is sleep on the j_commit_thread_wait wait queue, and** then run the per filesystem commit task queue when we wakeup.*/static int reiserfs_journal_commit_thread(void *nullp) { daemonize() ; spin_lock_irq(¤t->sigmask_lock); sigfillset(¤t->blocked); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); sprintf(current->comm, "kreiserfsd") ; lock_kernel() ; while(1) { while(TQ_ACTIVE(reiserfs_commit_thread_tq)) { run_task_queue(&reiserfs_commit_thread_tq) ; } /* if there aren't any more filesystems left, break */ if (reiserfs_mounted_fs_count <= 0) { run_task_queue(&reiserfs_commit_thread_tq) ; break ; } wake_up(&reiserfs_commit_thread_done) ; interruptible_sleep_on_timeout(&reiserfs_commit_thread_wait, 5 * HZ) ; } unlock_kernel() ; wake_up(&reiserfs_c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -