aboutsummaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2006-10-17 03:10:19 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-17 11:18:46 -0400
commit58ff407bee5a55f9c1188a3f9d70ffc79485183c (patch)
tree58132c31553a16b09e10f876561cd9ff1132fa77 /fs/buffer.c
parentd343fce148a4eee24a907a05c4101d3268045aae (diff)
[PATCH] Fix IO error reporting on fsync()
When IO error happens on metadata buffer, buffer is freed from memory and later fsync() is called, filesystems like ext2 fail to report EIO. We solve the problem by introducing a pointer to associated address space into the buffer_head. When a buffer is removed from a list of metadata buffers associated with an address space, IO error is transferred from the buffer to the address space, so that fsync can later report it. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index f65ef8821c73..35527dca1dbc 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -452,6 +452,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
452 bdevname(bh->b_bdev, b)); 452 bdevname(bh->b_bdev, b));
453 } 453 }
454 set_bit(AS_EIO, &page->mapping->flags); 454 set_bit(AS_EIO, &page->mapping->flags);
455 set_buffer_write_io_error(bh);
455 clear_buffer_uptodate(bh); 456 clear_buffer_uptodate(bh);
456 SetPageError(page); 457 SetPageError(page);
457 } 458 }
@@ -571,6 +572,10 @@ EXPORT_SYMBOL(mark_buffer_async_write);
571static inline void __remove_assoc_queue(struct buffer_head *bh) 572static inline void __remove_assoc_queue(struct buffer_head *bh)
572{ 573{
573 list_del_init(&bh->b_assoc_buffers); 574 list_del_init(&bh->b_assoc_buffers);
575 WARN_ON(!bh->b_assoc_map);
576 if (buffer_write_io_error(bh))
577 set_bit(AS_EIO, &bh->b_assoc_map->flags);
578 bh->b_assoc_map = NULL;
574} 579}
575 580
576int inode_has_buffers(struct inode *inode) 581int inode_has_buffers(struct inode *inode)
@@ -669,6 +674,7 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
669 spin_lock(&buffer_mapping->private_lock); 674 spin_lock(&buffer_mapping->private_lock);
670 list_move_tail(&bh->b_assoc_buffers, 675 list_move_tail(&bh->b_assoc_buffers,
671 &mapping->private_list); 676 &mapping->private_list);
677 bh->b_assoc_map = mapping;
672 spin_unlock(&buffer_mapping->private_lock); 678 spin_unlock(&buffer_mapping->private_lock);
673 } 679 }
674} 680}
@@ -765,7 +771,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
765 spin_lock(lock); 771 spin_lock(lock);
766 while (!list_empty(list)) { 772 while (!list_empty(list)) {
767 bh = BH_ENTRY(list->next); 773 bh = BH_ENTRY(list->next);
768 list_del_init(&bh->b_assoc_buffers); 774 __remove_assoc_queue(bh);
769 if (buffer_dirty(bh) || buffer_locked(bh)) { 775 if (buffer_dirty(bh) || buffer_locked(bh)) {
770 list_add(&bh->b_assoc_buffers, &tmp); 776 list_add(&bh->b_assoc_buffers, &tmp);
771 if (buffer_dirty(bh)) { 777 if (buffer_dirty(bh)) {
@@ -786,7 +792,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
786 792
787 while (!list_empty(&tmp)) { 793 while (!list_empty(&tmp)) {
788 bh = BH_ENTRY(tmp.prev); 794 bh = BH_ENTRY(tmp.prev);
789 __remove_assoc_queue(bh); 795 list_del_init(&bh->b_assoc_buffers);
790 get_bh(bh); 796 get_bh(bh);
791 spin_unlock(lock); 797 spin_unlock(lock);
792 wait_on_buffer(bh); 798 wait_on_buffer(bh);
@@ -1167,6 +1173,7 @@ void __bforget(struct buffer_head *bh)
1167 1173
1168 spin_lock(&buffer_mapping->private_lock); 1174 spin_lock(&buffer_mapping->private_lock);
1169 list_del_init(&bh->b_assoc_buffers); 1175 list_del_init(&bh->b_assoc_buffers);
1176 bh->b_assoc_map = NULL;
1170 spin_unlock(&buffer_mapping->private_lock); 1177 spin_unlock(&buffer_mapping->private_lock);
1171 } 1178 }
1172 __brelse(bh); 1179 __brelse(bh);