shutdown vop flags consistent with sync vop flags declarations too.
SGI-PV: 939911
SGI-Modid: xfs-linux-melb:xfs-kern:26096a
Signed-off-by: Nathan Scott <nathans@sgi.com>
 
        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);
 }
        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);
 }
         * 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);
        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;
 }
 
 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 */
 
 #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 *,
 
                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)
 
 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);
 
 
        if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id),
                           0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) {
-               xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE);
+               xfs_force_shutdown(dqp->q_mount, SHUTDOWN_CORRUPT_INCORE);
                return XFS_ERROR(EIO);
        }
 
 
                        if (!XFS_FORCED_SHUTDOWN(mp))
                                xfs_force_shutdown(mp,
                                                   (error == EFSCORRUPTED) ?
-                                                  XFS_CORRUPT_INCORE :
-                                                  XFS_METADATA_IO_ERROR);
+                                                  SHUTDOWN_CORRUPT_INCORE :
+                                                  SHUTDOWN_META_IO_ERROR);
                        return error;
                }
                xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock,
 
        XFS_BUF_ERROR(bp,0);
        xfs_buftrace("BUF_ERROR_RELSE", bp);
        if (! XFS_FORCED_SHUTDOWN(mp))
-               xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
        /*
         * We have to unpin the pinned buffers so do the
         * callbacks.
 
                struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev);
 
                if (sb && !IS_ERR(sb)) {
-                       xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
+                       xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
                        thaw_bdev(sb->s_bdev, sb);
                }
        
                break;
        }
        case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
-               xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
+               xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
                break;
        case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
-               xfs_force_shutdown(mp, XFS_FORCE_UMOUNT|XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp,
+                               SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
                break;
        default:
                return XFS_ERROR(EINVAL);
 
 
 corrupt_out:
        xfs_buf_relse(bp);
-       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
        xfs_iflush_abort(ip);
        /*
         * Unlocks the flush lock
                xfs_buf_relse(bp);
        }
 
-       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 
        if(!bufwasdelwri)  {
                /*
 
        xlog_in_core_t    *iclog = (xlog_in_core_t *)iclog_hndl;
 
        if (xlog_state_release_iclog(log, iclog)) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
                return EIO;
        }
 
                return XFS_ERROR(EIO);
 
        if ((error = xlog_write(mp, reg, nentries, tic, start_lsn, NULL, 0))) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
        }
        return error;
 }      /* xfs_log_write */
                        XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
                xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp));
                XFS_BUF_STALE(bp);
-               xfs_force_shutdown(l->l_mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(l->l_mp, SHUTDOWN_LOG_IO_ERROR);
                /*
                 * This flag will be propagated to the trans-committed
                 * callback routines to let them know that the log-commit
        ASSERT_ALWAYS(iclog);
        if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp,
                               iclog, XLOG_COMMIT_TRANS))) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
        }
        return error;
 }      /* xlog_commit_record */
        xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp,
                "xfs_log_write: reservation ran out. Need to up reservation");
        /* If we did not panic, shutdown the filesystem */
-       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
 #endif
     } else
        ticket->t_curr_res -= len;
 
                mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *);
                xfs_ioerror_alert("xlog_recover_iodone",
                                  mp, bp, XFS_BUF_ADDR(bp));
-               xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
        }
        XFS_BUF_SET_FSPRIVATE(bp, NULL);
        XFS_BUF_CLR_IODONE_FUNC(bp);
 
 #define xfs_force_shutdown(m,f)        \
        VFS_FORCE_SHUTDOWN((XFS_MTOVFS(m)), f, __FILE__, __LINE__)
 
-/*
- * Flags sent to xfs_force_shutdown.
- */
-#define XFS_METADATA_IO_ERROR  0x1
-#define XFS_LOG_IO_ERROR       0x2
-#define XFS_FORCE_UMOUNT       0x4
-#define XFS_CORRUPT_INCORE     0x8     /* Corrupt in-memory data structures */
-#define XFS_SHUTDOWN_REMOTE_REQ 0x10   /* Shutdown came from remote cell */
-
 /*
  * Flags for xfs_mountfs
  */
 
        xfs_mount_t     *mp;
 
        mp = XFS_BHVTOM(bdp);
-       logerror = flags & XFS_LOG_IO_ERROR;
+       logerror = flags & SHUTDOWN_LOG_IO_ERROR;
 
