diff options
-rw-r--r-- | sys/dev/ccd/ccd.c | 48 | ||||
-rw-r--r-- | sys/geom/geom_ccd.c | 48 |
2 files changed, 78 insertions, 18 deletions
diff --git a/sys/dev/ccd/ccd.c b/sys/dev/ccd/ccd.c index dab208c..1601e89 100644 --- a/sys/dev/ccd/ccd.c +++ b/sys/dev/ccd/ccd.c @@ -1,4 +1,4 @@ -/* $Id: ccd.c,v 1.7 1996/01/31 11:25:46 asami Exp $ */ +/* $Id: ccd.c,v 1.8 1996/03/21 04:13:25 asami Exp $ */ /* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */ @@ -136,13 +136,32 @@ int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | CCDB_VNODE; #define ccdunit(x) dkunit(x) #define ccdpart(x) dkpart(x) +/* + This is how mirroring works (only writes are special): + + When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s + linked together by the cb_mirror field. "cb_pflags & + CCDPF_MIRROR_DONE" is set to 0 on both of them. + + When a component returns to ccdiodone(), it checks if "cb_pflags & + CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's + flag and returns. If it is, it means its partner has already + returned, so it will go to the regular cleanup. + + */ + struct ccdbuf { struct buf cb_buf; /* new I/O buf */ struct buf *cb_obp; /* ptr. to original I/O buf */ int cb_unit; /* target unit */ int cb_comp; /* target component */ + int cb_pflags; /* mirror/parity status flag */ + struct ccdbuf *cb_mirror; /* mirror counterpart */ }; +/* bits in cb_pflags */ +#define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */ + #define getccdbuf() \ ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) #define putccdbuf(cbp) \ @@ -703,10 +722,7 @@ ccdstrategy(bp) if (bounds_check_with_label(bp, lp, wlabel) <= 0) goto done; - if (cs->sc_cflags & CCDF_MIRROR && (bp->b_flags & B_READ) == 0) - bp->b_resid = bp->b_bcount*2; - else - bp->b_resid = bp->b_bcount; + bp->b_resid = bp->b_bcount; /* * "Start" the unit. @@ -896,6 +912,11 @@ ccdbuffer(cb, cs, bp, bn, addr, bcount) cbp->cb_buf.b_vp = ci2->ci_vp; cbp->cb_comp = ci2 - cs->sc_cinfo; cb[1] = cbp; + /* link together the ccdbuf's and clear "mirror done" flag */ + cb[0]->cb_mirror = cb[1]; + cb[1]->cb_mirror = cb[0]; + cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; + cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; } } @@ -923,10 +944,7 @@ ccdintr(cs, bp) dk_busy &= ~(1 << cs->sc_dk); #endif if (bp->b_flags & B_ERROR) - if (cs->sc_cflags & CCDF_MIRROR && (bp->b_flags & B_READ) == 0) - bp->b_resid = bp->b_bcount*2; - else - bp->b_resid = bp->b_bcount; + bp->b_resid = bp->b_bcount; biodone(bp); } @@ -965,6 +983,18 @@ ccdiodone(cbp) unit, bp->b_error, cbp->cb_comp); #endif } + + if (ccd_softc[unit].sc_cflags & CCDF_MIRROR && + (cbp->cb_buf.b_flags & B_READ) == 0) + if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { + /* I'm done before my counterpart, so just set + partner's flag and return */ + cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; + putccdbuf(cbp); + splx(s); + return; + } + count = cbp->cb_buf.b_bcount; putccdbuf(cbp); diff --git a/sys/geom/geom_ccd.c b/sys/geom/geom_ccd.c index dab208c..1601e89 100644 --- a/sys/geom/geom_ccd.c +++ b/sys/geom/geom_ccd.c @@ -1,4 +1,4 @@ -/* $Id: ccd.c,v 1.7 1996/01/31 11:25:46 asami Exp $ */ +/* $Id: ccd.c,v 1.8 1996/03/21 04:13:25 asami Exp $ */ /* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */ @@ -136,13 +136,32 @@ int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | CCDB_VNODE; #define ccdunit(x) dkunit(x) #define ccdpart(x) dkpart(x) +/* + This is how mirroring works (only writes are special): + + When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s + linked together by the cb_mirror field. "cb_pflags & + CCDPF_MIRROR_DONE" is set to 0 on both of them. + + When a component returns to ccdiodone(), it checks if "cb_pflags & + CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's + flag and returns. If it is, it means its partner has already + returned, so it will go to the regular cleanup. + + */ + struct ccdbuf { struct buf cb_buf; /* new I/O buf */ struct buf *cb_obp; /* ptr. to original I/O buf */ int cb_unit; /* target unit */ int cb_comp; /* target component */ + int cb_pflags; /* mirror/parity status flag */ + struct ccdbuf *cb_mirror; /* mirror counterpart */ }; +/* bits in cb_pflags */ +#define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */ + #define getccdbuf() \ ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) #define putccdbuf(cbp) \ @@ -703,10 +722,7 @@ ccdstrategy(bp) if (bounds_check_with_label(bp, lp, wlabel) <= 0) goto done; - if (cs->sc_cflags & CCDF_MIRROR && (bp->b_flags & B_READ) == 0) - bp->b_resid = bp->b_bcount*2; - else - bp->b_resid = bp->b_bcount; + bp->b_resid = bp->b_bcount; /* * "Start" the unit. @@ -896,6 +912,11 @@ ccdbuffer(cb, cs, bp, bn, addr, bcount) cbp->cb_buf.b_vp = ci2->ci_vp; cbp->cb_comp = ci2 - cs->sc_cinfo; cb[1] = cbp; + /* link together the ccdbuf's and clear "mirror done" flag */ + cb[0]->cb_mirror = cb[1]; + cb[1]->cb_mirror = cb[0]; + cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE; + cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE; } } @@ -923,10 +944,7 @@ ccdintr(cs, bp) dk_busy &= ~(1 << cs->sc_dk); #endif if (bp->b_flags & B_ERROR) - if (cs->sc_cflags & CCDF_MIRROR && (bp->b_flags & B_READ) == 0) - bp->b_resid = bp->b_bcount*2; - else - bp->b_resid = bp->b_bcount; + bp->b_resid = bp->b_bcount; biodone(bp); } @@ -965,6 +983,18 @@ ccdiodone(cbp) unit, bp->b_error, cbp->cb_comp); #endif } + + if (ccd_softc[unit].sc_cflags & CCDF_MIRROR && + (cbp->cb_buf.b_flags & B_READ) == 0) + if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) { + /* I'm done before my counterpart, so just set + partner's flag and return */ + cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE; + putccdbuf(cbp); + splx(s); + return; + } + count = cbp->cb_buf.b_bcount; putccdbuf(cbp); |