cleanup b_inode usage and fix onstack inode abuse
PATCH 1/1 cleanup b_inode usage and fix onstack inode abuse
Currently the b_inode of struct buffer_head is a pointer to an inode, but it only always used as bool value.
This patch changes it to be a flag bit in the bh state. This allows us to shape of 32bit rom struct buffer_head for other uses like the lower layer private data that LVM2 needs or an increase of b_size that IA64 boxens with 64k pages need.
I also cleanes up buffer.c be removing lots of duplicated code and enables the alloc_inode patch by removing the last on-stack inodes.
The patch has been ACKed by akpm and sct, and a very similar change webnt into early 2.5.
fs/buffer.c +18 -26
@@ -583,37 +583,29 @@ struct buffer_head * get_hash_table(kdevreturn bh; } -void buffer_insert_inode_queue (struct buffer_head *bh,struct inode *inode) +void buffer_insert_list (struct buffer_head *bh,struct list_head *list) {spin_lock (&lru_list_lock); -if (bh->b_inode) +if (buffer_attached (bh))list_del (&bh->b_inode_buffers); - bh->b_inode = inode; -list_add (&bh->b_inode_buffers, &inode->i_dirty_buffers); +set_buffer_attached (bh); +list_add (&bh->b_inode_buffers, list);spin_unlock (&lru_list_lock); } -void buffer_insert_inode_data_queue (struct buffer_head *bh,struct inode *inode) -{ -spin_lock (&lru_list_lock); -if (bh->b_inode) -list_del (&bh->b_inode_buffers); - bh->b_inode = inode; -list_add (&bh->b_inode_buffers, &inode->i_dirty_data_buffers); -spin_unlock (&lru_list_lock); -} - -/* The caller must have the lru_list lock before calling the -remove_inode_queue functions. */ +/* +* The caller must have the lru_list lock before calling the +* remove_inode_queue functions. +*/ static void __remove_inode_queue (struct buffer_head *bh) { - bh->b_inode =NULL ;list_del (&bh->b_inode_buffers); +clear_buffer_attached (bh); }static inline void remove_inode_queue (struct buffer_head *bh) { -if (bh->b_inode) +if (buffer_attached (bh))__remove_inode_queue (bh); }
@@ -827,10 +819,10 @@ inline void set_buffer_async_io(struct bint fsync_buffers_list (struct list_head *list) {struct buffer_head *bh; -struct inode tmp; +struct list_head tmp;int err =0 , err2; -INIT_LIST_HEAD (&tmp.i_dirty_buffers); +INIT_LIST_HEAD (&tmp);spin_lock (&lru_list_lock);
@@ -838,10 +830,10 @@ int fsync_buffers_list(struct list_head bh =BH_ENTRY (list->next);list_del (&bh->b_inode_buffers);if (!buffer_dirty (bh) && !buffer_locked (bh)) - bh->b_inode =NULL ; +clear_buffer_attached (bh);else { - bh->b_inode = &tmp; -list_add (&bh->b_inode_buffers, &tmp.i_dirty_buffers); +set_buffer_attached (bh); +list_add (&bh->b_inode_buffers, &tmp);if (buffer_dirty (bh)) {get_bh (bh);spin_unlock (&lru_list_lock);
@@ -861,8 +853,8 @@ int fsync_buffers_list(struct list_head } } -while (!list_empty (&tmp.i_dirty_buffers)) { - bh =BH_ENTRY (tmp.i_dirty_buffers.prev); +while (!list_empty (&tmp)) { + bh =BH_ENTRY (tmp.prev);remove_inode_queue (bh);get_bh (bh);spin_unlock (&lru_list_lock);
@@ -1134,7 +1126,7 @@ struct buffer_head * bread(kdev_t dev, i*/ static void __put_unused_buffer_head (struct buffer_head * bh) { -if (bh->b_inode) +if (unlikely (buffer_attached (bh)))BUG ();if (nr_unused_buffer_heads >=MAX_UNUSED_BUFFERS ) {kmem_cache_free (bh_cachep, bh);
fs/reiserfs/inode.c +2 -2
@@ -102,9 +102,9 @@ inline void make_le_item_head (struct it }static void add_to_flushlist (struct inode *inode,struct buffer_head *bh) { -struct inode *jinode = &(SB_JOURNAL (inode->i_sb)->j_dummy_inode) ; +struct reiserfs_journal *j =SB_JOURNAL (inode->i_sb) ; -buffer_insert_inode_queue (bh, jinode) ; +buffer_insert_list (bh, &j->j_dirty_buffers) ; }//
fs/reiserfs/journal.c +2 -2
@@ -1937,7 +1937,7 @@ int journal_init(struct super_block *p_smemset (journal_writers,0 ,sizeof (char *) *512 ) ;/* debug code */ INIT_LIST_HEAD (&SB_JOURNAL (p_s_sb)->j_bitmap_nodes) ; -INIT_LIST_HEAD (&(SB_JOURNAL (p_s_sb)->j_dummy_inode.i_dirty_buffers)) ; +INIT_LIST_HEAD (&SB_JOURNAL (p_s_sb)->j_dirty_buffers) ;reiserfs_allocate_list_bitmaps (p_s_sb,SB_JOURNAL (p_s_sb)->j_list_bitmap,SB_BMAP_NR (p_s_sb)) ;allocate_bitmap_nodes (p_s_sb) ;
@@ -2933,7 +2933,7 @@ printk("journal-2020: do_journal_end: BASB_JOURNAL_LIST_INDEX (p_s_sb) = jindex ;/* write any buffers that must hit disk before this commit is done */ -fsync_inode_buffers (&(SB_JOURNAL (p_s_sb)->j_dummy_inode)) ; +fsync_buffers_list (&(SB_JOURNAL (p_s_sb)->j_dirty_buffers)) ;/* honor the flush and async wishes from the caller */ if (flush) {
include/linux/fs.h +28 -3
@@ -219,6 +219,7 @@ enum bh_state_bits { BH_Async,/* 1 if the buffer is under end_buffer_io_async I/O */ BH_Wait_IO,/* 1 if we should write out this buffer */ BH_Launder,/* 1 if we can throttle on this buffer */ + BH_Attached,/* 1 if b_inode_buffers is linked into a list */ BH_JBD ,/* 1 if it has an attached journal_head */ BH_PrivateStart,/* not a state bit, but the first bit available
@@ -266,7 +267,6 @@ struct buffer_head {unsigned long b_rsector;/* Real buffer location on disk */ wait_queue_head_t b_wait; -struct inode * b_inode;struct list_head b_inode_buffers;/* doubly linked list of inode dirty buffers */ };
@@ -1167,8 +1167,18 @@ static inline void mark_buffer_clean(strextern void FASTCALL (__mark_dirty (struct buffer_head *bh));extern void FASTCALL (__mark_buffer_dirty (struct buffer_head *bh));extern void FASTCALL (mark_buffer_dirty (struct buffer_head *bh)); -extern void FASTCALL (buffer_insert_inode_queue (struct buffer_head *,struct inode *)); -extern void FASTCALL (buffer_insert_inode_data_queue (struct buffer_head *,struct inode *)); + +extern void FASTCALL (buffer_insert_list (struct buffer_head *,struct list_head *)); + +static inline void buffer_insert_inode_queue (struct buffer_head *bh,struct inode *inode) +{ +buffer_insert_list (bh, &inode->i_dirty_buffers); +} + +static inline void buffer_insert_inode_data_queue (struct buffer_head *bh,struct inode *inode) +{ +buffer_insert_list (bh, &inode->i_dirty_data_buffers); +}static inline int atomic_set_buffer_dirty (struct buffer_head *bh) {
@@ -1183,6 +1193,21 @@ static inline void mark_buffer_async(strclear_bit (BH_Async, &bh->b_state); } +static inline void set_buffer_attached (struct buffer_head *bh) +{ +__set_bit (BH_Attached, &bh->b_state); +} + +static inline void clear_buffer_attached (struct buffer_head *bh) +{ +clear_bit (BH_Attached, &bh->b_state); +} + +static inline int buffer_attached (struct buffer_head *bh) +{ +return test_bit (BH_Attached, &bh->b_state); +} +/* * If an error happens during the make_request, this function * has to be recalled. It marks the buffer as clean and not
include/linux/reiserfs_fs_sb.h +1 -1
@@ -312,7 +312,7 @@ struct reiserfs_journal {int j_free_bitmap_nodes ;int j_used_bitmap_nodes ;struct list_head j_bitmap_nodes ; -struct inode j_dummy_inode ; +struct list_head j_dirty_buffers ;struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS ] ;/* array of bitmaps to record the deleted blocks */ struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT ] ;/* array of all the journal lists */ struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE ] ;/* hash table for real buffer heads in current trans */
kernel/ksyms.c +1 -2
@@ -525,8 +527,7 @@ EXPORT_SYMBOL(get_hash_table);EXPORT_SYMBOL (get_empty_inode);EXPORT_SYMBOL (insert_inode_hash);EXPORT_SYMBOL (remove_inode_hash); -EXPORT_SYMBOL (buffer_insert_inode_queue); -EXPORT_SYMBOL (buffer_insert_inode_data_queue); +EXPORT_SYMBOL (buffer_insert_list);EXPORT_SYMBOL (make_bad_inode);EXPORT_SYMBOL (is_bad_inode);EXPORT_SYMBOL (event);