diff options
Diffstat (limited to 'fs/xfs/linux-2.6')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 15 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.h | 2 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_vfs.h | 7 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_vnode.c | 16 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_vnode.h | 2 |
5 files changed, 33 insertions, 9 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 4d191ef39b67..1fcdc0abda6e 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -136,9 +136,10 @@ xfs_destroy_ioend( for (bh = ioend->io_buffer_head; bh; bh = next) { next = bh->b_private; - bh->b_end_io(bh, ioend->io_uptodate); + bh->b_end_io(bh, !ioend->io_error); } - + if (unlikely(ioend->io_error)) + vn_ioerror(ioend->io_vnode, ioend->io_error, __FILE__,__LINE__); vn_iowake(ioend->io_vnode); mempool_free(ioend, xfs_ioend_pool); } @@ -185,7 +186,7 @@ xfs_end_bio_unwritten( size_t size = ioend->io_size; int error; - if (ioend->io_uptodate) + if (likely(!ioend->io_error)) VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error); xfs_destroy_ioend(ioend); } @@ -211,7 +212,7 @@ xfs_alloc_ioend( * all the I/O from calling the completion routine too early. */ atomic_set(&ioend->io_remaining, 1); - ioend->io_uptodate = 1; /* cleared if any I/O fails */ + ioend->io_error = 0; ioend->io_list = NULL; ioend->io_type = type; ioend->io_vnode = vn_from_inode(inode); @@ -271,16 +272,14 @@ xfs_end_bio( if (bio->bi_size) return 1; - ASSERT(ioend); ASSERT(atomic_read(&bio->bi_cnt) >= 1); + ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; /* Toss bio and pass work off to an xfsdatad thread */ - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - ioend->io_uptodate = 0; bio->bi_private = NULL; bio->bi_end_io = NULL; - bio_put(bio); + xfs_finish_ioend(ioend); return 0; } diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h index 60716543c68b..41c7d2da638a 100644 --- a/fs/xfs/linux-2.6/xfs_aops.h +++ b/fs/xfs/linux-2.6/xfs_aops.h @@ -30,7 +30,7 @@ typedef void (*xfs_ioend_func_t)(void *); typedef struct xfs_ioend { struct xfs_ioend *io_list; /* next ioend in chain */ unsigned int io_type; /* delalloc / unwritten */ - unsigned int io_uptodate; /* I/O status register */ + int io_error; /* I/O error code */ atomic_t io_remaining; /* hold count */ struct vnode *io_vnode; /* file being written to */ struct buffer_head *io_buffer_head;/* buffer linked list head */ diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h index 841200c03092..2ca05043a0fd 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.h +++ b/fs/xfs/linux-2.6/xfs_vfs.h @@ -94,6 +94,13 @@ typedef enum { #define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ #define SYNC_QUIESCE 0x0100 /* quiesce filesystem for a snapshot */ +#define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */ +#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ +#define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */ +#define SHUTDOWN_CORRUPT_INCORE 0x0008 /* corrupt in-memory data structures */ +#define SHUTDOWN_REMOTE_REQ 0x0010 /* shutdown came from remote cell */ +#define SHUTDOWN_DEVICE_REQ 0x0020 /* failed all paths to the device */ + typedef int (*vfs_mount_t)(bhv_desc_t *, struct xfs_mount_args *, struct cred *); typedef int (*vfs_parseargs_t)(bhv_desc_t *, char *, diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index d27c25b27ccd..f17e39cff230 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -54,6 +54,22 @@ vn_iowake( wake_up(vptosync(vp)); } +/* + * Volume managers supporting multiple paths can send back ENODEV when the + * final path disappears. In this case continuing to fill the page cache + * with dirty data which cannot be written out is evil, so prevent that. + */ +void +vn_ioerror( + struct vnode *vp, + int error, + char *f, + int l) +{ + if (unlikely(error == -ENODEV)) + VFS_FORCE_SHUTDOWN(vp->v_vfsp, SHUTDOWN_DEVICE_REQ, f, l); +} + struct vnode * vn_initialize( struct inode *inode) diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 2a8e16c22353..a64b7db67003 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -514,6 +514,8 @@ extern void vn_revalidate_core(struct vnode *, vattr_t *); extern void vn_iowait(struct vnode *vp); extern void vn_iowake(struct vnode *vp); +extern void vn_ioerror(struct vnode *vp, int error, char *f, int l); + static inline int vn_count(struct vnode *vp) { return atomic_read(&vn_to_inode(vp)->i_count); |