Finally give CCD the disk mini-layer treatment:
CAUTION: Previously CCD would be different from all other disks in the system in that there were no "ccd0" device, only a "ccd0c" device. This is no longer so after this commit. If you access a ccd device through the "/dev/ccd0c" device _and_ have not actually put a BSD disklabel on the device, you will have to use the name "/dev/ccd0". If your CCD device contains a BSD disklabel there should be no difference. You need to recompile ccdconfig(8) using the changed src/sys/sys/ccdvar.h for the -g "show me" option to work. I have run the regression test I created before I started overhauling CCD and it flags no problems, but this code is mildly evil, so take care. If you would cry if you lost what's on CCD, make a back before you upgrade. Create separate cdevsw for the /dev/ccd.ctl device. Remove the cloning function, the disk-minilayer will do all naming for us. Remove the ccdunit and ccdpart functions and carry the softc pointer in the relevant dev_t's and structures. Release all memory when a CCD device is unconfigured, previously the softc would linger behind. Remove all traces of BSD disklabel fiddling code. Remove ccdpsize, the disk mini-layer does this for us. Don't allocate memory with M_WAITOK in ccdstrategy(). Remove boundary checks which the disk mini-layer does for us. Don't allocate space for more than 2 ccdbuf, RAID was never implemented. NB: I have not tried to address any of the preexisting ailments of CCD.
This commit is contained in:
parent
1dccd08a34
commit
0f76d6d822
@ -66,7 +66,6 @@
|
||||
#include <sys/stdint.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/devicestat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/vnode.h>
|
||||
@ -75,14 +74,6 @@
|
||||
|
||||
MALLOC_DEFINE(M_CCD, "CCD driver", "Concatenated Disk driver");
|
||||
|
||||
static u_int
|
||||
ccdunit(dev_t dev)
|
||||
{
|
||||
return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f));
|
||||
}
|
||||
|
||||
#define ccdpart(x) (minor(x) & 7)
|
||||
|
||||
/*
|
||||
This is how mirroring works (only writes are special):
|
||||
|
||||
@ -101,7 +92,7 @@ struct ccdbuf {
|
||||
struct bio cb_buf; /* new I/O buf */
|
||||
struct bio *cb_obp; /* ptr. to original I/O buf */
|
||||
struct ccdbuf *cb_freenext; /* free list link */
|
||||
int cb_unit; /* target unit */
|
||||
struct ccd_s *cb_softc;
|
||||
int cb_comp; /* target component */
|
||||
int cb_pflags; /* mirror/parity status flag */
|
||||
struct ccdbuf *cb_mirror; /* mirror counterpart */
|
||||
@ -110,48 +101,61 @@ struct ccdbuf {
|
||||
/* bits in cb_pflags */
|
||||
#define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */
|
||||
|
||||
#define CCDLABELDEV(dev) \
|
||||
(makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
|
||||
|
||||
/* convinient macros for often-used statements */
|
||||
#define IS_ALLOCATED(unit) (ccdfind(unit) != NULL)
|
||||
#define IS_INITED(cs) (((cs)->sc_flags & CCDF_INITED) != 0)
|
||||
|
||||
|
||||
static dev_t ccdctldev;
|
||||
|
||||
|
||||
static d_open_t ccdopen;
|
||||
static d_close_t ccdclose;
|
||||
static d_strategy_t ccdstrategy;
|
||||
static d_ioctl_t ccdioctl;
|
||||
static d_ioctl_t ccdioctltoo;
|
||||
static d_psize_t ccdsize;
|
||||
static d_ioctl_t ccdctlioctl;
|
||||
|
||||
#define NCCDFREEHIWAT 16
|
||||
|
||||
#define CDEV_MAJOR 74
|
||||
|
||||
static struct cdevsw ccdctl_cdevsw = {
|
||||
/* open */ nullopen,
|
||||
/* close */ nullclose,
|
||||
/* read */ noread,
|
||||
/* write */ nowrite,
|
||||
/* ioctl */ ccdctlioctl,
|
||||
/* poll */ nopoll,
|
||||
/* mmap */ nommap,
|
||||
/* strategy */ nostrategy,
|
||||
/* name */ "ccdctl",
|
||||
/* maj */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ 0
|
||||
};
|
||||
|
||||
static struct cdevsw ccd_cdevsw = {
|
||||
/* open */ ccdopen,
|
||||
/* close */ ccdclose,
|
||||
/* read */ physread,
|
||||
/* write */ physwrite,
|
||||
/* ioctl */ ccdioctl,
|
||||
/* ioctl */ noioctl,
|
||||
/* poll */ nopoll,
|
||||
/* mmap */ nommap,
|
||||
/* strategy */ ccdstrategy,
|
||||
/* name */ "ccd",
|
||||
/* maj */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ ccdsize,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ D_DISK,
|
||||
};
|
||||
static LIST_HEAD(, ccd_s) ccd_softc_list = LIST_HEAD_INITIALIZER(&ccd_softc_list);
|
||||
|
||||
static struct cdevsw ccddisk_cdevsw;
|
||||
|
||||
static LIST_HEAD(, ccd_s) ccd_softc_list =
|
||||
LIST_HEAD_INITIALIZER(&ccd_softc_list);
|
||||
|
||||
static struct ccd_s *ccdfind(int);
|
||||
static struct ccd_s *ccdnew(int);
|
||||
static int ccddestroy(struct ccd_s *, struct proc *);
|
||||
static int ccddestroy(struct ccd_s *);
|
||||
|
||||
/* called during module initialization */
|
||||
static void ccdattach(void);
|
||||
@ -164,10 +168,8 @@ static void ccdstart(struct ccd_s *, struct bio *);
|
||||
static void ccdinterleave(struct ccd_s *, int);
|
||||
static int ccdinit(struct ccd_s *, char **, struct thread *);
|
||||
static int ccdlookup(char *, struct thread *p, struct vnode **);
|
||||
static void ccdbuffer(struct ccdbuf **ret, struct ccd_s *,
|
||||
static int ccdbuffer(struct ccdbuf **ret, struct ccd_s *,
|
||||
struct bio *, daddr_t, caddr_t, long);
|
||||
static void ccdgetdisklabel(dev_t);
|
||||
static void ccdmakedisklabel(struct ccd_s *);
|
||||
static int ccdlock(struct ccd_s *);
|
||||
static void ccdunlock(struct ccd_s *);
|
||||
|
||||
@ -201,7 +203,7 @@ ccdnew(int unit)
|
||||
struct ccd_s *sc;
|
||||
|
||||
/* XXX: LOCK(unique unit numbers) */
|
||||
if (IS_ALLOCATED(unit) || unit > DKMAXUNIT)
|
||||
if (IS_ALLOCATED(unit) || unit > 32)
|
||||
return (NULL);
|
||||
|
||||
MALLOC(sc, struct ccd_s *, sizeof(*sc), M_CCD, M_WAITOK | M_ZERO);
|
||||
@ -212,7 +214,7 @@ ccdnew(int unit)
|
||||
}
|
||||
|
||||
static int
|
||||
ccddestroy(struct ccd_s *sc, struct proc *p)
|
||||
ccddestroy(struct ccd_s *sc)
|
||||
{
|
||||
|
||||
/* XXX: LOCK(unique unit numbers) */
|
||||
@ -222,25 +224,6 @@ ccddestroy(struct ccd_s *sc, struct proc *p)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ccd_clone(void *arg, char *name, int namelen, dev_t *dev)
|
||||
{
|
||||
int i, u;
|
||||
char *s;
|
||||
|
||||
if (*dev != NODEV)
|
||||
return;
|
||||
i = dev_stdclone(name, &s, "ccd", &u);
|
||||
if (i != 2)
|
||||
return;
|
||||
if (*s < 'a' || *s > 'h')
|
||||
return;
|
||||
if (s[1] != '\0')
|
||||
return;
|
||||
*dev = make_dev(&ccd_cdevsw, u * 8 + *s - 'a',
|
||||
UID_ROOT, GID_OPERATOR, 0640, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by main() during pseudo-device attachment. All we need
|
||||
* to do is to add devsw entries.
|
||||
@ -249,10 +232,9 @@ static void
|
||||
ccdattach()
|
||||
{
|
||||
|
||||
ccdctldev = make_dev(&ccd_cdevsw, 0xffff00ff,
|
||||
ccdctldev = make_dev(&ccdctl_cdevsw, 0xffff00ff,
|
||||
UID_ROOT, GID_OPERATOR, 0640, "ccd.ctl");
|
||||
ccdctldev->si_drv1 = ccdctldev;
|
||||
EVENTHANDLER_REGISTER(dev_clone, ccd_clone, 0, 1000);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -454,6 +436,7 @@ ccdinit(struct ccd_s *cs, char **cpaths, struct thread *td)
|
||||
if (tmppath != NULL)
|
||||
free(tmppath, M_CCD);
|
||||
free(cs->sc_cinfo, M_CCD);
|
||||
ccddestroy(cs);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -567,46 +550,13 @@ ccdinterleave(struct ccd_s *cs, int unit)
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
ccdopen(dev_t dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
int unit = ccdunit(dev);
|
||||
struct ccd_s *cs;
|
||||
struct disklabel *lp;
|
||||
int error = 0, part, pmask;
|
||||
|
||||
if (dev->si_drv1 == dev)
|
||||
return (0);
|
||||
|
||||
cs = IS_ALLOCATED(unit) ? ccdfind(unit) : ccdnew(unit);
|
||||
|
||||
if ((error = ccdlock(cs)) != 0)
|
||||
return (error);
|
||||
|
||||
lp = &cs->sc_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 (IS_INITED(cs) && (cs->sc_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;
|
||||
}
|
||||
|
||||
cs->sc_openmask |= pmask;
|
||||
done:
|
||||
ccdunlock(cs);
|
||||
cs = dev->si_drv1;
|
||||
cs->sc_openmask = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -614,96 +564,45 @@ ccdopen(dev_t dev, int flags, int fmt, struct thread *td)
|
||||
static int
|
||||
ccdclose(dev_t dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
int unit = ccdunit(dev);
|
||||
struct ccd_s *cs;
|
||||
int error = 0, part;
|
||||
|
||||
if (dev->si_drv1 == dev)
|
||||
return (0);
|
||||
|
||||
if (!IS_ALLOCATED(unit))
|
||||
return (ENXIO);
|
||||
cs = ccdfind(unit);
|
||||
|
||||
if ((error = ccdlock(cs)) != 0)
|
||||
return (error);
|
||||
|
||||
part = ccdpart(dev);
|
||||
|
||||
/* ...that much closer to allowing unconfiguration... */
|
||||
cs->sc_openmask &= ~(1 << part);
|
||||
/* collect "garbage" if possible */
|
||||
if (!IS_INITED(cs) && (cs->sc_flags & CCDF_WANTED) == 0)
|
||||
ccddestroy(cs, td->td_proc);
|
||||
else
|
||||
ccdunlock(cs);
|
||||
cs = dev->si_drv1;
|
||||
cs->sc_openmask = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ccdstrategy(struct bio *bp)
|
||||
{
|
||||
int unit = ccdunit(bp->bio_dev);
|
||||
struct ccd_s *cs = ccdfind(unit);
|
||||
int s;
|
||||
int wlabel;
|
||||
struct disklabel *lp;
|
||||
struct ccd_s *cs;
|
||||
int pbn; /* in sc_secsize chunks */
|
||||
long sz; /* in sc_secsize chunks */
|
||||
|
||||
if (bp->bio_dev->si_drv1 == bp->bio_dev) {
|
||||
biofinish(bp, NULL, ENXIO);
|
||||
return;
|
||||
}
|
||||
if (!IS_INITED(cs)) {
|
||||
biofinish(bp, NULL, ENXIO);
|
||||
return;
|
||||
}
|
||||
cs = bp->bio_dev->si_drv1;
|
||||
|
||||
/* If it's a nil transfer, wake up the top half now. */
|
||||
if (bp->bio_bcount == 0) {
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
lp = &cs->sc_label;
|
||||
pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE);
|
||||
sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize);
|
||||
|
||||
/*
|
||||
* Do bounds checking and adjust transfer. If there's an
|
||||
* error, the bounds check will flag that for us.
|
||||
* If out of bounds return an error. If at the EOF point,
|
||||
* simply read or write less.
|
||||
*/
|
||||
wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
|
||||
if (ccdpart(bp->bio_dev) != RAW_PART) {
|
||||
if (bounds_check_with_label(bp, lp, wlabel) <= 0) {
|
||||
|
||||
if (pbn < 0 || pbn >= cs->sc_size) {
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
if (pbn != cs->sc_size)
|
||||
biofinish(bp, NULL, EINVAL);
|
||||
else
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int pbn; /* in sc_secsize chunks */
|
||||
long sz; /* in sc_secsize chunks */
|
||||
return;
|
||||
}
|
||||
|
||||
pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE);
|
||||
sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize);
|
||||
|
||||
/*
|
||||
* If out of bounds return an error. If at the EOF point,
|
||||
* simply read or write less.
|
||||
*/
|
||||
|
||||
if (pbn < 0 || pbn >= cs->sc_size) {
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
if (pbn != cs->sc_size)
|
||||
biofinish(bp, NULL, EINVAL);
|
||||
else
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the request crosses EOF, truncate the request.
|
||||
*/
|
||||
if (pbn + sz > cs->sc_size) {
|
||||
bp->bio_bcount = (cs->sc_size - pbn) *
|
||||
cs->sc_geom.ccg_secsize;
|
||||
}
|
||||
/*
|
||||
* If the request crosses EOF, truncate the request.
|
||||
*/
|
||||
if (pbn + sz > cs->sc_size) {
|
||||
bp->bio_bcount = (cs->sc_size - pbn) *
|
||||
cs->sc_geom.ccg_secsize;
|
||||
}
|
||||
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
@ -711,9 +610,7 @@ ccdstrategy(struct bio *bp)
|
||||
/*
|
||||
* "Start" the unit.
|
||||
*/
|
||||
s = splbio();
|
||||
ccdstart(cs, bp);
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -721,11 +618,10 @@ static void
|
||||
ccdstart(struct ccd_s *cs, struct bio *bp)
|
||||
{
|
||||
long bcount, rcount;
|
||||
struct ccdbuf *cbp[4];
|
||||
/* XXX! : 2 reads and 2 writes for RAID 4/5 */
|
||||
struct ccdbuf *cbp[2];
|
||||
caddr_t addr;
|
||||
daddr_t bn;
|
||||
struct partition *pp;
|
||||
int err;
|
||||
|
||||
|
||||
/* Record the transaction start */
|
||||
@ -735,17 +631,21 @@ ccdstart(struct ccd_s *cs, struct bio *bp)
|
||||
* Translate the partition-relative block number to an absolute.
|
||||
*/
|
||||
bn = bp->bio_blkno;
|
||||
if (ccdpart(bp->bio_dev) != RAW_PART) {
|
||||
pp = &cs->sc_label.d_partitions[ccdpart(bp->bio_dev)];
|
||||
bn += pp->p_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate component buffers and fire off the requests
|
||||
*/
|
||||
addr = bp->bio_data;
|
||||
for (bcount = bp->bio_bcount; bcount > 0; bcount -= rcount) {
|
||||
ccdbuffer(cbp, cs, bp, bn, addr, bcount);
|
||||
err = ccdbuffer(cbp, cs, bp, bn, addr, bcount);
|
||||
if (err) {
|
||||
printf("ccdbuffer error %d\n", err);
|
||||
/* We're screwed */
|
||||
bp->bio_resid -= bcount;
|
||||
bp->bio_error = ENOMEM;
|
||||
bp->bio_flags |= BIO_ERROR;
|
||||
return;
|
||||
}
|
||||
rcount = cbp[0]->cb_buf.bio_bcount;
|
||||
|
||||
if (cs->sc_cflags & CCDF_MIRROR) {
|
||||
@ -787,7 +687,7 @@ ccdstart(struct ccd_s *cs, struct bio *bp)
|
||||
/*
|
||||
* Build a component buffer header.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, caddr_t addr, long bcount)
|
||||
{
|
||||
struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
|
||||
@ -893,13 +793,16 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
/*
|
||||
* Fill in the component buf structure.
|
||||
*/
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_WAITOK | M_ZERO);
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_NOWAIT | M_ZERO);
|
||||
if (cbp == NULL)
|
||||
return (ENOMEM);
|
||||
cbp->cb_buf.bio_cmd = bp->bio_cmd;
|
||||
cbp->cb_buf.bio_done = ccdiodone;
|
||||
cbp->cb_buf.bio_dev = ci->ci_dev; /* XXX */
|
||||
cbp->cb_buf.bio_blkno = cbn + cboff + CCD_OFFSET;
|
||||
cbp->cb_buf.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
|
||||
cbp->cb_buf.bio_data = addr;
|
||||
cbp->cb_buf.bio_caller2 = cbp;
|
||||
if (cs->sc_ileave == 0)
|
||||
cbc = dbtob((off_t)(ci->ci_size - cbn));
|
||||
else
|
||||
@ -911,7 +814,7 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
* context for ccdiodone
|
||||
*/
|
||||
cbp->cb_obp = bp;
|
||||
cbp->cb_unit = cs->sc_unit;
|
||||
cbp->cb_softc = cs;
|
||||
cbp->cb_comp = ci - cs->sc_cinfo;
|
||||
|
||||
cb[0] = cbp;
|
||||
@ -922,7 +825,12 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
*/
|
||||
if (cs->sc_cflags & CCDF_MIRROR) {
|
||||
/* mirror, setup second I/O */
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_WAITOK);
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_NOWAIT);
|
||||
if (cbp == NULL) {
|
||||
free(cb[0], M_CCD);
|
||||
cb[0] = NULL;
|
||||
return (ENOMEM);
|
||||
}
|
||||
bcopy(cb[0], cbp, sizeof(struct ccdbuf));
|
||||
cbp->cb_buf.bio_dev = ci2->ci_dev;
|
||||
cbp->cb_comp = ci2 - cs->sc_cinfo;
|
||||
@ -933,6 +841,7 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
|
||||
cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -943,14 +852,14 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
static void
|
||||
ccdiodone(struct bio *ibp)
|
||||
{
|
||||
struct ccdbuf *cbp = (struct ccdbuf *)ibp;
|
||||
struct bio *bp = cbp->cb_obp;
|
||||
int unit = cbp->cb_unit;
|
||||
struct ccdbuf *cbp;
|
||||
struct bio *bp;
|
||||
struct ccd_s *cs;
|
||||
int count, s;
|
||||
int count;
|
||||
|
||||
cs = ccdfind(unit);
|
||||
s = splbio();
|
||||
cbp = ibp->bio_caller2;
|
||||
cs = cbp->cb_softc;
|
||||
bp = cbp->cb_obp;
|
||||
/*
|
||||
* If an error occured, report it. If this is a mirrored
|
||||
* configuration and the first of two possible reads, do not
|
||||
@ -980,7 +889,8 @@ ccdiodone(struct bio *ibp)
|
||||
cbp->cb_buf.bio_error : EIO;
|
||||
}
|
||||
printf("ccd%d: error %d on component %d block %jd "
|
||||
"(ccd block %jd)%s\n", unit, bp->bio_error, cbp->cb_comp,
|
||||
"(ccd block %jd)%s\n", cs->sc_unit, bp->bio_error,
|
||||
cbp->cb_comp,
|
||||
(intmax_t)cbp->cb_buf.bio_blkno, (intmax_t)bp->bio_blkno,
|
||||
msg);
|
||||
}
|
||||
@ -1004,7 +914,6 @@ ccdiodone(struct bio *ibp)
|
||||
if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
|
||||
cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
|
||||
free(cbp, M_CCD);
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -1019,7 +928,6 @@ ccdiodone(struct bio *ibp)
|
||||
CCDPF_MIRROR_DONE;
|
||||
BIO_STRATEGY(&cbp->cb_mirror->cb_buf);
|
||||
free(cbp, M_CCD);
|
||||
splx(s);
|
||||
return;
|
||||
} else {
|
||||
free(cbp->cb_mirror, M_CCD);
|
||||
@ -1051,42 +959,24 @@ ccdiodone(struct bio *ibp)
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
biofinish(bp, &cs->device_stats, 0);
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static int ccdioctltoo(int unit, u_long cmd, caddr_t data, int flag, struct thread *td);
|
||||
|
||||
static int
|
||||
ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
ccdctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
struct ccd_ioctl *ccio;
|
||||
u_int unit;
|
||||
dev_t dev2;
|
||||
int error;
|
||||
|
||||
if (dev->si_drv1 != dev) {
|
||||
switch (cmd) {
|
||||
case CCDIOCSET:
|
||||
case CCDIOCCLR:
|
||||
case CCDCONFINFO:
|
||||
case CCDCPPINFO:
|
||||
printf("*** WARNING: upgrade your ccdconfig(8) binary\n");
|
||||
printf("*** WARNING: continuing in 30 seconds\n");
|
||||
tsleep(dev, PRIBIO, "ccdbug", hz * 30);
|
||||
break;
|
||||
}
|
||||
return ccdioctltoo(dev, cmd, data, flag, td);
|
||||
}
|
||||
switch (cmd) {
|
||||
case CCDIOCSET:
|
||||
case CCDIOCCLR:
|
||||
ccio = (struct ccd_ioctl *)data;
|
||||
unit = ccio->ccio_size;
|
||||
dev2 = makedev(CDEV_MAJOR, unit * 8 + 2);
|
||||
if (!(dev2->si_flags & SI_NAMED)) {
|
||||
dev2 = make_dev(&ccd_cdevsw, unit * 8 + 2,
|
||||
UID_ROOT, GID_OPERATOR, 0640, "ccd%dc", unit);
|
||||
ccdnew(unit);
|
||||
}
|
||||
return (ccdioctltoo(dev2, cmd, data, flag, td));
|
||||
return (ccdioctltoo(unit, cmd, data, flag, td));
|
||||
case CCDCONFINFO:
|
||||
{
|
||||
int ninit = 0;
|
||||
@ -1126,6 +1016,7 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
struct ccdcpps *cpps = (struct ccdcpps *)data;
|
||||
char *ubuf = cpps->buffer;
|
||||
struct ccd_s *cs;
|
||||
|
||||
|
||||
error = copyin(ubuf, &unit, sizeof (unit));
|
||||
@ -1135,7 +1026,33 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
if (!IS_ALLOCATED(unit))
|
||||
return (ENXIO);
|
||||
dev2 = makedev(CDEV_MAJOR, unit * 8 + 2);
|
||||
return (ccdioctltoo(dev2, cmd, data, flag, td));
|
||||
cs = ccdfind(unit);
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
{
|
||||
int len = 0, i;
|
||||
struct ccdcpps *cpps = (struct ccdcpps *)data;
|
||||
char *ubuf = cpps->buffer;
|
||||
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i)
|
||||
len += cs->sc_cinfo[i].ci_pathlen;
|
||||
|
||||
if (cpps->size < len)
|
||||
return (ENOMEM);
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i) {
|
||||
len = cs->sc_cinfo[i].ci_pathlen;
|
||||
error = copyout(cs->sc_cinfo[i].ci_path, ubuf,
|
||||
len);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
ubuf += len;
|
||||
}
|
||||
return(copyout("", ubuf, 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
@ -1144,23 +1061,20 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
}
|
||||
|
||||
static int
|
||||
ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
ccdioctltoo(int unit, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
int unit;
|
||||
int i, j, lookedup = 0, error = 0;
|
||||
int part, pmask, s;
|
||||
struct ccd_s *cs;
|
||||
struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
|
||||
struct ccdgeom *ccg;
|
||||
char **cpp;
|
||||
struct vnode **vpp;
|
||||
|
||||
unit = ccdunit(dev);
|
||||
if (!IS_ALLOCATED(unit))
|
||||
return (ENXIO);
|
||||
cs = ccdfind(unit);
|
||||
|
||||
switch (cmd) {
|
||||
case CCDIOCSET:
|
||||
if (cs == NULL)
|
||||
cs = ccdnew(unit);
|
||||
if (IS_INITED(cs))
|
||||
return (EBUSY);
|
||||
|
||||
@ -1250,13 +1164,25 @@ ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
*/
|
||||
ccio->ccio_unit = unit;
|
||||
ccio->ccio_size = cs->sc_size;
|
||||
ccdgetdisklabel(dev);
|
||||
cs->sc_disk = malloc(sizeof(struct disk), M_CCD, M_WAITOK);
|
||||
cs->sc_dev = disk_create(unit, cs->sc_disk, 0,
|
||||
&ccd_cdevsw, &ccddisk_cdevsw);
|
||||
cs->sc_dev->si_drv1 = cs;
|
||||
ccg = &cs->sc_geom;
|
||||
cs->sc_disk->d_sectorsize = ccg->ccg_secsize;
|
||||
cs->sc_disk->d_mediasize =
|
||||
cs->sc_size * (off_t)ccg->ccg_secsize;
|
||||
cs->sc_disk->d_fwsectors = ccg->ccg_nsectors;
|
||||
cs->sc_disk->d_fwheads = ccg->ccg_ntracks;
|
||||
|
||||
ccdunlock(cs);
|
||||
|
||||
break;
|
||||
|
||||
case CCDIOCCLR:
|
||||
if (cs == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
@ -1267,13 +1193,14 @@ ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
return (error);
|
||||
|
||||
/* Don't unconfigure if any other partitions are open */
|
||||
part = ccdpart(dev);
|
||||
pmask = (1 << part);
|
||||
if ((cs->sc_openmask & ~pmask)) {
|
||||
if (cs->sc_openmask) {
|
||||
ccdunlock(cs);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
disk_destroy(cs->sc_dev);
|
||||
free(cs->sc_disk, M_CCD);
|
||||
cs->sc_disk = NULL;
|
||||
/* Declare unit null and void (reset all flags) */
|
||||
cs->sc_flags &= (CCDF_WANTED | CCDF_LOCKED);
|
||||
|
||||
@ -1302,162 +1229,15 @@ ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
devstat_remove_entry(&cs->device_stats);
|
||||
|
||||
/* This must be atomic. */
|
||||
s = splhigh();
|
||||
ccdunlock(cs);
|
||||
splx(s);
|
||||
ccddestroy(cs);
|
||||
|
||||
break;
|
||||
|
||||
case CCDCONFINFO:
|
||||
{
|
||||
int ninit = 0;
|
||||
struct ccdconf *conf = (struct ccdconf *)data;
|
||||
struct ccd_s *tmpcs;
|
||||
struct ccd_s *ubuf = conf->buffer;
|
||||
|
||||
/* XXX: LOCK(unique unit numbers) */
|
||||
LIST_FOREACH(tmpcs, &ccd_softc_list, list)
|
||||
if (IS_INITED(tmpcs))
|
||||
ninit++;
|
||||
|
||||
if (conf->size == 0) {
|
||||
conf->size = sizeof(struct ccd_s) * ninit;
|
||||
break;
|
||||
} else if ((conf->size / sizeof(struct ccd_s) != ninit) ||
|
||||
(conf->size % sizeof(struct ccd_s) != 0)) {
|
||||
/* XXX: UNLOCK(unique unit numbers) */
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
ubuf += ninit;
|
||||
LIST_FOREACH(tmpcs, &ccd_softc_list, list) {
|
||||
if (!IS_INITED(tmpcs))
|
||||
continue;
|
||||
error = copyout(tmpcs, --ubuf,
|
||||
sizeof(struct ccd_s));
|
||||
if (error != 0)
|
||||
/* XXX: UNLOCK(unique unit numbers) */
|
||||
return (error);
|
||||
}
|
||||
/* XXX: UNLOCK(unique unit numbers) */
|
||||
}
|
||||
break;
|
||||
|
||||
case CCDCPPINFO:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
{
|
||||
int len = 0;
|
||||
struct ccdcpps *cpps = (struct ccdcpps *)data;
|
||||
char *ubuf = cpps->buffer;
|
||||
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i)
|
||||
len += cs->sc_cinfo[i].ci_pathlen;
|
||||
|
||||
if (cpps->size == 0) {
|
||||
cpps->size = len;
|
||||
break;
|
||||
} else if (cpps->size < len) {
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i) {
|
||||
len = cs->sc_cinfo[i].ci_pathlen;
|
||||
error = copyout(cs->sc_cinfo[i].ci_path, ubuf,
|
||||
len);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
ubuf += len;
|
||||
}
|
||||
return(copyout("", ubuf, 1));
|
||||
}
|
||||
break;
|
||||
|
||||
case DIOCGDINFO:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
*(struct disklabel *)data = cs->sc_label;
|
||||
break;
|
||||
|
||||
case DIOCWDINFO:
|
||||
case DIOCSDINFO:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
if ((flag & FWRITE) == 0)
|
||||
return (EBADF);
|
||||
|
||||
if ((error = ccdlock(cs)) != 0)
|
||||
return (error);
|
||||
|
||||
cs->sc_flags |= CCDF_LABELLING;
|
||||
|
||||
error = setdisklabel(&cs->sc_label,
|
||||
(struct disklabel *)data, 0);
|
||||
if (error == 0) {
|
||||
if (cmd == DIOCWDINFO)
|
||||
error = writedisklabel(CCDLABELDEV(dev),
|
||||
&cs->sc_label);
|
||||
}
|
||||
|
||||
cs->sc_flags &= ~CCDF_LABELLING;
|
||||
|
||||
ccdunlock(cs);
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
break;
|
||||
|
||||
case DIOCWLABEL:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
if ((flag & FWRITE) == 0)
|
||||
return (EBADF);
|
||||
if (*(int *)data != 0)
|
||||
cs->sc_flags |= CCDF_WLABEL;
|
||||
else
|
||||
cs->sc_flags &= ~CCDF_WLABEL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (ENOTTY);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ccdsize(dev_t dev)
|
||||
{
|
||||
struct ccd_s *cs;
|
||||
int part, size;
|
||||
|
||||
if (dev->si_drv1 == dev)
|
||||
return (-1);
|
||||
|
||||
if (ccdopen(dev, 0, S_IFCHR, curthread))
|
||||
return (-1);
|
||||
|
||||
cs = ccdfind(ccdunit(dev));
|
||||
part = ccdpart(dev);
|
||||
|
||||
if (!IS_INITED(cs))
|
||||
return (-1);
|
||||
|
||||
if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
|
||||
size = -1;
|
||||
else
|
||||
size = cs->sc_label.d_partitions[part].p_size;
|
||||
|
||||
if (ccdclose(dev, 0, S_IFCHR, curthread))
|
||||
return (-1);
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup the provided name in the filesystem. If the file exists,
|
||||
@ -1500,74 +1280,7 @@ ccdlookup(char *path, struct thread *td, struct vnode **vpp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the disklabel from the ccd. If one is not present, fake one
|
||||
* up.
|
||||
*/
|
||||
static void
|
||||
ccdgetdisklabel(dev_t dev)
|
||||
{
|
||||
int unit = ccdunit(dev);
|
||||
struct ccd_s *cs = ccdfind(unit);
|
||||
char *errstring;
|
||||
struct disklabel *lp = &cs->sc_label;
|
||||
struct ccdgeom *ccg = &cs->sc_geom;
|
||||
|
||||
bzero(lp, sizeof(*lp));
|
||||
|
||||
lp->d_secperunit = cs->sc_size;
|
||||
lp->d_secsize = ccg->ccg_secsize;
|
||||
lp->d_nsectors = ccg->ccg_nsectors;
|
||||
lp->d_ntracks = ccg->ccg_ntracks;
|
||||
lp->d_ncylinders = ccg->ccg_ncylinders;
|
||||
lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
|
||||
|
||||
strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
|
||||
lp->d_type = DTYPE_CCD;
|
||||
strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
|
||||
lp->d_rpm = 3600;
|
||||
lp->d_interleave = 1;
|
||||
lp->d_flags = 0;
|
||||
|
||||
lp->d_partitions[RAW_PART].p_offset = 0;
|
||||
lp->d_partitions[RAW_PART].p_size = cs->sc_size;
|
||||
lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
|
||||
lp->d_npartitions = RAW_PART + 1;
|
||||
|
||||
lp->d_bbsize = BBSIZE; /* XXX */
|
||||
lp->d_sbsize = 0;
|
||||
|
||||
lp->d_magic = DISKMAGIC;
|
||||
lp->d_magic2 = DISKMAGIC;
|
||||
lp->d_checksum = dkcksum(&cs->sc_label);
|
||||
|
||||
/*
|
||||
* Call the generic disklabel extraction routine.
|
||||
*/
|
||||
errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label);
|
||||
if (errstring != NULL)
|
||||
ccdmakedisklabel(cs);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Take care of things one might want to take care of in the event
|
||||
* that a disklabel isn't present.
|
||||
*/
|
||||
static void
|
||||
ccdmakedisklabel(struct ccd_s *cs)
|
||||
{
|
||||
struct disklabel *lp = &cs->sc_label;
|
||||
|
||||
/*
|
||||
* For historical reasons, if there's no disklabel present
|
||||
* the raw partition must be marked FS_BSDFFS.
|
||||
*/
|
||||
lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
|
||||
|
||||
strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait interruptibly for an exclusive lock.
|
||||
*
|
||||
* XXX
|
||||
@ -1600,4 +1313,3 @@ ccdunlock(struct ccd_s *cs)
|
||||
wakeup(cs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,6 @@
|
||||
#include <sys/stdint.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/devicestat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/vnode.h>
|
||||
@ -75,14 +74,6 @@
|
||||
|
||||
MALLOC_DEFINE(M_CCD, "CCD driver", "Concatenated Disk driver");
|
||||
|
||||
static u_int
|
||||
ccdunit(dev_t dev)
|
||||
{
|
||||
return (((minor(dev) >> 16) & 0x1e0) | ((minor(dev) >> 3) & 0x1f));
|
||||
}
|
||||
|
||||
#define ccdpart(x) (minor(x) & 7)
|
||||
|
||||
/*
|
||||
This is how mirroring works (only writes are special):
|
||||
|
||||
@ -101,7 +92,7 @@ struct ccdbuf {
|
||||
struct bio cb_buf; /* new I/O buf */
|
||||
struct bio *cb_obp; /* ptr. to original I/O buf */
|
||||
struct ccdbuf *cb_freenext; /* free list link */
|
||||
int cb_unit; /* target unit */
|
||||
struct ccd_s *cb_softc;
|
||||
int cb_comp; /* target component */
|
||||
int cb_pflags; /* mirror/parity status flag */
|
||||
struct ccdbuf *cb_mirror; /* mirror counterpart */
|
||||
@ -110,48 +101,61 @@ struct ccdbuf {
|
||||
/* bits in cb_pflags */
|
||||
#define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */
|
||||
|
||||
#define CCDLABELDEV(dev) \
|
||||
(makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
|
||||
|
||||
/* convinient macros for often-used statements */
|
||||
#define IS_ALLOCATED(unit) (ccdfind(unit) != NULL)
|
||||
#define IS_INITED(cs) (((cs)->sc_flags & CCDF_INITED) != 0)
|
||||
|
||||
|
||||
static dev_t ccdctldev;
|
||||
|
||||
|
||||
static d_open_t ccdopen;
|
||||
static d_close_t ccdclose;
|
||||
static d_strategy_t ccdstrategy;
|
||||
static d_ioctl_t ccdioctl;
|
||||
static d_ioctl_t ccdioctltoo;
|
||||
static d_psize_t ccdsize;
|
||||
static d_ioctl_t ccdctlioctl;
|
||||
|
||||
#define NCCDFREEHIWAT 16
|
||||
|
||||
#define CDEV_MAJOR 74
|
||||
|
||||
static struct cdevsw ccdctl_cdevsw = {
|
||||
/* open */ nullopen,
|
||||
/* close */ nullclose,
|
||||
/* read */ noread,
|
||||
/* write */ nowrite,
|
||||
/* ioctl */ ccdctlioctl,
|
||||
/* poll */ nopoll,
|
||||
/* mmap */ nommap,
|
||||
/* strategy */ nostrategy,
|
||||
/* name */ "ccdctl",
|
||||
/* maj */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ 0
|
||||
};
|
||||
|
||||
static struct cdevsw ccd_cdevsw = {
|
||||
/* open */ ccdopen,
|
||||
/* close */ ccdclose,
|
||||
/* read */ physread,
|
||||
/* write */ physwrite,
|
||||
/* ioctl */ ccdioctl,
|
||||
/* ioctl */ noioctl,
|
||||
/* poll */ nopoll,
|
||||
/* mmap */ nommap,
|
||||
/* strategy */ ccdstrategy,
|
||||
/* name */ "ccd",
|
||||
/* maj */ CDEV_MAJOR,
|
||||
/* dump */ nodump,
|
||||
/* psize */ ccdsize,
|
||||
/* psize */ nopsize,
|
||||
/* flags */ D_DISK,
|
||||
};
|
||||
static LIST_HEAD(, ccd_s) ccd_softc_list = LIST_HEAD_INITIALIZER(&ccd_softc_list);
|
||||
|
||||
static struct cdevsw ccddisk_cdevsw;
|
||||
|
||||
static LIST_HEAD(, ccd_s) ccd_softc_list =
|
||||
LIST_HEAD_INITIALIZER(&ccd_softc_list);
|
||||
|
||||
static struct ccd_s *ccdfind(int);
|
||||
static struct ccd_s *ccdnew(int);
|
||||
static int ccddestroy(struct ccd_s *, struct proc *);
|
||||
static int ccddestroy(struct ccd_s *);
|
||||
|
||||
/* called during module initialization */
|
||||
static void ccdattach(void);
|
||||
@ -164,10 +168,8 @@ static void ccdstart(struct ccd_s *, struct bio *);
|
||||
static void ccdinterleave(struct ccd_s *, int);
|
||||
static int ccdinit(struct ccd_s *, char **, struct thread *);
|
||||
static int ccdlookup(char *, struct thread *p, struct vnode **);
|
||||
static void ccdbuffer(struct ccdbuf **ret, struct ccd_s *,
|
||||
static int ccdbuffer(struct ccdbuf **ret, struct ccd_s *,
|
||||
struct bio *, daddr_t, caddr_t, long);
|
||||
static void ccdgetdisklabel(dev_t);
|
||||
static void ccdmakedisklabel(struct ccd_s *);
|
||||
static int ccdlock(struct ccd_s *);
|
||||
static void ccdunlock(struct ccd_s *);
|
||||
|
||||
@ -201,7 +203,7 @@ ccdnew(int unit)
|
||||
struct ccd_s *sc;
|
||||
|
||||
/* XXX: LOCK(unique unit numbers) */
|
||||
if (IS_ALLOCATED(unit) || unit > DKMAXUNIT)
|
||||
if (IS_ALLOCATED(unit) || unit > 32)
|
||||
return (NULL);
|
||||
|
||||
MALLOC(sc, struct ccd_s *, sizeof(*sc), M_CCD, M_WAITOK | M_ZERO);
|
||||
@ -212,7 +214,7 @@ ccdnew(int unit)
|
||||
}
|
||||
|
||||
static int
|
||||
ccddestroy(struct ccd_s *sc, struct proc *p)
|
||||
ccddestroy(struct ccd_s *sc)
|
||||
{
|
||||
|
||||
/* XXX: LOCK(unique unit numbers) */
|
||||
@ -222,25 +224,6 @@ ccddestroy(struct ccd_s *sc, struct proc *p)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ccd_clone(void *arg, char *name, int namelen, dev_t *dev)
|
||||
{
|
||||
int i, u;
|
||||
char *s;
|
||||
|
||||
if (*dev != NODEV)
|
||||
return;
|
||||
i = dev_stdclone(name, &s, "ccd", &u);
|
||||
if (i != 2)
|
||||
return;
|
||||
if (*s < 'a' || *s > 'h')
|
||||
return;
|
||||
if (s[1] != '\0')
|
||||
return;
|
||||
*dev = make_dev(&ccd_cdevsw, u * 8 + *s - 'a',
|
||||
UID_ROOT, GID_OPERATOR, 0640, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by main() during pseudo-device attachment. All we need
|
||||
* to do is to add devsw entries.
|
||||
@ -249,10 +232,9 @@ static void
|
||||
ccdattach()
|
||||
{
|
||||
|
||||
ccdctldev = make_dev(&ccd_cdevsw, 0xffff00ff,
|
||||
ccdctldev = make_dev(&ccdctl_cdevsw, 0xffff00ff,
|
||||
UID_ROOT, GID_OPERATOR, 0640, "ccd.ctl");
|
||||
ccdctldev->si_drv1 = ccdctldev;
|
||||
EVENTHANDLER_REGISTER(dev_clone, ccd_clone, 0, 1000);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -454,6 +436,7 @@ ccdinit(struct ccd_s *cs, char **cpaths, struct thread *td)
|
||||
if (tmppath != NULL)
|
||||
free(tmppath, M_CCD);
|
||||
free(cs->sc_cinfo, M_CCD);
|
||||
ccddestroy(cs);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -567,46 +550,13 @@ ccdinterleave(struct ccd_s *cs, int unit)
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
ccdopen(dev_t dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
int unit = ccdunit(dev);
|
||||
struct ccd_s *cs;
|
||||
struct disklabel *lp;
|
||||
int error = 0, part, pmask;
|
||||
|
||||
if (dev->si_drv1 == dev)
|
||||
return (0);
|
||||
|
||||
cs = IS_ALLOCATED(unit) ? ccdfind(unit) : ccdnew(unit);
|
||||
|
||||
if ((error = ccdlock(cs)) != 0)
|
||||
return (error);
|
||||
|
||||
lp = &cs->sc_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 (IS_INITED(cs) && (cs->sc_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;
|
||||
}
|
||||
|
||||
cs->sc_openmask |= pmask;
|
||||
done:
|
||||
ccdunlock(cs);
|
||||
cs = dev->si_drv1;
|
||||
cs->sc_openmask = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -614,96 +564,45 @@ ccdopen(dev_t dev, int flags, int fmt, struct thread *td)
|
||||
static int
|
||||
ccdclose(dev_t dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
int unit = ccdunit(dev);
|
||||
struct ccd_s *cs;
|
||||
int error = 0, part;
|
||||
|
||||
if (dev->si_drv1 == dev)
|
||||
return (0);
|
||||
|
||||
if (!IS_ALLOCATED(unit))
|
||||
return (ENXIO);
|
||||
cs = ccdfind(unit);
|
||||
|
||||
if ((error = ccdlock(cs)) != 0)
|
||||
return (error);
|
||||
|
||||
part = ccdpart(dev);
|
||||
|
||||
/* ...that much closer to allowing unconfiguration... */
|
||||
cs->sc_openmask &= ~(1 << part);
|
||||
/* collect "garbage" if possible */
|
||||
if (!IS_INITED(cs) && (cs->sc_flags & CCDF_WANTED) == 0)
|
||||
ccddestroy(cs, td->td_proc);
|
||||
else
|
||||
ccdunlock(cs);
|
||||
cs = dev->si_drv1;
|
||||
cs->sc_openmask = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ccdstrategy(struct bio *bp)
|
||||
{
|
||||
int unit = ccdunit(bp->bio_dev);
|
||||
struct ccd_s *cs = ccdfind(unit);
|
||||
int s;
|
||||
int wlabel;
|
||||
struct disklabel *lp;
|
||||
struct ccd_s *cs;
|
||||
int pbn; /* in sc_secsize chunks */
|
||||
long sz; /* in sc_secsize chunks */
|
||||
|
||||
if (bp->bio_dev->si_drv1 == bp->bio_dev) {
|
||||
biofinish(bp, NULL, ENXIO);
|
||||
return;
|
||||
}
|
||||
if (!IS_INITED(cs)) {
|
||||
biofinish(bp, NULL, ENXIO);
|
||||
return;
|
||||
}
|
||||
cs = bp->bio_dev->si_drv1;
|
||||
|
||||
/* If it's a nil transfer, wake up the top half now. */
|
||||
if (bp->bio_bcount == 0) {
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
lp = &cs->sc_label;
|
||||
pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE);
|
||||
sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize);
|
||||
|
||||
/*
|
||||
* Do bounds checking and adjust transfer. If there's an
|
||||
* error, the bounds check will flag that for us.
|
||||
* If out of bounds return an error. If at the EOF point,
|
||||
* simply read or write less.
|
||||
*/
|
||||
wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
|
||||
if (ccdpart(bp->bio_dev) != RAW_PART) {
|
||||
if (bounds_check_with_label(bp, lp, wlabel) <= 0) {
|
||||
|
||||
if (pbn < 0 || pbn >= cs->sc_size) {
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
if (pbn != cs->sc_size)
|
||||
biofinish(bp, NULL, EINVAL);
|
||||
else
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int pbn; /* in sc_secsize chunks */
|
||||
long sz; /* in sc_secsize chunks */
|
||||
return;
|
||||
}
|
||||
|
||||
pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE);
|
||||
sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize);
|
||||
|
||||
/*
|
||||
* If out of bounds return an error. If at the EOF point,
|
||||
* simply read or write less.
|
||||
*/
|
||||
|
||||
if (pbn < 0 || pbn >= cs->sc_size) {
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
if (pbn != cs->sc_size)
|
||||
biofinish(bp, NULL, EINVAL);
|
||||
else
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the request crosses EOF, truncate the request.
|
||||
*/
|
||||
if (pbn + sz > cs->sc_size) {
|
||||
bp->bio_bcount = (cs->sc_size - pbn) *
|
||||
cs->sc_geom.ccg_secsize;
|
||||
}
|
||||
/*
|
||||
* If the request crosses EOF, truncate the request.
|
||||
*/
|
||||
if (pbn + sz > cs->sc_size) {
|
||||
bp->bio_bcount = (cs->sc_size - pbn) *
|
||||
cs->sc_geom.ccg_secsize;
|
||||
}
|
||||
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
@ -711,9 +610,7 @@ ccdstrategy(struct bio *bp)
|
||||
/*
|
||||
* "Start" the unit.
|
||||
*/
|
||||
s = splbio();
|
||||
ccdstart(cs, bp);
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -721,11 +618,10 @@ static void
|
||||
ccdstart(struct ccd_s *cs, struct bio *bp)
|
||||
{
|
||||
long bcount, rcount;
|
||||
struct ccdbuf *cbp[4];
|
||||
/* XXX! : 2 reads and 2 writes for RAID 4/5 */
|
||||
struct ccdbuf *cbp[2];
|
||||
caddr_t addr;
|
||||
daddr_t bn;
|
||||
struct partition *pp;
|
||||
int err;
|
||||
|
||||
|
||||
/* Record the transaction start */
|
||||
@ -735,17 +631,21 @@ ccdstart(struct ccd_s *cs, struct bio *bp)
|
||||
* Translate the partition-relative block number to an absolute.
|
||||
*/
|
||||
bn = bp->bio_blkno;
|
||||
if (ccdpart(bp->bio_dev) != RAW_PART) {
|
||||
pp = &cs->sc_label.d_partitions[ccdpart(bp->bio_dev)];
|
||||
bn += pp->p_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate component buffers and fire off the requests
|
||||
*/
|
||||
addr = bp->bio_data;
|
||||
for (bcount = bp->bio_bcount; bcount > 0; bcount -= rcount) {
|
||||
ccdbuffer(cbp, cs, bp, bn, addr, bcount);
|
||||
err = ccdbuffer(cbp, cs, bp, bn, addr, bcount);
|
||||
if (err) {
|
||||
printf("ccdbuffer error %d\n", err);
|
||||
/* We're screwed */
|
||||
bp->bio_resid -= bcount;
|
||||
bp->bio_error = ENOMEM;
|
||||
bp->bio_flags |= BIO_ERROR;
|
||||
return;
|
||||
}
|
||||
rcount = cbp[0]->cb_buf.bio_bcount;
|
||||
|
||||
if (cs->sc_cflags & CCDF_MIRROR) {
|
||||
@ -787,7 +687,7 @@ ccdstart(struct ccd_s *cs, struct bio *bp)
|
||||
/*
|
||||
* Build a component buffer header.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, caddr_t addr, long bcount)
|
||||
{
|
||||
struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
|
||||
@ -893,13 +793,16 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
/*
|
||||
* Fill in the component buf structure.
|
||||
*/
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_WAITOK | M_ZERO);
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_NOWAIT | M_ZERO);
|
||||
if (cbp == NULL)
|
||||
return (ENOMEM);
|
||||
cbp->cb_buf.bio_cmd = bp->bio_cmd;
|
||||
cbp->cb_buf.bio_done = ccdiodone;
|
||||
cbp->cb_buf.bio_dev = ci->ci_dev; /* XXX */
|
||||
cbp->cb_buf.bio_blkno = cbn + cboff + CCD_OFFSET;
|
||||
cbp->cb_buf.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
|
||||
cbp->cb_buf.bio_data = addr;
|
||||
cbp->cb_buf.bio_caller2 = cbp;
|
||||
if (cs->sc_ileave == 0)
|
||||
cbc = dbtob((off_t)(ci->ci_size - cbn));
|
||||
else
|
||||
@ -911,7 +814,7 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
* context for ccdiodone
|
||||
*/
|
||||
cbp->cb_obp = bp;
|
||||
cbp->cb_unit = cs->sc_unit;
|
||||
cbp->cb_softc = cs;
|
||||
cbp->cb_comp = ci - cs->sc_cinfo;
|
||||
|
||||
cb[0] = cbp;
|
||||
@ -922,7 +825,12 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
*/
|
||||
if (cs->sc_cflags & CCDF_MIRROR) {
|
||||
/* mirror, setup second I/O */
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_WAITOK);
|
||||
cbp = malloc(sizeof(struct ccdbuf), M_CCD, M_NOWAIT);
|
||||
if (cbp == NULL) {
|
||||
free(cb[0], M_CCD);
|
||||
cb[0] = NULL;
|
||||
return (ENOMEM);
|
||||
}
|
||||
bcopy(cb[0], cbp, sizeof(struct ccdbuf));
|
||||
cbp->cb_buf.bio_dev = ci2->ci_dev;
|
||||
cbp->cb_comp = ci2 - cs->sc_cinfo;
|
||||
@ -933,6 +841,7 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
|
||||
cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -943,14 +852,14 @@ ccdbuffer(struct ccdbuf **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, cadd
|
||||
static void
|
||||
ccdiodone(struct bio *ibp)
|
||||
{
|
||||
struct ccdbuf *cbp = (struct ccdbuf *)ibp;
|
||||
struct bio *bp = cbp->cb_obp;
|
||||
int unit = cbp->cb_unit;
|
||||
struct ccdbuf *cbp;
|
||||
struct bio *bp;
|
||||
struct ccd_s *cs;
|
||||
int count, s;
|
||||
int count;
|
||||
|
||||
cs = ccdfind(unit);
|
||||
s = splbio();
|
||||
cbp = ibp->bio_caller2;
|
||||
cs = cbp->cb_softc;
|
||||
bp = cbp->cb_obp;
|
||||
/*
|
||||
* If an error occured, report it. If this is a mirrored
|
||||
* configuration and the first of two possible reads, do not
|
||||
@ -980,7 +889,8 @@ ccdiodone(struct bio *ibp)
|
||||
cbp->cb_buf.bio_error : EIO;
|
||||
}
|
||||
printf("ccd%d: error %d on component %d block %jd "
|
||||
"(ccd block %jd)%s\n", unit, bp->bio_error, cbp->cb_comp,
|
||||
"(ccd block %jd)%s\n", cs->sc_unit, bp->bio_error,
|
||||
cbp->cb_comp,
|
||||
(intmax_t)cbp->cb_buf.bio_blkno, (intmax_t)bp->bio_blkno,
|
||||
msg);
|
||||
}
|
||||
@ -1004,7 +914,6 @@ ccdiodone(struct bio *ibp)
|
||||
if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
|
||||
cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
|
||||
free(cbp, M_CCD);
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -1019,7 +928,6 @@ ccdiodone(struct bio *ibp)
|
||||
CCDPF_MIRROR_DONE;
|
||||
BIO_STRATEGY(&cbp->cb_mirror->cb_buf);
|
||||
free(cbp, M_CCD);
|
||||
splx(s);
|
||||
return;
|
||||
} else {
|
||||
free(cbp->cb_mirror, M_CCD);
|
||||
@ -1051,42 +959,24 @@ ccdiodone(struct bio *ibp)
|
||||
bp->bio_resid = bp->bio_bcount;
|
||||
biofinish(bp, &cs->device_stats, 0);
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static int ccdioctltoo(int unit, u_long cmd, caddr_t data, int flag, struct thread *td);
|
||||
|
||||
static int
|
||||
ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
ccdctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
struct ccd_ioctl *ccio;
|
||||
u_int unit;
|
||||
dev_t dev2;
|
||||
int error;
|
||||
|
||||
if (dev->si_drv1 != dev) {
|
||||
switch (cmd) {
|
||||
case CCDIOCSET:
|
||||
case CCDIOCCLR:
|
||||
case CCDCONFINFO:
|
||||
case CCDCPPINFO:
|
||||
printf("*** WARNING: upgrade your ccdconfig(8) binary\n");
|
||||
printf("*** WARNING: continuing in 30 seconds\n");
|
||||
tsleep(dev, PRIBIO, "ccdbug", hz * 30);
|
||||
break;
|
||||
}
|
||||
return ccdioctltoo(dev, cmd, data, flag, td);
|
||||
}
|
||||
switch (cmd) {
|
||||
case CCDIOCSET:
|
||||
case CCDIOCCLR:
|
||||
ccio = (struct ccd_ioctl *)data;
|
||||
unit = ccio->ccio_size;
|
||||
dev2 = makedev(CDEV_MAJOR, unit * 8 + 2);
|
||||
if (!(dev2->si_flags & SI_NAMED)) {
|
||||
dev2 = make_dev(&ccd_cdevsw, unit * 8 + 2,
|
||||
UID_ROOT, GID_OPERATOR, 0640, "ccd%dc", unit);
|
||||
ccdnew(unit);
|
||||
}
|
||||
return (ccdioctltoo(dev2, cmd, data, flag, td));
|
||||
return (ccdioctltoo(unit, cmd, data, flag, td));
|
||||
case CCDCONFINFO:
|
||||
{
|
||||
int ninit = 0;
|
||||
@ -1126,6 +1016,7 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
struct ccdcpps *cpps = (struct ccdcpps *)data;
|
||||
char *ubuf = cpps->buffer;
|
||||
struct ccd_s *cs;
|
||||
|
||||
|
||||
error = copyin(ubuf, &unit, sizeof (unit));
|
||||
@ -1135,7 +1026,33 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
if (!IS_ALLOCATED(unit))
|
||||
return (ENXIO);
|
||||
dev2 = makedev(CDEV_MAJOR, unit * 8 + 2);
|
||||
return (ccdioctltoo(dev2, cmd, data, flag, td));
|
||||
cs = ccdfind(unit);
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
{
|
||||
int len = 0, i;
|
||||
struct ccdcpps *cpps = (struct ccdcpps *)data;
|
||||
char *ubuf = cpps->buffer;
|
||||
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i)
|
||||
len += cs->sc_cinfo[i].ci_pathlen;
|
||||
|
||||
if (cpps->size < len)
|
||||
return (ENOMEM);
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i) {
|
||||
len = cs->sc_cinfo[i].ci_pathlen;
|
||||
error = copyout(cs->sc_cinfo[i].ci_path, ubuf,
|
||||
len);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
ubuf += len;
|
||||
}
|
||||
return(copyout("", ubuf, 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
@ -1144,23 +1061,20 @@ ccdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
}
|
||||
|
||||
static int
|
||||
ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
ccdioctltoo(int unit, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
{
|
||||
int unit;
|
||||
int i, j, lookedup = 0, error = 0;
|
||||
int part, pmask, s;
|
||||
struct ccd_s *cs;
|
||||
struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
|
||||
struct ccdgeom *ccg;
|
||||
char **cpp;
|
||||
struct vnode **vpp;
|
||||
|
||||
unit = ccdunit(dev);
|
||||
if (!IS_ALLOCATED(unit))
|
||||
return (ENXIO);
|
||||
cs = ccdfind(unit);
|
||||
|
||||
switch (cmd) {
|
||||
case CCDIOCSET:
|
||||
if (cs == NULL)
|
||||
cs = ccdnew(unit);
|
||||
if (IS_INITED(cs))
|
||||
return (EBUSY);
|
||||
|
||||
@ -1250,13 +1164,25 @@ ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
*/
|
||||
ccio->ccio_unit = unit;
|
||||
ccio->ccio_size = cs->sc_size;
|
||||
ccdgetdisklabel(dev);
|
||||
cs->sc_disk = malloc(sizeof(struct disk), M_CCD, M_WAITOK);
|
||||
cs->sc_dev = disk_create(unit, cs->sc_disk, 0,
|
||||
&ccd_cdevsw, &ccddisk_cdevsw);
|
||||
cs->sc_dev->si_drv1 = cs;
|
||||
ccg = &cs->sc_geom;
|
||||
cs->sc_disk->d_sectorsize = ccg->ccg_secsize;
|
||||
cs->sc_disk->d_mediasize =
|
||||
cs->sc_size * (off_t)ccg->ccg_secsize;
|
||||
cs->sc_disk->d_fwsectors = ccg->ccg_nsectors;
|
||||
cs->sc_disk->d_fwheads = ccg->ccg_ntracks;
|
||||
|
||||
ccdunlock(cs);
|
||||
|
||||
break;
|
||||
|
||||
case CCDIOCCLR:
|
||||
if (cs == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
@ -1267,13 +1193,14 @@ ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
return (error);
|
||||
|
||||
/* Don't unconfigure if any other partitions are open */
|
||||
part = ccdpart(dev);
|
||||
pmask = (1 << part);
|
||||
if ((cs->sc_openmask & ~pmask)) {
|
||||
if (cs->sc_openmask) {
|
||||
ccdunlock(cs);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
disk_destroy(cs->sc_dev);
|
||||
free(cs->sc_disk, M_CCD);
|
||||
cs->sc_disk = NULL;
|
||||
/* Declare unit null and void (reset all flags) */
|
||||
cs->sc_flags &= (CCDF_WANTED | CCDF_LOCKED);
|
||||
|
||||
@ -1302,162 +1229,15 @@ ccdioctltoo(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
||||
devstat_remove_entry(&cs->device_stats);
|
||||
|
||||
/* This must be atomic. */
|
||||
s = splhigh();
|
||||
ccdunlock(cs);
|
||||
splx(s);
|
||||
ccddestroy(cs);
|
||||
|
||||
break;
|
||||
|
||||
case CCDCONFINFO:
|
||||
{
|
||||
int ninit = 0;
|
||||
struct ccdconf *conf = (struct ccdconf *)data;
|
||||
struct ccd_s *tmpcs;
|
||||
struct ccd_s *ubuf = conf->buffer;
|
||||
|
||||
/* XXX: LOCK(unique unit numbers) */
|
||||
LIST_FOREACH(tmpcs, &ccd_softc_list, list)
|
||||
if (IS_INITED(tmpcs))
|
||||
ninit++;
|
||||
|
||||
if (conf->size == 0) {
|
||||
conf->size = sizeof(struct ccd_s) * ninit;
|
||||
break;
|
||||
} else if ((conf->size / sizeof(struct ccd_s) != ninit) ||
|
||||
(conf->size % sizeof(struct ccd_s) != 0)) {
|
||||
/* XXX: UNLOCK(unique unit numbers) */
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
ubuf += ninit;
|
||||
LIST_FOREACH(tmpcs, &ccd_softc_list, list) {
|
||||
if (!IS_INITED(tmpcs))
|
||||
continue;
|
||||
error = copyout(tmpcs, --ubuf,
|
||||
sizeof(struct ccd_s));
|
||||
if (error != 0)
|
||||
/* XXX: UNLOCK(unique unit numbers) */
|
||||
return (error);
|
||||
}
|
||||
/* XXX: UNLOCK(unique unit numbers) */
|
||||
}
|
||||
break;
|
||||
|
||||
case CCDCPPINFO:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
{
|
||||
int len = 0;
|
||||
struct ccdcpps *cpps = (struct ccdcpps *)data;
|
||||
char *ubuf = cpps->buffer;
|
||||
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i)
|
||||
len += cs->sc_cinfo[i].ci_pathlen;
|
||||
|
||||
if (cpps->size == 0) {
|
||||
cpps->size = len;
|
||||
break;
|
||||
} else if (cpps->size < len) {
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
for (i = 0; i < cs->sc_nccdisks; ++i) {
|
||||
len = cs->sc_cinfo[i].ci_pathlen;
|
||||
error = copyout(cs->sc_cinfo[i].ci_path, ubuf,
|
||||
len);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
ubuf += len;
|
||||
}
|
||||
return(copyout("", ubuf, 1));
|
||||
}
|
||||
break;
|
||||
|
||||
case DIOCGDINFO:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
*(struct disklabel *)data = cs->sc_label;
|
||||
break;
|
||||
|
||||
case DIOCWDINFO:
|
||||
case DIOCSDINFO:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
if ((flag & FWRITE) == 0)
|
||||
return (EBADF);
|
||||
|
||||
if ((error = ccdlock(cs)) != 0)
|
||||
return (error);
|
||||
|
||||
cs->sc_flags |= CCDF_LABELLING;
|
||||
|
||||
error = setdisklabel(&cs->sc_label,
|
||||
(struct disklabel *)data, 0);
|
||||
if (error == 0) {
|
||||
if (cmd == DIOCWDINFO)
|
||||
error = writedisklabel(CCDLABELDEV(dev),
|
||||
&cs->sc_label);
|
||||
}
|
||||
|
||||
cs->sc_flags &= ~CCDF_LABELLING;
|
||||
|
||||
ccdunlock(cs);
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
break;
|
||||
|
||||
case DIOCWLABEL:
|
||||
if (!IS_INITED(cs))
|
||||
return (ENXIO);
|
||||
|
||||
if ((flag & FWRITE) == 0)
|
||||
return (EBADF);
|
||||
if (*(int *)data != 0)
|
||||
cs->sc_flags |= CCDF_WLABEL;
|
||||
else
|
||||
cs->sc_flags &= ~CCDF_WLABEL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (ENOTTY);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ccdsize(dev_t dev)
|
||||
{
|
||||
struct ccd_s *cs;
|
||||
int part, size;
|
||||
|
||||
if (dev->si_drv1 == dev)
|
||||
return (-1);
|
||||
|
||||
if (ccdopen(dev, 0, S_IFCHR, curthread))
|
||||
return (-1);
|
||||
|
||||
cs = ccdfind(ccdunit(dev));
|
||||
part = ccdpart(dev);
|
||||
|
||||
if (!IS_INITED(cs))
|
||||
return (-1);
|
||||
|
||||
if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
|
||||
size = -1;
|
||||
else
|
||||
size = cs->sc_label.d_partitions[part].p_size;
|
||||
|
||||
if (ccdclose(dev, 0, S_IFCHR, curthread))
|
||||
return (-1);
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup the provided name in the filesystem. If the file exists,
|
||||
@ -1500,74 +1280,7 @@ ccdlookup(char *path, struct thread *td, struct vnode **vpp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the disklabel from the ccd. If one is not present, fake one
|
||||
* up.
|
||||
*/
|
||||
static void
|
||||
ccdgetdisklabel(dev_t dev)
|
||||
{
|
||||
int unit = ccdunit(dev);
|
||||
struct ccd_s *cs = ccdfind(unit);
|
||||
char *errstring;
|
||||
struct disklabel *lp = &cs->sc_label;
|
||||
struct ccdgeom *ccg = &cs->sc_geom;
|
||||
|
||||
bzero(lp, sizeof(*lp));
|
||||
|
||||
lp->d_secperunit = cs->sc_size;
|
||||
lp->d_secsize = ccg->ccg_secsize;
|
||||
lp->d_nsectors = ccg->ccg_nsectors;
|
||||
lp->d_ntracks = ccg->ccg_ntracks;
|
||||
lp->d_ncylinders = ccg->ccg_ncylinders;
|
||||
lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
|
||||
|
||||
strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
|
||||
lp->d_type = DTYPE_CCD;
|
||||
strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
|
||||
lp->d_rpm = 3600;
|
||||
lp->d_interleave = 1;
|
||||
lp->d_flags = 0;
|
||||
|
||||
lp->d_partitions[RAW_PART].p_offset = 0;
|
||||
lp->d_partitions[RAW_PART].p_size = cs->sc_size;
|
||||
lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
|
||||
lp->d_npartitions = RAW_PART + 1;
|
||||
|
||||
lp->d_bbsize = BBSIZE; /* XXX */
|
||||
lp->d_sbsize = 0;
|
||||
|
||||
lp->d_magic = DISKMAGIC;
|
||||
lp->d_magic2 = DISKMAGIC;
|
||||
lp->d_checksum = dkcksum(&cs->sc_label);
|
||||
|
||||
/*
|
||||
* Call the generic disklabel extraction routine.
|
||||
*/
|
||||
errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label);
|
||||
if (errstring != NULL)
|
||||
ccdmakedisklabel(cs);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Take care of things one might want to take care of in the event
|
||||
* that a disklabel isn't present.
|
||||
*/
|
||||
static void
|
||||
ccdmakedisklabel(struct ccd_s *cs)
|
||||
{
|
||||
struct disklabel *lp = &cs->sc_label;
|
||||
|
||||
/*
|
||||
* For historical reasons, if there's no disklabel present
|
||||
* the raw partition must be marked FS_BSDFFS.
|
||||
*/
|
||||
lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
|
||||
|
||||
strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait interruptibly for an exclusive lock.
|
||||
*
|
||||
* XXX
|
||||
@ -1600,4 +1313,3 @@ ccdunlock(struct ccd_s *cs)
|
||||
wakeup(cs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,10 +170,11 @@ struct ccd_s {
|
||||
struct ccdiinfo *sc_itable; /* interleave table */
|
||||
struct devstat device_stats; /* device statistics */
|
||||
struct ccdgeom sc_geom; /* pseudo geometry info */
|
||||
struct disklabel sc_label; /* generic disk device info */
|
||||
int sc_openmask;
|
||||
int sc_pick; /* side of mirror picked */
|
||||
daddr_t sc_blk[2]; /* mirror localization */
|
||||
struct disk *sc_disk;
|
||||
struct cdev *sc_dev;
|
||||
};
|
||||
|
||||
/* sc_flags */
|
||||
|
Loading…
Reference in New Issue
Block a user