Propagate write errors to userspace
Subsystems (6)
PATCH 1/1 Propagate write errors to userspace
Andrew, this is my write error propagation patch updated to 2.5.60-mm1. Please add this to your collection.
fs/buffer.c +30 -10
@@ -164,15 +164,27 @@* Default synchronous end-of-IO handler.. Just mark it up-to-date and * unlock the buffer. This is what ll_rw_block uses too. */ -void end_buffer_io_sync (struct buffer_head *bh,int uptodate) +void end_buffer_read_sync (struct buffer_head *bh,int uptodate) {if (uptodate) {set_buffer_uptodate (bh); }else { -/* -* This happens, due to failed READA attempts. -* buffer_io_error(bh); -*/ +/* This happens, due to failed READA attempts. */ +clear_buffer_uptodate (bh); + } +unlock_buffer (bh); +put_bh (bh); +} + +void end_buffer_write_sync (struct buffer_head *bh,int uptodate) +{ +if (uptodate) { +set_buffer_uptodate (bh); + }else { +buffer_io_error (bh); +printk (KERN_WARNING "lost page write due to I/O error on %s\n" , +bdevname (bh->b_bdev)); +set_buffer_write_io_error (bh);clear_buffer_uptodate (bh); }unlock_buffer (bh);
@@ -549,6 +561,9 @@set_buffer_uptodate (bh); }else {buffer_io_error (bh); +printk (KERN_WARNING "lost page write due to I/O error on %s\n" , +bdevname (bh->b_bdev)); + page->mapping->error = -EIO ;clear_buffer_uptodate (bh);SetPageError (page); }
@@ -1200,7 +1215,7 @@if (buffer_dirty (bh))buffer_error ();get_bh (bh); - bh->b_end_io = end_buffer_io_sync; + bh->b_end_io = end_buffer_read_sync;submit_bh (READ , bh);wait_on_buffer (bh);if (buffer_uptodate (bh))
@@ -2542,8 +2557,10 @@buffer_error ();if (rw ==READ &&buffer_dirty (bh))buffer_error (); - -set_buffer_req (bh); + +/* Only clear out a write error when rewriting */ +if (test_set_buffer_req (bh) && rw ==WRITE ) +clear_buffer_write_io_error (bh);/* * from here on down, it's all bio -- do the initial mapping,
@@ -2603,13 +2620,14 @@continue ;get_bh (bh); - bh->b_end_io = end_buffer_io_sync;if (rw ==WRITE ) { + bh->b_end_io = end_buffer_write_sync;if (test_clear_buffer_dirty (bh)) {submit_bh (WRITE , bh);continue ; } }else { + bh->b_end_io = end_buffer_read_sync;if (!buffer_uptodate (bh)) {submit_bh (rw, bh);continue ;
@@ -2630,7 +2648,7 @@lock_buffer (bh);if (test_clear_buffer_dirty (bh)) {get_bh (bh); - bh->b_end_io = end_buffer_io_sync; + bh->b_end_io = end_buffer_write_sync;submit_bh (WRITE , bh);wait_on_buffer (bh); }else {
@@ -2689,6 +2707,8 @@ bh = head; do { check_ttfb_buffer(page, bh); + if (buffer_write_io_error(bh)) + page->mapping->error = -EIO; if (buffer_busy(bh)) goto failed; if (!buffer_uptodate(bh) && !buffer_req(bh))
fs/inode.c +1 -0
@@ -134,6 +134,7 @@ mapping->dirtied_when =0 ; mapping->assoc_mapping =NULL ; mapping->backing_dev_info = &default_backing_dev_info; + mapping->error =0 ;if (sb->s_bdev) inode->i_data.backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;memset (&inode->u,0 ,sizeof (inode->u));
fs/mpage.c +4 -0
@@ -562,6 +562,8 @@if (bio) bio =mpage_bio_submit (WRITE , bio); *ret = page->mapping->a_ops->writepage (page, wbc); +if (*ret <0 ) + page->mapping->error = *ret; out:return bio; }
@@ -665,6 +667,8 @@ test_clear_page_dirty(page)) {if (writepage) { ret = (*writepage)(page, wbc); +if (ret <0 ) + page->mapping->error = ret; }else { bio =mpage_writepage (bio, page, get_block, &last_block_in_bio, &ret, wbc);
fs/ntfs/compress.c +1 -1
@@ -598,7 +598,7 @@continue ; }atomic_inc (&tbh->b_count); - tbh->b_end_io = end_buffer_io_sync; + tbh->b_end_io = end_buffer_read_sync;submit_bh (READ , tbh); }
fs/open.c +21 -4
@@ -843,21 +843,38 @@*/ int filp_close (struct file *filp,fl_owner_t id) { -int retval; +struct address_space *mapping = filp->f_dentry->d_inode->i_mapping; +int retval =0 , err; + +/* Report and clear outstanding errors */ + err = filp->f_error; +if (err) { + filp->f_error =0 ; + retval = err; + } + + err = mapping->error; +if (err && !retval) { + mapping->error =0 ; + retval = err; + }if (!file_count (filp)) {printk (KERN_ERR "VFS: Close: file count is 0\n" ); -return 0 ; +return retval; } - retval =0 ; +if (filp->f_op && filp->f_op->flush) {lock_kernel (); - retval = filp->f_op->flush (filp); + err = filp->f_op->flush (filp);unlock_kernel (); +if (err && !retval) + retval = err; }dnotify_flush (filp, id);locks_remove_posix (filp, id);fput (filp); +return retval; }
include/linux/buffer_head.h +7 -3
@@ -24,8 +24,9 @@ BH_Async_Read,/* Is under end_buffer_async_read I/O */ BH_Async_Write,/* Is under end_buffer_async_write I/O */ BH_Delay,/* Buffer is not yet allocated on disk */ - BH_Boundary,/* Block is followed by a discontiguity */ + BH_Write_EIO,/* I/O error on write */ + BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities */
@@ -103,12 +104,14 @@ BUFFER_FNS(Lock, locked) TAS_BUFFER_FNS(Lock, locked) BUFFER_FNS(Req, req) +TAS_BUFFER_FNS(Req, req) BUFFER_FNS(Mapped, mapped) BUFFER_FNS(New, new) BUFFER_FNS(Async_Read, async_read) BUFFER_FNS(Async_Write, async_write) -BUFFER_FNS (Delay, delay); +BUFFER_FNS(Delay, delay) BUFFER_FNS(Boundary, boundary) +BUFFER_FNS(Write_EIO,write_io_error)#define bh_offset (bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK)#define touch_buffer (bh) mark_page_accessed(bh->b_page)
@@ -136,7 +139,8 @@int try_to_free_buffers (struct page *);void create_empty_buffers (struct page *,unsigned long ,unsigned long b_state); -void end_buffer_io_sync (struct buffer_head *bh,int uptodate); +void end_buffer_read_sync (struct buffer_head *bh,int uptodate); +void end_buffer_write_sync (struct buffer_head *bh,int uptodate);/* Things to do with buffers at mapping->private_list */ void buffer_insert_list(spinlock_t *lock,
include/linux/fs.h +1 -0
@@ -326,6 +326,7 @@spinlock_t private_lock;/* for use by the address_space */ struct list_head private_list;/* ditto */ struct address_space *assoc_mapping;/* ditto */ +int error;/* write error for fsync */ };struct char_device {
kernel/ksyms.c +2 -1
@@ -170,7 +170,8 @@EXPORT_SYMBOL (d_lookup);EXPORT_SYMBOL (d_path);EXPORT_SYMBOL (mark_buffer_dirty); -EXPORT_SYMBOL (end_buffer_io_sync); +EXPORT_SYMBOL (end_buffer_read_sync); +EXPORT_SYMBOL (end_buffer_write_sync);EXPORT_SYMBOL (__mark_inode_dirty);EXPORT_SYMBOL (get_empty_filp);EXPORT_SYMBOL (init_private_file);
mm/filemap.c +8 -0
@@ -185,6 +185,14 @@write_lock (&mapping->page_lock); }write_unlock (&mapping->page_lock); + +/* Check for outstanding write errors */ +if (mapping->error) + { + ret = mapping->error; + mapping->error =0 ; + } +return ret; }
mm/vmscan.c +3 -0
@@ -342,6 +342,9 @@SetPageReclaim (page); res = mapping->a_ops->writepage (page, &wbc); +if (res <0 ) { + mapping->error = res; + }if (res ==WRITEPAGE_ACTIVATE ) {ClearPageReclaim (page); goto activate_locked;
Signature · 1 line
"Love the dolphins," she advised him. "Write by W.A.S.T.E.."