When a read or write operation fails on a sector found on the bad block table,
authormiod <miod@openbsd.org>
Wed, 14 Jan 2015 21:17:09 +0000 (21:17 +0000)
committermiod <miod@openbsd.org>
Wed, 14 Jan 2015 21:17:09 +0000 (21:17 +0000)
be sure to adjust the IOPB data pointer before redirecting the I/O for this
particular sector to the replacement location.

Otherwise, the data pointer still points to the first sector of the I/O, which
may not necessarily be the one which failed.

(This is yet another 19 years old bug, making your filesystems self-destruct
even faster than intended)

sys/arch/sparc/dev/xd.c
sys/arch/sparc/dev/xy.c

index 8d1c119..3ec02b0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: xd.c,v 1.68 2015/01/14 21:14:49 miod Exp $    */
+/*     $OpenBSD: xd.c,v 1.69 2015/01/14 21:17:09 miod Exp $    */
 /*     $NetBSD: xd.c,v 1.37 1997/07/29 09:58:16 fair Exp $     */
 
 /*
@@ -1985,6 +1985,7 @@ xdc_error(xdcsc, iorq, iopb, rqno, comm)
                                                                 * standard */
                        iopb->headno = i % iorq->xd->nhead;
                        iopb->sectno = i / iorq->xd->nhead;
+                       iopb->daddr = (u_long) iorq->dbuf - DVMA_BASE;
                        XDC_HWAIT(xdcsc, rqno);
                        xdc_start(xdcsc, 1);    /* resubmit */
                        return (XD_ERR_AOK);    /* recovered! */
index e776a59..e930135 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: xy.c,v 1.65 2015/01/14 21:14:49 miod Exp $    */
+/*     $OpenBSD: xy.c,v 1.66 2015/01/14 21:17:09 miod Exp $    */
 /*     $NetBSD: xy.c,v 1.26 1997/07/19 21:43:56 pk Exp $       */
 
 /*
@@ -1825,6 +1825,7 @@ xyc_error(xycsc, iorq, iopb, comm)
        int     errno = iorq->errno;
        int     erract = xyc_entoact(errno);
        int     oldmode, advance, i;
+       u_long  addr;
 
        if (erract == XY_ERA_RSET) {    /* some errors require a reset */
                oldmode = iorq->mode;
@@ -1853,6 +1854,11 @@ xyc_error(xycsc, iorq, iopb, comm)
                                                                 * standard */
                        iopb->head = i % iorq->xy->nhead;
                        iopb->sect = i / iorq->xy->nhead;
+
+                       addr = (u_long) iorq->dbuf - DVMA_BASE;
+                       iopb->dataa = (addr & 0xffff);
+                       iopb->datar = ((addr & 0xff0000) >> 16);
+
                        /* will resubmit when we come out of remove_iorq */
                        return (XY_ERR_AOK);    /* recovered! */
                }