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

📄 journal.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
/*** Write ahead logging implementation copyright Chris Mason 2000**** The background commits make this code very interelated, and ** overly complex.  I need to rethink things a bit....The major players:**** journal_begin -- call with the number of blocks you expect to log.  **                  If the current transaction is too** 		    old, it will block until the current transaction is ** 		    finished, and then start a new one.**		    Usually, your transaction will get joined in with **                  previous ones for speed.**** journal_join  -- same as journal_begin, but won't block on the current **                  transaction regardless of age.  Don't ever call**                  this.  Ever.  There are only two places it should be **                  called from, and they are both inside this file.**** journal_mark_dirty -- adds blocks into this transaction.  clears any flags **                       that might make them get sent to disk**                       and then marks them BH_JDirty.  Puts the buffer head **                       into the current transaction hash.  **** journal_end -- if the current transaction is batchable, it does nothing**                   otherwise, it could do an async/synchronous commit, or**                   a full flush of all log and real blocks in the **                   transaction.**** flush_old_commits -- if the current transaction is too old, it is ended and **                      commit blocks are sent to disk.  Forces commit blocks **                      to disk for all backgrounded commits that have been **                      around too long.**		     -- Note, if you call this as an immediate flush from **		        from within kupdate, it will ignore the immediate flag*/#include <linux/config.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/time.h>#include <asm/semaphore.h>#include <linux/vmalloc.h>#include <linux/reiserfs_fs.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/fcntl.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/smp_lock.h>#include <linux/suspend.h>#include <linux/buffer_head.h>#include <linux/workqueue.h>#include <linux/writeback.h>#include <linux/blkdev.h>/* gets a struct reiserfs_journal_list * from a list head */#define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \                               j_list))#define JOURNAL_WORK_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \                               j_working_list))/* the number of mounted filesystems.  This is used to decide when to** start and kill the commit workqueue*/static int reiserfs_mounted_fs_count;static struct workqueue_struct *commit_wq;#define JOURNAL_TRANS_HALF 1018   /* must be correct to keep the desc and commit				     structs at 4k */#define BUFNR 64 /*read ahead *//* cnode stat bits.  Move these into reiserfs_fs.h */#define BLOCK_FREED 2		/* this block was freed, and can't be written.  */#define BLOCK_FREED_HOLDER 3    /* this block was freed during this transaction, and can't be written */#define BLOCK_NEEDS_FLUSH 4	/* used in flush_journal_list */#define BLOCK_DIRTIED 5/* journal list state bits */#define LIST_TOUCHED 1#define LIST_DIRTY   2#define LIST_COMMIT_PENDING  4		/* someone will commit this list *//* flags for do_journal_end */#define FLUSH_ALL   1		/* flush commit and real blocks */#define COMMIT_NOW  2		/* end and commit this transaction */#define WAIT        4		/* wait for the log blocks to hit the disk*//* state bits for the journal */#define WRITERS_BLOCKED 1      /* set when new writers not allowed */#define WRITERS_QUEUED 2       /* set when log is full due to too many				* writers				*/static int do_journal_end(struct reiserfs_transaction_handle *,struct super_block *,unsigned long nblocks,int flags) ;static int flush_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ;static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall)  ;static int can_dirty(struct reiserfs_journal_cnode *cn) ;static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks);static int release_journal_dev( struct super_block *super,				struct reiserfs_journal *journal );static int dirty_one_transaction(struct super_block *s,                                 struct reiserfs_journal_list *jl);static void flush_async_commits(void *p);static void init_journal_hash(struct super_block *p_s_sb) {  memset(SB_JOURNAL(p_s_sb)->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ;}/*** clears BH_Dirty and sticks the buffer on the clean list.  Called because I can't allow refile_buffer to** make schedule happen after I've freed a block.  Look at remove_from_transaction and journal_mark_freed for** more details.*/static int reiserfs_clean_and_file_buffer(struct buffer_head *bh) {  if (bh) {    clear_buffer_dirty(bh);    clear_bit(BH_JTest, &bh->b_state);  }  return 0 ;}static void disable_barrier(struct super_block *s){    REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_BARRIER_FLUSH);    printk("reiserfs: disabling flush barriers on %s\n", reiserfs_bdevname(s));}static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block *p_s_sb) {  struct reiserfs_bitmap_node *bn ;  static int id;  bn = reiserfs_kmalloc(sizeof(struct reiserfs_bitmap_node), GFP_NOFS, p_s_sb) ;  if (!bn) {    return NULL ;  }  bn->data = reiserfs_kmalloc(p_s_sb->s_blocksize, GFP_NOFS, p_s_sb) ;  if (!bn->data) {    reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;    return NULL ;  }  bn->id = id++ ;  memset(bn->data, 0, p_s_sb->s_blocksize) ;  INIT_LIST_HEAD(&bn->list) ;  return bn ;}static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *p_s_sb) {  struct reiserfs_bitmap_node *bn = NULL;  struct list_head *entry = SB_JOURNAL(p_s_sb)->j_bitmap_nodes.next ;  SB_JOURNAL(p_s_sb)->j_used_bitmap_nodes++ ;repeat:  if(entry != &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) {    bn = list_entry(entry, struct reiserfs_bitmap_node, list) ;    list_del(entry) ;    memset(bn->data, 0, p_s_sb->s_blocksize) ;    SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes-- ;    return bn ;  }  bn = allocate_bitmap_node(p_s_sb) ;  if (!bn) {    yield();    goto repeat ;  }  return bn ;}static inline void free_bitmap_node(struct super_block *p_s_sb,                                    struct reiserfs_bitmap_node *bn) {  SB_JOURNAL(p_s_sb)->j_used_bitmap_nodes-- ;  if (SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes > REISERFS_MAX_BITMAP_NODES) {    reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ;    reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;  } else {    list_add(&bn->list, &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;    SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes++ ;  }}static void allocate_bitmap_nodes(struct super_block *p_s_sb) {  int i ;  struct reiserfs_bitmap_node *bn = NULL ;  for (i = 0 ; i < REISERFS_MIN_BITMAP_NODES ; i++) {    bn = allocate_bitmap_node(p_s_sb) ;    if (bn) {      list_add(&bn->list, &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;      SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes++ ;    } else {      break ; // this is ok, we'll try again when more are needed     }  }}static int set_bit_in_list_bitmap(struct super_block *p_s_sb, int block,                                  struct reiserfs_list_bitmap *jb) {  int bmap_nr = block / (p_s_sb->s_blocksize << 3) ;  int bit_nr = block % (p_s_sb->s_blocksize << 3) ;  if (!jb->bitmaps[bmap_nr]) {    jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb) ;  }  set_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data) ;  return 0 ;}static void cleanup_bitmap_list(struct super_block *p_s_sb,                                struct reiserfs_list_bitmap *jb) {  int i;  if (jb->bitmaps == NULL)    return;  for (i = 0 ; i < SB_BMAP_NR(p_s_sb) ; i++) {    if (jb->bitmaps[i]) {      free_bitmap_node(p_s_sb, jb->bitmaps[i]) ;      jb->bitmaps[i] = NULL ;    }  }}/*** only call this on FS unmount.*/static int free_list_bitmaps(struct super_block *p_s_sb,                             struct reiserfs_list_bitmap *jb_array) {  int i ;  struct reiserfs_list_bitmap *jb ;  for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {    jb = jb_array + i ;    jb->journal_list = NULL ;    cleanup_bitmap_list(p_s_sb, jb) ;    vfree(jb->bitmaps) ;    jb->bitmaps = NULL ;  }  return 0;}static int free_bitmap_nodes(struct super_block *p_s_sb) {  struct list_head *next = SB_JOURNAL(p_s_sb)->j_bitmap_nodes.next ;  struct reiserfs_bitmap_node *bn ;  while(next != &SB_JOURNAL(p_s_sb)->j_bitmap_nodes) {    bn = list_entry(next, struct reiserfs_bitmap_node, list) ;    list_del(next) ;    reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ;    reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;    next = SB_JOURNAL(p_s_sb)->j_bitmap_nodes.next ;    SB_JOURNAL(p_s_sb)->j_free_bitmap_nodes-- ;  }  return 0 ;}/*** get memory for JOURNAL_NUM_BITMAPS worth of bitmaps. ** jb_array is the array to be filled in.*/int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb,                                   struct reiserfs_list_bitmap *jb_array,				   int bmap_nr) {  int i ;  int failed = 0 ;  struct reiserfs_list_bitmap *jb ;  int mem = bmap_nr * sizeof(struct reiserfs_bitmap_node *) ;  for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {    jb = jb_array + i ;    jb->journal_list = NULL ;    jb->bitmaps = vmalloc( mem ) ;    if (!jb->bitmaps) {      reiserfs_warning(p_s_sb, "clm-2000, unable to allocate bitmaps for journal lists") ;      failed = 1;         break ;    }    memset(jb->bitmaps, 0, mem) ;  }  if (failed) {    free_list_bitmaps(p_s_sb, jb_array) ;    return -1 ;  }  return 0 ;}/*** find an available list bitmap.  If you can't find one, flush a commit list ** and try again*/static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb, struct reiserfs_journal_list *jl) {  int i,j ;   struct reiserfs_list_bitmap *jb = NULL ;  for (j = 0 ; j < (JOURNAL_NUM_BITMAPS * 3) ; j++) {    i = SB_JOURNAL(p_s_sb)->j_list_bitmap_index ;    SB_JOURNAL(p_s_sb)->j_list_bitmap_index = (i + 1) % JOURNAL_NUM_BITMAPS ;    jb = SB_JOURNAL(p_s_sb)->j_list_bitmap + i ;    if (SB_JOURNAL(p_s_sb)->j_list_bitmap[i].journal_list) {      flush_commit_list(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap[i].journal_list, 1) ;      if (!SB_JOURNAL(p_s_sb)->j_list_bitmap[i].journal_list) {	break ;      }    } else {      break ;    }  }  if (jb->journal_list) { /* double check to make sure if flushed correctly */    return NULL ;  }  jb->journal_list = jl ;  return jb ;}/* ** allocates a new chunk of X nodes, and links them all together as a list.** Uses the cnode->next and cnode->prev pointers** returns NULL on failure*/static struct reiserfs_journal_cnode *allocate_cnodes(int num_cnodes) {  struct reiserfs_journal_cnode *head ;  int i ;  if (num_cnodes <= 0) {    return NULL ;  }  head = vmalloc(num_cnodes * sizeof(struct reiserfs_journal_cnode)) ;  if (!head) {    return NULL ;  }  memset(head, 0, num_cnodes * sizeof(struct reiserfs_journal_cnode)) ;  head[0].prev = NULL ;  head[0].next = head + 1 ;  for (i = 1 ; i < num_cnodes; i++) {    head[i].prev = head + (i - 1) ;    head[i].next = head + (i + 1) ; /* if last one, overwrite it after the if */  }  head[num_cnodes -1].next = NULL ;  return head ;}/*** pulls a cnode off the free list, or returns NULL on failure */static struct reiserfs_journal_cnode *get_cnode(struct super_block *p_s_sb) {  struct reiserfs_journal_cnode *cn ;  reiserfs_check_lock_depth(p_s_sb, "get_cnode") ;  if (SB_JOURNAL(p_s_sb)->j_cnode_free <= 0) {    return NULL ;  }  SB_JOURNAL(p_s_sb)->j_cnode_used++ ;  SB_JOURNAL(p_s_sb)->j_cnode_free-- ;  cn = SB_JOURNAL(p_s_sb)->j_cnode_free_list ;  if (!cn) {    return cn ;  }  if (cn->next) {    cn->next->prev = NULL ;  }  SB_JOURNAL(p_s_sb)->j_cnode_free_list = cn->next ;  memset(cn, 0, sizeof(struct reiserfs_journal_cnode)) ;  return cn ;}/*** returns a cnode to the free list */static void free_cnode(struct super_block *p_s_sb, struct reiserfs_journal_cnode *cn) {  reiserfs_check_lock_depth(p_s_sb, "free_cnode") ;  SB_JOURNAL(p_s_sb)->j_cnode_used-- ;  SB_JOURNAL(p_s_sb)->j_cnode_free++ ;  /* memset(cn, 0, sizeof(struct reiserfs_journal_cnode)) ; */  cn->next = SB_JOURNAL(p_s_sb)->j_cnode_free_list ;  if (SB_JOURNAL(p_s_sb)->j_cnode_free_list) {    SB_JOURNAL(p_s_sb)->j_cnode_free_list->prev = cn ;  }  cn->prev = NULL ; /* not needed with the memset, but I might kill the memset, and forget to do this */  SB_JOURNAL(p_s_sb)->j_cnode_free_list = cn ;}static int clear_prepared_bits(struct buffer_head *bh) {  clear_bit(BH_JPrepared, &bh->b_state) ;  clear_bit(BH_JRestore_dirty, &bh->b_state) ;  return 0 ;}/* buffer is in current transaction */inline int buffer_journaled(const struct buffer_head *bh) {  if (bh)    return test_bit(BH_JDirty, &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) {

⌨️ 快捷键说明

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