mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-29 16:44:03 +00:00
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
This commit is contained in:
parent
447be3f1e4
commit
3f4f4a1465
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157740
@ -104,6 +104,8 @@ The flags are as follows:
|
||||
.Bd -literal -offset indent
|
||||
CCDF_UNIFORM 0x02 Use uniform interleave
|
||||
CCDF_MIRROR 0x04 Support mirroring
|
||||
CCDF_NO_OFFSET 0x08 Do not use an offset
|
||||
CCDF_LINUX 0x0A Linux md(4) compatibility
|
||||
.Ed
|
||||
.Pp
|
||||
The format in the
|
||||
@ -127,6 +129,10 @@ The component devices need to name partitions of type
|
||||
.Dq 4.2BSD
|
||||
as shown by
|
||||
.Xr disklabel 8 ) .
|
||||
.Pp
|
||||
If you want to use the Linux md(4) compatibility mode, please be sure
|
||||
to read the notes in
|
||||
.Xr ccd 4 .
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/ccd.conf -compact
|
||||
.It Pa /etc/ccd.conf
|
||||
@ -159,6 +165,16 @@ and assigned to ccd0.
|
||||
# ccdconfig ccd0 128 CCDF_MIRROR /dev/da8s2 /dev/da9s3
|
||||
.Ed
|
||||
.Pp
|
||||
The following are matching commands in Linux and FreeBSD to create a
|
||||
raid-0 in Linux and read it from FreeBSD.
|
||||
.Bd -literal
|
||||
# Create a raid-0 on Linux:
|
||||
mdadm --create --chunk=32 --level=0 --raid-devices=2 /dev/md0 \\
|
||||
/dev/hda1 /dev/hdb1
|
||||
# Make the raid-0 just created available on FreeBSD:
|
||||
ccdconfig -c /dev/ccd0 32 linux /dev/ad0s1 /dev/ad0s2
|
||||
.Ed
|
||||
.Pp
|
||||
When you create a new ccd disk you generally want to
|
||||
.Xr fdisk 8
|
||||
and
|
||||
|
@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#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 */
|
||||
|
||||
#include "pathnames.h"
|
||||
|
||||
@ -65,6 +67,10 @@ struct flagval {
|
||||
{ "uniform", CCDF_UNIFORM },
|
||||
{ "CCDF_MIRROR", CCDF_MIRROR },
|
||||
{ "mirror", CCDF_MIRROR },
|
||||
{ "CCDF_NO_OFFSET", CCDF_NO_OFFSET },
|
||||
{ "no_offset", CCDF_NO_OFFSET },
|
||||
{ "CCDF_LINUX", CCDF_LINUX },
|
||||
{ "linux", CCDF_LINUX },
|
||||
{ "none", 0 },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
@ -245,6 +251,10 @@ do_single(int argc, char **argv, int action)
|
||||
gctl_ro_param(grq, "uniform", -1, "");
|
||||
if (flags & CCDF_MIRROR)
|
||||
gctl_ro_param(grq, "mirror", -1, "");
|
||||
if (flags & CCDF_NO_OFFSET)
|
||||
gctl_ro_param(grq, "no_offset", -1, "");
|
||||
if (flags & CCDF_LINUX)
|
||||
gctl_ro_param(grq, "linux", -1, "");
|
||||
gctl_ro_param(grq, "nprovider", sizeof(argc), &argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
sprintf(buf1, "provider%d", i);
|
||||
|
@ -173,6 +173,34 @@ You cannot replace a disk in a mirrored
|
||||
.Nm
|
||||
partition without first backing up the partition, then replacing the disk,
|
||||
then restoring the partition.
|
||||
.Ss Linux compatibility
|
||||
The Linux compatibility mode does not try to read the label that Linux'
|
||||
md(4) driver leaves on the raw devices. You will have to give the order
|
||||
of devices and the interleave factor on your own. When in Linux
|
||||
compatibility mode, ccd will convert the interleave factor from Linux
|
||||
terminology. That means you give the same interleave factor that you
|
||||
gave as chunk size in Linux.
|
||||
.Pp
|
||||
If you have a Linux md(4) device in "legacy" mode, do not use the
|
||||
CCD_LINUX flag in
|
||||
.Xr ccdconfig 8 .
|
||||
Use the CCD_NO_OFFSET flag instead. In that case you have to convert
|
||||
the interleave factor on your own, usually it is Linux' chunk size
|
||||
multiplied by two.
|
||||
.Pp
|
||||
Using a Linux raid this way is potentially dangerous and can destroy
|
||||
the data in there. Since FreeBSD does not read the label used by
|
||||
Linux, changes in Linux might invalidate the compatibility layer.
|
||||
.Pp
|
||||
However, using this is reasonably safe if you test the compatibility
|
||||
before mounting a raid read-write for the first time. Just using
|
||||
ccdconfig without mounting does not write anything to the Linux raid.
|
||||
Then you do a fsck.ex2fs on the ccd device using the -n flag. You can
|
||||
mount the filesystem readonly to check files in there. If all this
|
||||
works, it is unlikely that there is a problem with ccd. Keep in mind
|
||||
that even when the Linux compatibility mode in ccd is working
|
||||
correctly, bugs in FreeBSD's ex2fs implementation would still destroy
|
||||
your data.
|
||||
.Sh WARNINGS
|
||||
If just one (or more) of the disks in a
|
||||
.Nm
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user