⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 journal.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
    ** 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 + -