📄 journal.c
字号:
** transactions, but only bother if we've actually spanned ** across multiple lists */ if (flush_jl != jl) { ret = kupdate_transactions(s, jl, &tjl, &trans_id, len, i); } flush_journal_list(s, flush_jl, 1); return 0;}/*** removes any nodes in table with name block and dev as bh.** only touchs the hnext and hprev pointers.*/void remove_journal_hash(struct super_block *sb, struct reiserfs_journal_cnode **table, struct reiserfs_journal_list *jl, unsigned long block, int remove_freed){ struct reiserfs_journal_cnode *cur ; struct reiserfs_journal_cnode **head ; head= &(journal_hash(table, sb, block)) ; if (!head) { return ; } cur = *head ; while(cur) { if (cur->blocknr == block && cur->sb == sb && (jl == NULL || jl == cur->jlist) && (!test_bit(BLOCK_FREED, &cur->state) || remove_freed)) { if (cur->hnext) { cur->hnext->hprev = cur->hprev ; } if (cur->hprev) { cur->hprev->hnext = cur->hnext ; } else { *head = cur->hnext ; } cur->blocknr = 0 ; cur->sb = NULL ; cur->state = 0 ; if (cur->bh && cur->jlist) /* anybody who clears the cur->bh will also dec the nonzerolen */ atomic_dec(&(cur->jlist->j_nonzerolen)) ; cur->bh = NULL ; cur->jlist = NULL ; } cur = cur->hnext ; }}static void free_journal_ram(struct super_block *p_s_sb) { reiserfs_kfree(SB_JOURNAL(p_s_sb)->j_current_jl, sizeof(struct reiserfs_journal_list), p_s_sb); SB_JOURNAL(p_s_sb)->j_num_lists--; vfree(SB_JOURNAL(p_s_sb)->j_cnode_free_orig) ; free_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap) ; free_bitmap_nodes(p_s_sb) ; /* must be after free_list_bitmaps */ if (SB_JOURNAL(p_s_sb)->j_header_bh) { brelse(SB_JOURNAL(p_s_sb)->j_header_bh) ; } /* j_header_bh is on the journal dev, make sure not to release the journal * dev until we brelse j_header_bh */ release_journal_dev(p_s_sb, SB_JOURNAL(p_s_sb)); vfree(SB_JOURNAL(p_s_sb)) ;}/*** call on unmount. Only set error to 1 if you haven't made your way out** of read_super() yet. Any other caller must keep error at 0.*/static int do_journal_release(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, int error) { struct reiserfs_transaction_handle myth ; /* 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 */ 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) ; 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-- ; /* wait for all commits to finish */ cancel_delayed_work(&SB_JOURNAL(p_s_sb)->j_work); flush_workqueue(commit_wq); if (!reiserfs_mounted_fs_count) { destroy_workqueue(commit_wq); commit_wq = NULL; } free_journal_ram(p_s_sb) ; return 0 ;}/*** call on unmount. flush all journal trans, release all alloc'd ram*/int journal_release(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb) { return do_journal_release(th, p_s_sb, 0) ;}/*** only call from an error condition inside reiserfs_read_super!*/int journal_release_error(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb) { return do_journal_release(th, p_s_sb, 1) ;}/* compares description block with commit block. returns 1 if they differ, 0 if they are the same */static int journal_compare_desc_commit(struct super_block *p_s_sb, struct reiserfs_journal_desc *desc, struct reiserfs_journal_commit *commit) { if (get_commit_trans_id (commit) != get_desc_trans_id (desc) || get_commit_trans_len (commit) != get_desc_trans_len (desc) || get_commit_trans_len (commit) > SB_JOURNAL_TRANS_MAX(p_s_sb) || get_commit_trans_len (commit) <= 0 ) { return 1 ; } return 0 ;}/* returns 0 if it did not find a description block ** returns -1 if it found a corrupt commit block** returns 1 if both desc and commit were valid */static int journal_transaction_is_valid(struct super_block *p_s_sb, struct buffer_head *d_bh, unsigned long *oldest_invalid_trans_id, unsigned long *newest_mount_id) { struct reiserfs_journal_desc *desc ; struct reiserfs_journal_commit *commit ; struct buffer_head *c_bh ; unsigned long offset ; if (!d_bh) return 0 ; desc = (struct reiserfs_journal_desc *)d_bh->b_data ; if (get_desc_trans_len(desc) > 0 && !memcmp(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8)) { if (oldest_invalid_trans_id && *oldest_invalid_trans_id && get_desc_trans_id(desc) > *oldest_invalid_trans_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-986: transaction " "is valid returning because trans_id %d is greater than " "oldest_invalid %lu", get_desc_trans_id(desc), *oldest_invalid_trans_id); return 0 ; } if (newest_mount_id && *newest_mount_id > get_desc_mount_id (desc)) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1087: transaction " "is valid returning because mount_id %d is less than " "newest_mount_id %lu", get_desc_mount_id (desc), *newest_mount_id) ; return -1 ; } if ( get_desc_trans_len(desc) > SB_JOURNAL_TRANS_MAX(p_s_sb) ) { reiserfs_warning(p_s_sb, "journal-2018: Bad transaction length %d encountered, ignoring transaction", get_desc_trans_len(desc)); return -1 ; } offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ; /* ok, we have a journal description block, lets see if the transaction was valid */ c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((offset + get_desc_trans_len(desc) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; if (!c_bh) return 0 ; 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_transaction_is_valid, commit offset %ld had bad " "time %d or length %d", c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), get_commit_trans_id (commit), get_commit_trans_len(commit)); brelse(c_bh) ; if (oldest_invalid_trans_id) { *oldest_invalid_trans_id = get_desc_trans_id(desc) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1004: " "transaction_is_valid setting oldest invalid trans_id " "to %d", get_desc_trans_id(desc)) ; } return -1; } brelse(c_bh) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1006: found valid " "transaction start offset %llu, len %d id %d", d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), get_desc_trans_len(desc), get_desc_trans_id(desc)) ; return 1 ; } else { return 0 ; }}static void brelse_array(struct buffer_head **heads, int num) { int i ; for (i = 0 ; i < num ; i++) { brelse(heads[i]) ; }}/*** given the start, and values for the oldest acceptable transactions,** this either reads in a replays a transaction, or returns because the transaction** is invalid, or too old.*/static int journal_read_transaction(struct super_block *p_s_sb, unsigned long cur_dblock, unsigned long oldest_start, unsigned long oldest_trans_id, unsigned long newest_mount_id) { struct reiserfs_journal_desc *desc ; struct reiserfs_journal_commit *commit ; unsigned long trans_id = 0 ; struct buffer_head *c_bh ; struct buffer_head *d_bh ; struct buffer_head **log_blocks = NULL ; struct buffer_head **real_blocks = NULL ; unsigned long trans_offset ; int i; int trans_half; d_bh = journal_bread(p_s_sb, cur_dblock) ; if (!d_bh) return 1 ; desc = (struct reiserfs_journal_desc *)d_bh->b_data ; trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: " "journal_read_transaction, offset %llu, len %d mount_id %d", d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), get_desc_trans_len(desc), get_desc_mount_id(desc)) ; if (get_desc_trans_id(desc) < oldest_trans_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: " "journal_read_trans skipping because %lu is too old", cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ; brelse(d_bh) ; return 1 ; } if (get_desc_mount_id(desc) != newest_mount_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: " "journal_read_trans skipping because %d is != " "newest_mount_id %lu", get_desc_mount_id(desc), newest_mount_id) ; brelse(d_bh) ; return 1 ; } c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + get_desc_trans_len(desc) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; 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 %llu had bad time %d or length %d", c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), get_commit_trans_id(commit), get_commit_trans_len(commit)); brelse(c_bh) ; brelse(d_bh) ; return 1; } trans_id = get_desc_trans_id(desc) ; /* now we know we've got a good transaction, and it was inside the valid time ranges */ log_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; real_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; if (!log_blocks || !real_blocks) { brelse(c_bh) ; brelse(d_bh) ; reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_warning(p_s_sb, "journal-1169: kmalloc failed, unable to mount FS") ; return -1 ; } /* get all the buffer heads */ trans_half = journal_trans_half (p_s_sb->s_blocksize) ; for(i = 0 ; i < get_desc_trans_len(desc) ; i++) { log_blocks[i] = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + (trans_offset + 1 + i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)); if (i < 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 - trans_half])) ; } if ( real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(p_s_sb) ) { reiserfs_warning(p_s_sb, "journal-1207: REPLAY FAILURE fsck required! Block to replay is outside of filesystem"); goto abort_replay; } /* make sure we don't try to replay onto log or reserved area */ if (is_block_in_log_or_reserved_area(p_s_sb, real_blocks[i]->b_blocknr)) { reiserfs_warning(p_s_sb, "journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block") ;abort_replay: brelse_array(log_blocks, i) ; brelse_array(real_blocks, i) ; brelse(c_bh) ; brelse(d_bh) ; reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } } /* read in the log blocks, memcpy to the corresponding real block */ ll_rw_block(READ, get_desc_trans_len(desc), log_blocks) ; for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { wait_on_buffer(log_blocks[i]) ; if (!buffer_uptodate(log_blocks[i])) { reiserfs_warning(p_s_sb, "journal-1212: REPLAY FAILURE fsck required! buffer write failed") ; brelse_array(log_blocks + i, get_desc_trans_len(desc) - i) ; brelse_array(real_blocks, get_desc_trans_len(desc)) ; brelse(c_bh) ; brelse(d_bh) ; reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ; set_buffer_uptodate(real_blocks[i]) ; brelse(log_blocks[i]) ; } /* flush out the real blocks */ for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { set_buffer_dirty(real_blocks[i]) ; ll_rw_block(WRITE, 1, real_blocks + i) ; } for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { wait_on_buffer(real_blocks[i]) ; if (!buffer_uptodate(real_blocks[i])) { reiserfs_warning(p_s_sb, "journal-1226: REPLAY FAILURE, fsck required! buffer write failed") ; brelse_array(real_blocks + i, get_desc_trans_len(desc) - i) ; brelse(c_bh) ; brelse(d_bh) ; reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } brelse(real_blocks[i]) ; } cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + get_desc_trans_len(desc) + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1095: setting journal " "start to offset %ld", cur_dblock - SB_ONDISK_JOURNAL_1st_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 - SB_ONDISK_JOURNAL_1st_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) ; reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; return 0 ;}/* This function reads blocks starting from block and to max_block of bufsize size (but no more than BUFNR blocks at a time). This proved to improve mounting speed on self-rebuilding raid5 arrays at least. Right now it is only used from journal code. But later we might use it from other places. Note: Do not use journal_getblk/sb_getblk functions here! */struct buffer_head * reiserfs_breada (struct block_device *dev, int block, int bufsize, unsigned int max_block){ struct buffer_head * bhlist[BUFNR]; unsigned int blocks = BUFNR; struct buffer_head * bh; int i, j; bh = __getblk (dev, block, bufsize ); if (buffer_uptodate (bh)) return (bh); if (block + BUFNR > max_block) { blocks = max_block - block; } bhlist[0] = bh; j = 1; for (i = 1; i < blocks; i++) { bh = __getblk (dev, block + i, bufsize); if (buffer_uptodate (bh)) { brelse (bh); break; } else bhlist[j++] = bh; } ll_rw_block (READ, j, bhlist); for(i = 1; i < j; i++) brelse (bhlist[i]); bh = bhlist[0]; wait_on_buffer (bh); if (buffer_uptodate (bh)) return bh; brelse (bh); return NULL;}/*** 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, which 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 oldest_trans_i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -