diff options
author | cracauer <cracauer@FreeBSD.org> | 2006-04-13 20:35:31 +0000 |
---|---|---|
committer | cracauer <cracauer@FreeBSD.org> | 2006-04-13 20:35:31 +0000 |
commit | 452517900b740c1fd397a45dd60e21139e4ff858 (patch) | |
tree | e57019f9c8880c0c23b44e552f1fd6f71f1890a3 /sys/geom | |
parent | 65aeb543f38c35372f717f654ab9ddab09e77d7b (diff) | |
download | FreeBSD-src-452517900b740c1fd397a45dd60e21139e4ff858.zip FreeBSD-src-452517900b740c1fd397a45dd60e21139e4ff858.tar.gz |
Make CCD be able to read and write Linux software raids.
Supported for raid-0 with <n> disks, raid-1 with 2 disks.
Manpages have examples, warnings etc.
Test scripts on
http://www.cons.org/cracauer/ccdconfig-linux/
Reviewed by: alfred
Diffstat (limited to 'sys/geom')
-rw-r--r-- | sys/geom/geom_ccd.c | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/sys/geom/geom_ccd.c b/sys/geom/geom_ccd.c index fb66882..e31f23a 100644 --- a/sys/geom/geom_ccd.c +++ b/sys/geom/geom_ccd.c @@ -72,6 +72,8 @@ __FBSDID("$FreeBSD$"); /* sc_flags */ #define CCDF_UNIFORM 0x02 /* use LCCD of sizes for uniform interleave */ #define CCDF_MIRROR 0x04 /* use mirroring */ +#define CCDF_NO_OFFSET 0x08 /* do not leave space in front */ +#define CCDF_LINUX 0x10 /* use Linux compatibility mode */ /* Mask of user-settable ccd flags. */ #define CCDF_USERMASK (CCDF_UNIFORM|CCDF_MIRROR) @@ -136,6 +138,7 @@ struct ccd_s { u_int32_t sc_secsize; /* # bytes per sector */ int sc_pick; /* side of mirror picked */ daddr_t sc_blk[2]; /* mirror localization */ + u_int32_t sc_offset; /* actual offset used */ }; static g_start_t g_ccd_start; @@ -215,6 +218,20 @@ ccdinit(struct gctl_req *req, struct ccd_s *cs) maxsecsize = 0; minsize = 0; + + if (cs->sc_flags & CCDF_LINUX) { + cs->sc_offset = 0; + cs->sc_ileave *= 2; + if (cs->sc_flags & CCDF_MIRROR && cs->sc_ndisks != 2) + gctl_error(req, "Mirror mode for Linux raids is " + "only supported with 2 devices"); + } else { + if (cs->sc_flags & CCDF_NO_OFFSET) + cs->sc_offset = 0; + else + cs->sc_offset = CCD_OFFSET; + + } for (ix = 0; ix < cs->sc_ndisks; ix++) { ci = &cs->sc_cinfo[ix]; @@ -222,7 +239,7 @@ ccdinit(struct gctl_req *req, struct ccd_s *cs) sectorsize = ci->ci_provider->sectorsize; if (sectorsize > maxsecsize) maxsecsize = sectorsize; - size = mediasize / DEV_BSIZE - CCD_OFFSET; + size = mediasize / DEV_BSIZE - cs->sc_offset; /* Truncate to interleave boundary */ @@ -604,7 +621,7 @@ ccdbuffer(struct bio **cb, struct ccd_s *cs, struct bio *bp, daddr_t bn, caddr_t if (cbp == NULL) return (ENOMEM); cbp->bio_done = g_std_done; - cbp->bio_offset = dbtob(cbn + cboff + CCD_OFFSET); + cbp->bio_offset = dbtob(cbn + cboff + cs->sc_offset); cbp->bio_data = addr; if (cs->sc_ileave == 0) cbc = dbtob((off_t)(ci->ci_size - cbn)); @@ -740,6 +757,11 @@ g_ccd_create(struct gctl_req *req, struct g_class *mp) sc->sc_unit = *unit; sc->sc_ileave = *ileave; + if (gctl_get_param(req, "no_offset", NULL)) + sc->sc_flags |= CCDF_NO_OFFSET; + if (gctl_get_param(req, "linux", NULL)) + sc->sc_flags |= CCDF_LINUX; + if (gctl_get_param(req, "uniform", NULL)) sc->sc_flags |= CCDF_UNIFORM; if (gctl_get_param(req, "mirror", NULL)) |