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

📄 journal.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    /* if someone is getting the commit list, we must wait for them */    while (atomic_read(&(jl->j_commit_flushing))) {        sleep_on(&(jl->j_commit_wait)) ;    }    /* if someone is flushing this list, we must wait for them */    while (atomic_read(&(jl->j_flushing))) {        sleep_on(&(jl->j_flush_wait)) ;    }    /* was it flushed while we slept? */    if (jl->j_len <= 0 || jl->j_trans_id != orig_trans_id) {        return 0 ;    }    /* this list is now ours, we can change anything we want */    atomic_set(&(jl->j_flushing), 1) ;loop_start:    cn = jl->j_realblock ;    while(cn) {        saved_bh = NULL ;        /* if the blocknr == 0, this has been cleared from the hash,        ** skip it        */        if (cn->blocknr == 0) {            goto next ;        }        /* look for a more recent transaction that logged this        ** buffer.  Only the most recent transaction with a buffer in        ** it is allowed to send that buffer to disk        */        pjl = find_newer_jl_for_cn(cn) ;        if (run == 0 && !pjl && cn->bh && buffer_journal_dirty(cn->bh) &&            can_dirty(cn))         {            if (!test_bit(BH_JPrepared, &cn->bh->b_state)) {                set_bit(BLOCK_NEEDS_FLUSH, &cn->state) ;		submit_logged_buffer(cn->bh) ;            } else {                /* someone else is using this buffer.  We can't                 ** send it to disk right now because they might                ** be changing/logging it.                */                ret = 1 ;            }        } else if (test_bit(BLOCK_NEEDS_FLUSH, &cn->state)) {            clear_bit(BLOCK_NEEDS_FLUSH, &cn->state) ;            if (!pjl && cn->bh) {                wait_on_buffer(cn->bh) ;            }            /* check again, someone could have logged while we scheduled */            pjl = find_newer_jl_for_cn(cn) ;            /* before the JDirty_wait bit is set, the             ** buffer is added to the hash list.  So, if we are            ** run in the middle of a do_journal_end, we will notice            ** if this buffer was logged and added from the latest            ** transaction.  In this case, we don't want to decrement            ** b_count            */            if (!pjl && cn->bh && buffer_journal_dirty(cn->bh)) {                blocknr = cn->blocknr ;                walk_cn = cn ;                saved_bh= cn->bh ;                /* update all older transactions to show this block                ** was flushed                */                mark_buffer_notjournal_dirty(cn->bh) ;                while(walk_cn) {                    if (walk_cn->bh && walk_cn->blocknr == blocknr &&                          walk_cn->dev == cn->dev) {                        if (walk_cn->jlist) {                            atomic_dec(&(walk_cn->jlist->j_nonzerolen)) ;                        }                        walk_cn->bh = NULL ;                    }                    walk_cn = walk_cn->hnext ;                }                if (atomic_read(&saved_bh->b_count) < 1) {                    reiserfs_warning("clm-2081: bad count on %lu\n",                                       saved_bh->b_blocknr) ;                }                brelse(saved_bh) ;            }        }        /*        ** if the more recent transaction is committed to the log,        ** this buffer can be considered flushed.  Decrement our        ** counters to reflect one less buffer that needs writing.        **        ** note, this relies on all of the above code being        ** schedule free once pjl comes back non-null.        */        if (pjl && cn->bh && atomic_read(&pjl->j_commit_left) == 0) {            atomic_dec(&cn->jlist->j_nonzerolen) ;            cn->bh = NULL ;        } next:        cn = cn->next ;    }    /* the first run through the loop sends all the dirty buffers to    ** ll_rw_block.    ** the second run through the loop does all the accounting    */    if (run++ == 0) {        goto loop_start ;    }    atomic_set(&(jl->j_flushing), 0) ;    wake_up(&(jl->j_flush_wait)) ;    return ret ;}/* since we never give dirty buffers to bdflush/kupdate, we have to** flush them ourselves.  This runs through the journal lists, finds** old metadata in need of flushing and sends it to disk.** this does not end transactions, commit anything, or free** cnodes.**** returns the highest transaction id that was flushed last time*/static unsigned long reiserfs_journal_kupdate(struct super_block *s) {    struct reiserfs_journal_list *jl ;    int i ;    int start ;    time_t age ;    int ret = 0 ;    start = SB_JOURNAL_LIST_INDEX(s) ;    /* safety check to prevent flush attempts during a mount */    if (start < 0) {        return 0 ;    }    i = (start + 1) % JOURNAL_LIST_COUNT ;    while(i != start) {        jl = SB_JOURNAL_LIST(s) + i  ;        age = CURRENT_TIME - jl->j_timestamp ;        if (jl->j_len > 0 && // age >= (JOURNAL_MAX_COMMIT_AGE * 2) &&             atomic_read(&(jl->j_nonzerolen)) > 0 &&            atomic_read(&(jl->j_commit_left)) == 0) {            if (jl->j_trans_id == SB_JOURNAL(s)->j_trans_id) {                break ;            }            /* if ret was already 1, we want to preserve that */            ret |= kupdate_one_transaction(s, jl) ;        }         if (atomic_read(&(jl->j_nonzerolen)) > 0) {            ret |= 1 ;        }        i = (i + 1) % JOURNAL_LIST_COUNT ;    }    return ret ;}/*** removes any nodes in table with name block and dev as bh.** only touchs the hnext and hprev pointers.*/void remove_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_list *jl,struct buffer_head *bh,                         int remove_freed){  struct reiserfs_journal_cnode *cur ;  struct reiserfs_journal_cnode **head ;  if (!bh)    return ;  head= &(journal_hash(table, bh->b_dev, bh->b_blocknr)) ;  if (!head) {    return ;  }  cur = *head ;  while(cur) {    if (cur->blocknr == bh->b_blocknr && cur->dev == bh->b_dev && (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->dev = 0 ;      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) {  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) ;  }  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) ;  }  /* we decrement before we wake up, because the commit thread dies off  ** when it has been woken up and the count is <= 0  */  reiserfs_mounted_fs_count-- ;  wake_up(&reiserfs_commit_thread_wait) ;  sleep_on(&reiserfs_commit_thread_done) ;  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 (le32_to_cpu(commit->j_trans_id) != le32_to_cpu(desc->j_trans_id) ||       le32_to_cpu(commit->j_len) != le32_to_cpu(desc->j_len) ||       le32_to_cpu(commit->j_len) > JOURNAL_TRANS_MAX ||       le32_to_cpu(commit->j_len) <= 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 (le32_to_cpu(desc->j_len) > 0 && !memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8)) {    if (oldest_invalid_trans_id && *oldest_invalid_trans_id && le32_to_cpu(desc->j_trans_id) > *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\n", le32_to_cpu(desc->j_trans_id), 		       *oldest_invalid_trans_id);      return 0 ;    }    if (newest_mount_id && *newest_mount_id > le32_to_cpu(desc->j_mount_id)) {      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\n", desc->j_mount_id, 		     *newest_mount_id) ;      return -1 ;    }    offset = d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb) ;    /* ok, we have a journal description block, lets see if the transaction was valid */    c_bh = sb_bread(p_s_sb, reiserfs_get_journal_block(p_s_sb) + ((offset + le32_to_cpu(desc->j_len) + 1) % JOURNAL_BLOCK_COUNT)) ;    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\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) ;      if (oldest_invalid_trans_id)        *oldest_invalid_trans_id = le32_to_cpu(desc->j_trans_id) ;	reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1004: "	               "transaction_is_valid setting oldest invalid trans_id "		       "to %d\n", le32_to_cpu(desc->j_trans_id)) ;      return -1;     }    brelse(c_bh) ;    reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1006: found valid "                   "transaction start offset %lu, len %d id %d\n", 		   d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb), 		   le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_trans_id)) ;    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;  d_bh = sb_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 - reiserfs_get_journal_block(p_s_sb) ;  reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: "                 "journal_read_transaction, offset %lu, len %d mount_id %d\n", 		 d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb), 		 le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_mount_id)) ;  if (le32_to_cpu(desc->j_trans_id) < oldest_trans_id) {    reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: "                   "journal_read_trans skipping because %lu is too old\n", 		   cur_dblock - reiserfs_get_journal_block(p_s_sb)) ;    brelse(d_bh) ;    return 1 ;  }  if (le32_to_cpu(desc->j_mount_id) != newest_mount_id) {    reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: "                   "journal_read_trans skipping because %d is != "		   "newest_mount_id %lu\n", le32_to_cpu(desc->j_mount_id), 		    newest_mount_id) ;    brelse(d_bh) ;    return 1 ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -