📄 ccd.c
字号:
/* * Allocate an interleave table. * Chances are this is too big, but we don't care. */ size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); bzero((caddr_t)cs->sc_itable, size); /* * Trivial case: no interleave (actually interleave of disk size). * Each table entry represents a single component in its entirety. */ if (cs->sc_ileave == 0) { bn = 0; ii = cs->sc_itable; for (ix = 0; ix < cs->sc_nccdisks; ix++) { /* Allocate space for ii_index. */ ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK); ii->ii_ndisk = 1; ii->ii_startblk = bn; ii->ii_startoff = 0; ii->ii_index[0] = ix; bn += cs->sc_cinfo[ix].ci_size; ii++; } ii->ii_ndisk = 0;#ifdef DEBUG if (ccddebug & CCDB_INIT) printiinfo(cs->sc_itable);#endif return; } /* * The following isn't fast or pretty; it doesn't have to be. */ size = 0; bn = lbn = 0; for (ii = cs->sc_itable; ; ii++) { /* Allocate space for ii_index. */ ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), M_DEVBUF, M_WAITOK); /* * Locate the smallest of the remaining components */ smallci = NULL; for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) if (ci->ci_size > size && (smallci == NULL || ci->ci_size < smallci->ci_size)) smallci = ci; /* * Nobody left, all done */ if (smallci == NULL) { ii->ii_ndisk = 0; break; } /* * Record starting logical block and component offset */ ii->ii_startblk = bn / cs->sc_ileave; ii->ii_startoff = lbn; /* * Determine how many disks take part in this interleave * and record their indices. */ ix = 0; for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) if (ci->ci_size >= smallci->ci_size) ii->ii_index[ix++] = ci - cs->sc_cinfo; ii->ii_ndisk = ix; bn += ix * (smallci->ci_size - size); lbn = smallci->ci_size / cs->sc_ileave; size = smallci->ci_size; }#ifdef DEBUG if (ccddebug & CCDB_INIT) printiinfo(cs->sc_itable);#endif}/* ARGSUSED */static intccdopen(dev, flags, fmt, p) dev_t dev; int flags, fmt; struct proc *p;{ int unit = ccdunit(dev); struct ccd_softc *cs; struct disklabel *lp; int error = 0, part, pmask;#ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdopen(%x, %x)\n", dev, flags);#endif if (unit >= numccd) return (ENXIO); cs = &ccd_softc[unit]; if (error = ccdlock(cs)) return (error); lp = &cs->sc_dkdev.dk_label; part = ccdpart(dev); pmask = (1 << part); /* * If we're initialized, check to see if there are any other * open partitions. If not, then it's safe to update * the in-core disklabel. */ if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0)) ccdgetdisklabel(dev); /* Check that the partition exists. */ if (part != RAW_PART && ((part >= lp->d_npartitions) || (lp->d_partitions[part].p_fstype == FS_UNUSED))) { error = ENXIO; goto done; } /* Prevent our unit from being unconfigured while open. */ switch (fmt) { case S_IFCHR: cs->sc_dkdev.dk_copenmask |= pmask; break; case S_IFBLK: cs->sc_dkdev.dk_bopenmask |= pmask; break; } cs->sc_dkdev.dk_openmask = cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; done: ccdunlock(cs); return (0);}/* ARGSUSED */static intccdclose(dev, flags, fmt, p) dev_t dev; int flags, fmt; struct proc *p;{ int unit = ccdunit(dev); struct ccd_softc *cs; int error = 0, part;#ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdclose(%x, %x)\n", dev, flags);#endif if (unit >= numccd) return (ENXIO); cs = &ccd_softc[unit]; if (error = ccdlock(cs)) return (error); part = ccdpart(dev); /* ...that much closer to allowing unconfiguration... */ switch (fmt) { case S_IFCHR: cs->sc_dkdev.dk_copenmask &= ~(1 << part); break; case S_IFBLK: cs->sc_dkdev.dk_bopenmask &= ~(1 << part); break; } cs->sc_dkdev.dk_openmask = cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; ccdunlock(cs); return (0);}static intccdread(dev_t dev, struct uio *uio, int ioflag){ return (physio(ccdstrategy, NULL, dev, 1, minphys, uio));}static intccdwrite(dev_t dev, struct uio *uio, int ioflag){ return (physio(ccdstrategy, NULL, dev, 0, minphys, uio));}static voidccdstrategy(bp) register struct buf *bp;{ register int unit = ccdunit(bp->b_dev); register struct ccd_softc *cs = &ccd_softc[unit]; register int s; int wlabel; struct disklabel *lp;#ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdstrategy(%x): unit %d\n", bp, unit);#endif if ((cs->sc_flags & CCDF_INITED) == 0) { bp->b_error = ENXIO; bp->b_flags |= B_ERROR; goto done; } /* If it's a nil transfer, wake up the top half now. */ if (bp->b_bcount == 0) goto done; lp = &cs->sc_dkdev.dk_label; /* * Do bounds checking and adjust transfer. If there's an * error, the bounds check will flag that for us. */ wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); if (ccdpart(bp->b_dev) != RAW_PART) if (bounds_check_with_label(bp, lp, wlabel) <= 0) goto done; bp->b_resid = bp->b_bcount; /* * "Start" the unit. */ s = splbio(); ccdstart(cs, bp); splx(s); return;done: biodone(bp);}static voidccdstart(cs, bp) register struct ccd_softc *cs; register struct buf *bp;{ register long bcount, rcount; struct ccdbuf *cbp[4]; /* XXX! : 2 reads and 2 writes for RAID 4/5 */ caddr_t addr; daddr_t bn; struct partition *pp;#ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdstart(%x, %x)\n", cs, bp);#endif /* Record the transaction start */ devstat_start_transaction(&cs->device_stats); /* * Translate the partition-relative block number to an absolute. */ bn = bp->b_blkno; if (ccdpart(bp->b_dev) != RAW_PART) { pp = &cs->sc_dkdev.dk_label.d_partitions[ccdpart(bp->b_dev)]; bn += pp->p_offset; } /* * Allocate component buffers and fire off the requests */ addr = bp->b_data; for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { ccdbuffer(cbp, cs, bp, bn, addr, bcount); rcount = cbp[0]->cb_buf.b_bcount; if ((cbp[0]->cb_buf.b_flags & B_READ) == 0) cbp[0]->cb_buf.b_vp->v_numoutput++; VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf); if (cs->sc_cflags & CCDF_MIRROR && (cbp[0]->cb_buf.b_flags & B_READ) == 0) { /* mirror, start another write */ cbp[1]->cb_buf.b_vp->v_numoutput++; VOP_STRATEGY(cbp[1]->cb_buf.b_vp, &cbp[1]->cb_buf); } bn += btodb(rcount); addr += rcount; }}/* * Build a component buffer header. */static voidccdbuffer(cb, cs, bp, bn, addr, bcount) register struct ccdbuf **cb; register struct ccd_softc *cs; struct buf *bp; daddr_t bn; caddr_t addr; long bcount;{ register struct ccdcinfo *ci, *ci2 = NULL; /* XXX */ register struct ccdbuf *cbp; register daddr_t cbn, cboff; register off_t cbc;#ifdef DEBUG if (ccddebug & CCDB_IO) printf("ccdbuffer(%x, %x, %d, %x, %d)\n", cs, bp, bn, addr, bcount);#endif /* * Determine which component bn falls in. */ cbn = bn; cboff = 0; /* * Serially concatenated */ if (cs->sc_ileave == 0) { register daddr_t sblk; sblk = 0; for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) sblk += ci->ci_size; cbn -= sblk; } /* * Interleaved */ else { register struct ccdiinfo *ii; int ccdisk, off; cboff = cbn % cs->sc_ileave; cbn /= cs->sc_ileave; for (ii = cs->sc_itable; ii->ii_ndisk; ii++) if (ii->ii_startblk > cbn) break; ii--; off = cbn - ii->ii_startblk; if (ii->ii_ndisk == 1) { ccdisk = ii->ii_index[0]; cbn = ii->ii_startoff + off; } else { if (cs->sc_cflags & CCDF_MIRROR) { ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)]; cbn = ii->ii_startoff + off / (ii->ii_ndisk/2); /* mirrored data */ ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2]; } else if (cs->sc_cflags & CCDF_PARITY) { ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)]; cbn = ii->ii_startoff + off / (ii->ii_ndisk-1); if (cbn % ii->ii_ndisk <= ccdisk) ccdisk++; } else { ccdisk = ii->ii_index[off % ii->ii_ndisk]; cbn = ii->ii_startoff + off / ii->ii_ndisk; } } cbn *= cs->sc_ileave; ci = &cs->sc_cinfo[ccdisk]; } /* * Fill in the component buf structure. */ cbp = getccdbuf(); bzero(cbp, sizeof (struct ccdbuf)); cbp->cb_buf.b_flags = bp->b_flags | B_CALL; cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone; cbp->cb_buf.b_proc = bp->b_proc; cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */ cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET; cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET); cbp->cb_buf.b_data = addr; cbp->cb_buf.b_vp = ci->ci_vp; LIST_INIT(&cbp->cb_buf.b_dep); cbp->cb_buf.b_resid = 0; if (cs->sc_ileave == 0) cbc = dbtob((off_t)(ci->ci_size - cbn)); else cbc = dbtob((off_t)(cs->sc_ileave - cboff)); cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount; cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount; /* * context for ccdiodone */ cbp->cb_obp = bp; cbp->cb_unit = cs - ccd_softc; cbp->cb_comp = ci - cs->sc_cinfo;#ifdef DEBUG if (ccddebug & CCDB_IO) printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);#endif cb[0] = cbp; if (cs->sc_cflags & CCDF_MIRROR && (cbp->cb_buf.b_flags & B_READ) == 0) { /* mirror, start one more write */ cbp = getccdbuf(); bzero(cbp, sizeof (struct ccdbuf)); *cbp = *cb[0]; cbp->cb_buf.b_dev = ci2->ci_dev; cbp->cb_buf.b_vp = ci2->ci_vp; LIST_INIT(&cbp->cb_buf.b_dep); 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; }}static voidccdintr(cs, bp) register struct ccd_softc *cs; register struct buf *bp;{#ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdintr(%x, %x)\n", cs, bp);#endif /* * Request is done for better or worse, wakeup the top half. */ /* Record device statistics */ devstat_end_transaction(&cs->device_stats, bp->b_bcount - bp->b_resid, (bp->b_flags & B_ORDERED) ? DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE, (bp->b_flags & B_READ) ? DEVSTAT_READ : DEVSTAT_WRITE); if (bp->b_flags & B_ERROR) bp->b_resid = bp->b_bcount; biodone(bp);}/* * Called at interrupt time. * Mark the component as done and if all components are done, * take a ccd interrupt. */static voidccdiodone(cbp) struct ccdbuf *cbp;{ register struct buf *bp = cbp->cb_obp; register int unit = cbp->cb_unit; int count, s; s = splbio();#ifdef DEBUG if (ccddebug & CCDB_FOLLOW) printf("ccdiodone(%x)\n", cbp); if (ccddebug & CCDB_IO) { printf("ccdiodone: bp %x bcount %d resid %d\n", bp, bp->b_bcount, bp->b_resid); printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", cbp->cb_buf.b_dev, cbp->cb_comp, cbp, cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); }#endif if (cbp->cb_buf.b_flags & B_ERROR) { bp->b_flags |= B_ERROR; bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;#ifdef DEBUG printf("ccd%d: error %d on component %d\n", 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -