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 introdusing a pointer to associated address space to buffer_head.
When 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 <[email protected]>
diff -rupX /home/jack/.kerndiffexclude linux-2.6.18-1-mark_error_buffer/fs/buffer.c linux-2.6.18-2-fsync_bh_fix/fs/buffer.c
--- linux-2.6.18-1-mark_error_buffer/fs/buffer.c 2006-10-06 13:05:29.000000000 +0200
+++ linux-2.6.18-2-fsync_bh_fix/fs/buffer.c 2006-10-10 17:00:04.000000000 +0200
@@ -709,6 +709,10 @@ EXPORT_SYMBOL(mark_buffer_async_write);
static inline void __remove_assoc_queue(struct buffer_head *bh)
{
list_del_init(&bh->b_assoc_buffers);
+ WARN_ON(!bh->b_assoc_map);
+ if (buffer_write_io_error(bh))
+ set_bit(AS_EIO, &bh->b_assoc_map->flags);
+ bh->b_assoc_map = NULL;
}
int inode_has_buffers(struct inode *inode)
@@ -807,6 +811,7 @@ void mark_buffer_dirty_inode(struct buff
spin_lock(&buffer_mapping->private_lock);
list_move_tail(&bh->b_assoc_buffers,
&mapping->private_list);
+ bh->b_assoc_map = mapping;
spin_unlock(&buffer_mapping->private_lock);
}
}
@@ -900,7 +905,7 @@ static int fsync_buffers_list(spinlock_t
spin_lock(lock);
while (!list_empty(list)) {
bh = BH_ENTRY(list->next);
- list_del_init(&bh->b_assoc_buffers);
+ __remove_assoc_queue(bh);
if (buffer_dirty(bh) || buffer_locked(bh)) {
list_add(&bh->b_assoc_buffers, &tmp);
if (buffer_dirty(bh)) {
@@ -921,7 +926,7 @@ static int fsync_buffers_list(spinlock_t
while (!list_empty(&tmp)) {
bh = BH_ENTRY(tmp.prev);
- __remove_assoc_queue(bh);
+ list_del_init(&bh->b_assoc_buffers);
get_bh(bh);
spin_unlock(lock);
wait_on_buffer(bh);
@@ -1285,6 +1290,7 @@ void __bforget(struct buffer_head *bh)
spin_lock(&buffer_mapping->private_lock);
list_del_init(&bh->b_assoc_buffers);
+ bh->b_assoc_map = NULL;
spin_unlock(&buffer_mapping->private_lock);
}
__brelse(bh);
diff -rupX /home/jack/.kerndiffexclude linux-2.6.18-1-mark_error_buffer/include/linux/buffer_head.h linux-2.6.18-2-fsync_bh_fix/include/linux/buffer_head.h
--- linux-2.6.18-1-mark_error_buffer/include/linux/buffer_head.h 2006-09-27 13:09:04.000000000 +0200
+++ linux-2.6.18-2-fsync_bh_fix/include/linux/buffer_head.h 2006-10-10 15:37:46.000000000 +0200
@@ -67,6 +67,8 @@ struct buffer_head {
bh_end_io_t *b_end_io; /* I/O completion */
void *b_private; /* reserved for b_end_io */
struct list_head b_assoc_buffers; /* associated with another mapping */
+ struct address_space *b_assoc_map; /* mapping this buffer is
+ associated with */
atomic_t b_count; /* users using this buffer_head */
};
--
Jan Kara <[email protected]>
SuSE CR Labs
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]