-       if (!(flags & XFS_FORCE_UMOUNT)) {
-               cmn_err(CE_NOTE,
-               "xfs_force_shutdown(%s,0x%x) called from line %d of file %s.  Return address = 0x%p",
-                       mp->m_fsname,flags,lnnum,fname,__return_address);
+       if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
+               cmn_err(CE_NOTE, "xfs_force_shutdown(%s,0x%x) called from "
+                                "line %d of file %s.  Return address = 0x%p",
+                       mp->m_fsname, flags, lnnum, fname, __return_address);
        }
        /*
         * No need to duplicate efforts.
        /*
         * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
         * queue up anybody new on the log reservations, and wakes up
-        * everybody who's sleeping on log reservations and tells
-        * them the bad news.
+        * everybody who's sleeping on log reservations to tell them
+        * the bad news.
         */
        if (xfs_log_force_umount(mp, logerror))
                return;
 
-       if (flags & XFS_CORRUPT_INCORE) {
+       if (flags & SHUTDOWN_CORRUPT_INCORE) {
                xfs_cmn_err(XFS_PTAG_SHUTDOWN_CORRUPT, CE_ALERT, mp,
     "Corruption of in-memory data detected.  Shutting down filesystem: %s",
                        mp->m_fsname);
                if (XFS_ERRLEVEL_HIGH <= xfs_error_level) {
                        xfs_stack_trace();
                }
-       } else if (!(flags & XFS_FORCE_UMOUNT)) {
+       } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
                if (logerror) {
                        xfs_cmn_err(XFS_PTAG_SHUTDOWN_LOGERROR, CE_ALERT, mp,
-                       "Log I/O Error Detected.  Shutting down filesystem: %s",
+               "Log I/O Error Detected.  Shutting down filesystem: %s",
                                mp->m_fsname);
-               } else if (!(flags & XFS_SHUTDOWN_REMOTE_REQ)) {
+               } else if (flags & SHUTDOWN_DEVICE_REQ) {
                        xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp,
-                               "I/O Error Detected.  Shutting down filesystem: %s",
+               "All device paths lost.  Shutting down filesystem: %s",
+                               mp->m_fsname);
+               } else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
+                       xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp,
+               "I/O Error Detected.  Shutting down filesystem: %s",
                                mp->m_fsname);
                }
        }
-       if (!(flags & XFS_FORCE_UMOUNT)) {
-               cmn_err(CE_ALERT,
-               "Please umount the filesystem, and rectify the problem(s)");
+       if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
+               cmn_err(CE_ALERT, "Please umount the filesystem, "
+                                 "and rectify the problem(s)");
        }
 }
 
                 * from bwrite and we could be tracing a buffer that has
                 * been reused.
                 */
-               xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
        }
        return (error);
 }
 
         */
        nvec = xfs_trans_count_vecs(tp);
        if (nvec == 0) {
-               xfs_force_shutdown(mp, XFS_LOG_IO_ERROR);
+               xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
                goto shut_us_down;
        } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
                log_vector = log_vector_fast;
         */
        if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) {
                XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp);
-               xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+               xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
        }
 #ifdef DEBUG
        if (!(flags & XFS_TRANS_ABORT)) {
 
                        AIL_UNLOCK(mp, s);
                else {
                        xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp,
-                               "xfs_trans_delete_ail: attempting to delete a log item that is not in the AIL");
+               "%s: attempting to delete a log item that is not in the AIL",
+                                       __FUNCTION__);
                        AIL_UNLOCK(mp, s);
-                       xfs_force_shutdown(mp, XFS_CORRUPT_INCORE);
+                       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
                }
        }
 }
 
                                 */
                                if (tp->t_flags & XFS_TRANS_DIRTY)
                                        xfs_force_shutdown(tp->t_mountp,
-                                                          XFS_METADATA_IO_ERROR);
+                                                       SHUTDOWN_META_IO_ERROR);
                                return error;
                        }
                }
                xfs_ioerror_alert("xfs_trans_read_buf", mp,
                                  bp, blkno);
                if (tp->t_flags & XFS_TRANS_DIRTY)
-                       xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR);
+                       xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR);
                xfs_buf_relse(bp);
                return error;
        }
                if (xfs_error_target == target) {
                        if (((xfs_req_num++) % xfs_error_mod) == 0) {
                                xfs_force_shutdown(tp->t_mountp,
-                                                  XFS_METADATA_IO_ERROR);
+                                                  SHUTDOWN_META_IO_ERROR);
                                xfs_buf_relse(bp);
                                printk("Returning error in trans!\n");
                                return XFS_ERROR(EIO);
 
                        cmn_err(CE_NOTE,
                "xfs_inactive:  xfs_ifree() returned an error = %d on %s",
                                error, mp->m_fsname);
-                       xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR);
+                       xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
                }
                xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
        } else {