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

📄 journal.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* buffer is in current transaction */inline int buffer_journaled(const struct buffer_head *bh) {  if (bh)    return test_bit(BH_JDirty, ( struct buffer_head * ) &bh->b_state) ;  else    return 0 ;}/* disk block was taken off free list before being in a finished transation, or written to disk** journal_new blocks can be reused immediately, for any purpose*/ inline int buffer_journal_new(const struct buffer_head *bh) {  if (bh)     return test_bit(BH_JNew, ( struct buffer_head * )&bh->b_state) ;  else    return 0 ;}inline int mark_buffer_journal_new(struct buffer_head *bh) {  if (bh) {    set_bit(BH_JNew, &bh->b_state) ;  }  return 0 ;}inline int mark_buffer_not_journaled(struct buffer_head *bh) {  if (bh)     clear_bit(BH_JDirty, &bh->b_state) ;  return 0 ;}/* utility function to force a BUG if it is called without the big** kernel lock held.  caller is the string printed just before calling BUG()*/void reiserfs_check_lock_depth(char *caller) {#ifdef CONFIG_SMP  if (current->lock_depth < 0) {    printk("%s called without kernel lock held\n", caller) ;    show_reiserfs_locks() ;    BUG() ;  }#else  ;#endif}/* return a cnode with same dev, block number and size in table, or null if not found */static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct reiserfs_journal_cnode **table,                                   				  kdev_t dev,long bl,int size) {  struct reiserfs_journal_cnode *cn ;  cn = journal_hash(table, dev, bl) ;  while(cn) {    if ((cn->blocknr == bl) && (cn->dev == dev))      return cn ;    cn = cn->hnext ;  }  return (struct reiserfs_journal_cnode *)0 ;}/* returns a cnode with same size, block number and dev as bh in the current transaction hash.  NULL if not found */static inline struct reiserfs_journal_cnode *get_journal_hash(struct super_block *p_s_sb, struct buffer_head *bh) {  struct reiserfs_journal_cnode *cn ;  if (bh) {    cn =  get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, bh->b_dev, bh->b_blocknr, bh->b_size) ;  }  else {    return (struct reiserfs_journal_cnode *)0 ;  }  return cn ;}/* once upon a time, the journal would deadlock.  a lot.  Now, when** CONFIG_REISERFS_CHECK is defined, anytime someone enters a** transaction, it pushes itself into this ugly static list, and pops** itself off before calling journal_end.  I made a SysRq key to dump** the list, and tell me what the writers are when I'm deadlocked.  */				/* are you depending on the compiler                                   to optimize this function away                                   everywhere it is called? It is not                                   obvious how this works, but I                                   suppose debugging code need not be                                   clear.  -Hans */static char *journal_writers[512] ;int push_journal_writer(char *s) {#ifdef CONFIG_REISERFS_CHECK  int i ;  for (i = 0 ; i < 512 ; i++) {    if (!journal_writers[i]) {      journal_writers[i] = s ;      return i ;    }  }  return -1 ;#else  return 0 ;#endif}int pop_journal_writer(int index) {#ifdef CONFIG_REISERFS_CHECK  if (index >= 0) {    journal_writers[index] = NULL ;  }#endif  return 0 ;}int dump_journal_writers(void) {  int i ;  for (i = 0 ; i < 512 ; i++) {    if (journal_writers[i]) {      printk("%d: %s\n", i, journal_writers[i]) ;    }  }  return 0 ;}/*** this actually means 'can this block be reallocated yet?'.  If you set search_all, a block can only be allocated** if it is not in the current transaction, was not freed by the current transaction, and has no chance of ever** being overwritten by a replay after crashing.**** If you don't set search_all, a block can only be allocated if it is not in the current transaction.  Since deleting** a block removes it from the current transaction, this case should never happen.  If you don't set search_all, make** sure you never write the block without logging it.**** next_zero_bit is a suggestion about the next block to try for find_forward.** when bl is rejected because it is set in a journal list bitmap, we search** for the next zero bit in the bitmap that rejected bl.  Then, we return that** through next_zero_bit for find_forward to try.**** Just because we return something in next_zero_bit does not mean we won't** reject it on the next call to reiserfs_in_journal***/int reiserfs_in_journal(struct super_block *p_s_sb, kdev_t dev,                         unsigned long bl, int size, int search_all, 			unsigned long *next_zero_bit) {  struct reiserfs_journal_cnode *cn ;  struct reiserfs_list_bitmap *jb ;  int i ;  int bmap_nr = bl / (p_s_sb->s_blocksize << 3) ;  int bit_nr = bl % (p_s_sb->s_blocksize << 3) ;  int tmp_bit ;  *next_zero_bit = 0 ; /* always start this at zero. */  /* we aren't logging all blocks are safe for reuse */  if (reiserfs_dont_log(p_s_sb)) {    return 0 ;  }  PROC_INFO_INC( p_s_sb, journal.in_journal );  /* If we aren't doing a search_all, this is a metablock, and it will be logged before use.  ** if we crash before the transaction that freed it commits,  this transaction won't  ** have committed either, and the block will never be written  */  if (search_all) {    for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {      PROC_INFO_INC( p_s_sb, journal.in_journal_bitmap );      jb = SB_JOURNAL(p_s_sb)->j_list_bitmap + i ;      if (jb->journal_list && jb->bitmaps[bmap_nr] &&          test_bit(bit_nr, jb->bitmaps[bmap_nr]->data)) {	tmp_bit = find_next_zero_bit((unsigned long *)	                             (jb->bitmaps[bmap_nr]->data),	                             p_s_sb->s_blocksize << 3, bit_nr+1) ; 	*next_zero_bit = bmap_nr * (p_s_sb->s_blocksize << 3) + tmp_bit ;	return 1 ;      }    }  }  /* is it in any old transactions? */  if (search_all && (cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_list_hash_table, dev,bl,size))) {    return 1;   }  /* is it in the current transaction.  This should never happen */  if ((cn = get_journal_hash_dev(SB_JOURNAL(p_s_sb)->j_hash_table, dev,bl,size))) {    return 1;   }  PROC_INFO_INC( p_s_sb, journal.in_journal_reusable );  /* safe for reuse */  return 0 ;}/* insert cn into table*/inline void insert_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_cnode *cn) {  struct reiserfs_journal_cnode *cn_orig ;  cn_orig = journal_hash(table, cn->dev, cn->blocknr) ;  cn->hnext = cn_orig ;  cn->hprev = NULL ;  if (cn_orig) {    cn_orig->hprev = cn ;  }  journal_hash(table, cn->dev, cn->blocknr) =  cn ;}/* lock the current transaction */inline static void lock_journal(struct super_block *p_s_sb) {  PROC_INFO_INC( p_s_sb, journal.lock_journal );  while(atomic_read(&(SB_JOURNAL(p_s_sb)->j_wlock)) > 0) {    PROC_INFO_INC( p_s_sb, journal.lock_journal_wait );    sleep_on(&(SB_JOURNAL(p_s_sb)->j_wait)) ;  }  atomic_set(&(SB_JOURNAL(p_s_sb)->j_wlock), 1) ;}/* unlock the current transaction */inline static void unlock_journal(struct super_block *p_s_sb) {  atomic_dec(&(SB_JOURNAL(p_s_sb)->j_wlock)) ;  wake_up(&(SB_JOURNAL(p_s_sb)->j_wait)) ;}/*** this used to be much more involved, and I'm keeping it just in case things get ugly again.** it gets called by flush_commit_list, and cleans up any data stored about blocks freed during a** transaction.*/static void cleanup_freed_for_journal_list(struct super_block *p_s_sb, struct reiserfs_journal_list *jl) {  struct reiserfs_list_bitmap *jb = jl->j_list_bitmap ;  if (jb) {    cleanup_bitmap_list(p_s_sb, jb) ;  }  jl->j_list_bitmap->journal_list = NULL ;  jl->j_list_bitmap = NULL ;}/*** if this journal list still has commit blocks unflushed, send them to disk.**** log areas must be flushed in order (transaction 2 can't commit before transaction 1)** Before the commit block can by written, every other log block must be safely on disk***/static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) {  int i, count ;  int index = 0 ;  int bn ;  int retry_count = 0 ;  int orig_commit_left = 0 ;  struct buffer_head *tbh = NULL ;  struct reiserfs_journal_list *other_jl ;  reiserfs_check_lock_depth("flush_commit_list") ;  if (atomic_read(&jl->j_older_commits_done)) {    return 0 ;  }  /* before we can put our commit blocks on disk, we have to make sure everyone older than  ** us is on disk too  */  if (jl->j_len <= 0) {    return 0 ;  }  if (flushall) {    /* we _must_ make sure the transactions are committed in order.  Start with the    ** index after this one, wrap all the way around     */    index = (jl - SB_JOURNAL_LIST(s)) + 1 ;    for (i = 0 ; i < JOURNAL_LIST_COUNT ; i++) {      other_jl = SB_JOURNAL_LIST(s) + ( (index + i) % JOURNAL_LIST_COUNT) ;      if (other_jl && other_jl != jl && other_jl->j_len > 0 && other_jl->j_trans_id > 0 &&           other_jl->j_trans_id <= jl->j_trans_id && (atomic_read(&(jl->j_older_commits_done)) == 0)) {        flush_commit_list(s, other_jl, 0) ;      }    }  }  count = 0 ;  /* don't flush the commit list for the current transactoin */  if (jl == ((SB_JOURNAL_LIST(s) + SB_JOURNAL_LIST_INDEX(s)))) {    return 0 ;  }  /* make sure nobody is trying to flush this one at the same time */  if (atomic_read(&(jl->j_commit_flushing))) {    sleep_on(&(jl->j_commit_wait)) ;    if (flushall) {      atomic_set(&(jl->j_older_commits_done), 1) ;    }    return 0 ;  }    /* this commit is done, exit */  if (atomic_read(&(jl->j_commit_left)) <= 0) {    if (flushall) {      atomic_set(&(jl->j_older_commits_done), 1) ;    }    return 0 ;  }  /* keeps others from flushing while we are flushing */  atomic_set(&(jl->j_commit_flushing), 1) ;   if (jl->j_len > JOURNAL_TRANS_MAX) {    reiserfs_panic(s, "journal-512: flush_commit_list: length is %lu, list number %d\n", jl->j_len, jl - SB_JOURNAL_LIST(s)) ;    return 0 ;  }  orig_commit_left = atomic_read(&(jl->j_commit_left)) ;   /* start by checking all the commit blocks in this transaction.    ** Add anyone not on disk into tbh.  Stop checking once commit_left <= 1, because that means we  ** only have the commit block left   */retry:  count = 0 ;  for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 && i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */    bn = reiserfs_get_journal_block(s) + (jl->j_start+i) % JOURNAL_BLOCK_COUNT;    tbh = sb_get_hash_table(s, bn) ;/* kill this sanity check */if (count > (orig_commit_left + 2)) {reiserfs_panic(s, "journal-539: flush_commit_list: BAD count(%d) > orig_commit_left(%d)!\n", count, orig_commit_left) ;}    if (tbh) {      if (buffer_locked(tbh)) { /* wait on it, redo it just to make sure */	wait_on_buffer(tbh) ;	if (!buffer_uptodate(tbh)) {	  reiserfs_panic(s, "journal-584, buffer write failed\n") ;	}      }       if (buffer_dirty(tbh)) {	printk("journal-569: flush_commit_list, block already dirty!\n") ;      } else {					mark_buffer_dirty(tbh) ;      }      ll_rw_block(WRITE, 1, &tbh) ;      count++ ;      put_bh(tbh) ; /* once for our get_hash */    }   }  /* wait on everyone in tbh before writing commit block*/  if (count > 0) {    for (i = 0 ; atomic_read(&(jl->j_commit_left)) > 1 &&                  i < (jl->j_len + 1) ; i++) {  /* everything but commit_bh */      bn = reiserfs_get_journal_block(s) + (jl->j_start + i) % JOURNAL_BLOCK_COUNT  ;      tbh = sb_get_hash_table(s, bn) ;      wait_on_buffer(tbh) ;      if (!buffer_uptodate(tbh)) {	reiserfs_panic(s, "journal-601, buffer write failed\n") ;      }      put_bh(tbh) ; /* once for our get_hash */      bforget(tbh) ;    /* once due to original getblk in do_journal_end */      atomic_dec(&(jl->j_commit_left)) ;    }  }  if (atomic_read(&(jl->j_commit_left)) != 1) { /* just the commit_bh left, flush it without calling getblk for everyone */    if (retry_count < 2) {      printk("journal-582: flush_commit_list, not all log blocks on disk yet, trying again\n") ;      retry_count++ ;      goto retry;    }    reiserfs_panic(s, "journal-563: flush_commit_list: BAD, j_commit_left is %u, should be 1\n", 		   atomic_read(&(jl->j_commit_left)));  }  mark_buffer_dirty(jl->j_commit_bh) ;  ll_rw_block(WRITE, 1, &(jl->j_commit_bh)) ;  wait_on_buffer(jl->j_commit_bh) ;  if (!buffer_uptodate(jl->j_commit_bh)) {

⌨️ 快捷键说明

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