Add a RAID1C (raid1 + crypto) softraid(8) discipline.
authorstsp <stsp@openbsd.org>
Mon, 8 Feb 2021 11:20:03 +0000 (11:20 +0000)
committerstsp <stsp@openbsd.org>
Mon, 8 Feb 2021 11:20:03 +0000 (11:20 +0000)
The RAID1C discipline encrypts data like the CRYPTO discipline, and accepts
multiple chunks during creation and assembly like the RAID1 discipline.

To deal with failing disks a RAID1C volume may be assembled with a smaller
number of chunks than the volume was created with. The volume will then come
up in degraded state. If the volume is now detached and assembled again with
the correct number of chunks, any re-added chunks will require a rebuild.

Consequently, assembling RAID1C volumes requires careful attention to the
chunks passed via 'bioctl -l'.  If a chunk is accidentally omitted from the
command line during volume assembly, then this chunk will need to be rebuilt.

At least one known-good chunk is required in order to assemble the volume.

Like CRYPTO, RAID1C supports passphrase and key-disk authentication.
Key-disk based volumes are assembled automatically if the key disk is present
while the system is booting up.

Unlike CRYPTO and RAID1, there is no boot support for RAID1C yet.

RAID1C largely reuses existing code of RAID1 and CRYPTO disciplines.
At present RAID1C's discipline-specific data structure is shared with that
of the CRYPTO discipline to allow re-use of existing CRYPTO code. A custom
RAID1C data structure would require CRYPTO code to access struct sr_crypto
via a pointer instead of via a member field of struct sr_discipline.

ok jsing@

sbin/bioctl/bioctl.8
sbin/bioctl/bioctl.c
sys/conf/files
sys/dev/softraid.c
sys/dev/softraid_crypto.c
sys/dev/softraidvar.h

index 38b5958..5b324fd 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: bioctl.8,v 1.108 2020/10/30 13:55:48 schwarze Exp $
+.\"    $OpenBSD: bioctl.8,v 1.109 2021/02/08 11:20:03 stsp Exp $
 .\"
 .\" Copyright (c) 2004, 2005 Marco Peereboom
 .\"
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: October 30 2020 $
+.Dd $Mdocdate: February 8 2021 $
 .Dt BIOCTL 8
 .Os
 .Sh NAME
@@ -227,6 +227,9 @@ An encrypting discipline.
 .It Cm c
 CONCAT:
 A concatenating discipline.
+.It Cm 1C
+RAID 1 + CRYPTO:
+An encrypting and mirroring discipline.
 .El
 .Pp
 The CONCAT discipline requires a minimum of one chunk, RAID 0 and RAID 1
@@ -234,6 +237,11 @@ disciplines require a minimum of two chunks, RAID 5 requires a minimum
 of three chunks and the CRYPTO discipline requires exactly one chunk to
 be provided via
 .Fl l .
+.Pp
+The RAID 1C discipline requires a minimum of two chunks when a new volume
+is created, and a minimum of one chunk when an existing volume is assembled.
+Missing RAID 1C chunks will be marked as offline and must be rebuilt before
+they become part of the array again.
 .It Fl d
 Detach volume specified by
 .Ar device .
index 4cfc769..2d2146b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: bioctl.c,v 1.145 2020/10/30 13:55:48 schwarze Exp $ */
+/* $OpenBSD: bioctl.c,v 1.146 2021/02/08 11:20:03 stsp Exp $ */
 
 /*
  * Copyright (c) 2004, 2005 Marco Peereboom
@@ -131,7 +131,9 @@ main(int argc, char *argv[])
                        break;
                case 'c': /* create */
                        func |= BIOC_CREATERAID;
-                       if (isdigit((unsigned char)*optarg)) {
+                       if (strcmp(optarg, "1C") == 0) {
+                               cr_level = 0x1C;
+                       } else if (isdigit((unsigned char)*optarg)) {
                                cr_level = strtonum(optarg, 0, 10, &errstr);
                                if (errstr != NULL)
                                        errx(1, "Invalid RAID level");
@@ -498,6 +500,11 @@ bio_inq(char *name)
                                    volname, status, size, bv.bv_dev,
                                    percent, seconds);
                                break;
+                       case 0x1C:
+                               printf("%11s %-10s %14s %-7s RAID%X%s%s %s\n",
+                                   volname, status, size, bv.bv_dev,
+                                   bv.bv_level, percent, seconds, cache);
+                               break;
                        default:
                                printf("%11s %-10s %14s %-7s RAID%u%s%s %s\n",
                                    volname, status, size, bv.bv_dev,
@@ -847,6 +854,7 @@ bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
                min_disks = 3;
                break;
        case 'C':
+       case 0x1C:
                min_disks = 1;
                break;
        case 'c':
@@ -871,7 +879,7 @@ bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
        create.bc_flags = BIOC_SCDEVT | cflags;
        create.bc_key_disk = NODEV;
 
-       if (level == 'C' && key_disk == NULL) {
+       if ((level == 'C' || level == 0x1C) && key_disk == NULL) {
 
                memset(&kdfinfo, 0, sizeof(kdfinfo));
                memset(&kdfhint, 0, sizeof(kdfhint));
@@ -899,7 +907,7 @@ bio_createraid(u_int16_t level, char *dev_list, char *key_disk)
                create.bc_opaque_size = sizeof(kdfinfo);
                create.bc_opaque_flags = BIOC_SOIN;
 
-       } else if (level == 'C' && key_disk != NULL) {
+       } else if ((level == 'C' || level == 0x1C) && key_disk != NULL) {
 
                /* Get device number for key disk. */
                fd = opendev(key_disk, O_RDONLY, OPENDEV_BLCK, NULL);
index ff84e57..836b8a6 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.693 2021/01/28 14:53:20 visa Exp $
+#      $OpenBSD: files,v 1.694 2021/02/08 11:20:03 stsp Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -515,6 +515,7 @@ file        dev/softraid_raid0.c            softraid
 file   dev/softraid_raid1.c            softraid
 file   dev/softraid_raid5.c            softraid
 file   dev/softraid_raid6.c            softraid
+file   dev/softraid_raid1c.c           softraid & crypto
 
 # SPD Memory EEPROM
 device spdmem
index 2aac992..0ffaeb8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.417 2020/12/16 18:16:34 cheloha Exp $ */
+/* $OpenBSD: softraid.c,v 1.418 2021/02/08 11:20:03 stsp Exp $ */
 /*
  * Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us>
  * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
@@ -1397,7 +1397,7 @@ sr_boot_assembly(struct sr_softc *sc)
                 * key disk...
                 */
                bcr.bc_key_disk = NODEV;
-               if (bv->sbv_level == 'C') {
+               if (bv->sbv_level == 'C' || bv->sbv_level == 0x1C) {
                        SLIST_FOREACH(bc, &kdh, sbc_link) {
                                if (bcmp(&bc->sbc_metadata->ssdi.ssd_uuid,
                                    &bv->sbv_uuid,
@@ -1447,7 +1447,7 @@ sr_boot_assembly(struct sr_softc *sc)
                bcr.bc_flags = BIOC_SCDEVT |
                    (bv->sbv_flags & BIOC_SCNOAUTOASSEMBLE);
 
-               if (bv->sbv_level == 'C' &&
+               if ((bv->sbv_level == 'C' || bv->sbv_level == 0x1C) &&
                    bcmp(&sr_bootuuid, &bv->sbv_uuid, sizeof(sr_bootuuid)) == 0)
                        data = sr_bootkey;
 
@@ -2585,7 +2585,8 @@ sr_ioctl_vol(struct sr_softc *sc, struct bioc_vol *bv)
                bv->bv_nodisk = sd->sd_meta->ssdi.ssd_chunk_no;
 
 #ifdef CRYPTO
-               if (sd->sd_meta->ssdi.ssd_level == 'C' &&
+               if ((sd->sd_meta->ssdi.ssd_level == 'C' ||
+                   sd->sd_meta->ssdi.ssd_level == 0x1C) &&
                    sd->mds.mdd_crypto.key_disk != NULL)
                        bv->bv_nodisk++;
 #endif
@@ -2641,7 +2642,8 @@ sr_ioctl_disk(struct sr_softc *sc, struct bioc_disk *bd)
                        src = sd->sd_vol.sv_chunks[bd->bd_diskid];
 #ifdef CRYPTO
                else if (bd->bd_diskid == sd->sd_meta->ssdi.ssd_chunk_no &&
-                   sd->sd_meta->ssdi.ssd_level == 'C' &&
+                   (sd->sd_meta->ssdi.ssd_level == 'C' ||
+                   sd->sd_meta->ssdi.ssd_level == 0x1C) &&
                    sd->mds.mdd_crypto.key_disk != NULL)
                        src = sd->mds.mdd_crypto.key_disk;
 #endif
@@ -3398,7 +3400,11 @@ sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc,
        } else {
 
                /* Ensure we are assembling the correct # of chunks. */
-               if (sd->sd_meta->ssdi.ssd_chunk_no != no_chunk) {
+               if (bc->bc_level == 0x1C &&
+                   sd->sd_meta->ssdi.ssd_chunk_no > no_chunk) {
+                       sr_warn(sc, "trying to bring up %s degraded",
+                           sd->sd_meta->ssd_devname);
+               } else if (sd->sd_meta->ssdi.ssd_chunk_no != no_chunk) {
                        sr_error(sc, "volume chunk count does not match metadata "
                            "chunk count");
                        goto unwind;
@@ -3977,6 +3983,9 @@ sr_discipline_init(struct sr_discipline *sd, int level)
        case 'C':
                sr_crypto_discipline_init(sd);
                break;
+       case 0x1C:
+               sr_raid1c_discipline_init(sd);
+               break;
 #endif
        case 'c':
                sr_concat_discipline_init(sd);
index 7e2cc40..d143a23 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid_crypto.c,v 1.139 2020/07/13 00:06:22 kn Exp $ */
+/* $OpenBSD: softraid_crypto.c,v 1.140 2021/02/08 11:20:04 stsp Exp $ */
 /*
  * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
  * Copyright (c) 2008 Hans-Joerg Hoexer <hshoexer@openbsd.org>
 
 #include <dev/softraidvar.h>
 
-/*
- * The per-I/O data that we need to preallocate. We cannot afford to allow I/O
- * to start failing when memory pressure kicks in. We can store this in the WU
- * because we assert that only one ccb per WU will ever be active.
- */
-struct sr_crypto_wu {
-       struct sr_workunit               cr_wu;         /* Must be first. */
-       struct uio                       cr_uio;
-       struct iovec                     cr_iov;
-       struct cryptop                  *cr_crp;
-       void                            *cr_dmabuf;
-};
-
-
 struct sr_crypto_wu *sr_crypto_prepare(struct sr_workunit *, int);
 int            sr_crypto_create_keys(struct sr_discipline *);
 int            sr_crypto_get_kdf(struct bioc_createraid *,
@@ -79,6 +65,8 @@ int           sr_crypto_change_maskkey(struct sr_discipline *,
                    struct sr_crypto_kdfinfo *, struct sr_crypto_kdfinfo *);
 int            sr_crypto_create(struct sr_discipline *,
                    struct bioc_createraid *, int, int64_t);
+int            sr_crypto_meta_create(struct sr_discipline *,
+                   struct bioc_createraid *);
 int            sr_crypto_assemble(struct sr_discipline *,
                    struct bioc_createraid *, int, void *);
 int            sr_crypto_alloc_resources(struct sr_discipline *);
@@ -131,18 +119,34 @@ int
 sr_crypto_create(struct sr_discipline *sd, struct bioc_createraid *bc,
     int no_chunk, int64_t coerced_size)
 {
-       struct sr_meta_opt_item *omi;
-       int                     rv = EINVAL;
+       int rv = EINVAL;
 
        if (no_chunk != 1) {
                sr_error(sd->sd_sc, "%s requires exactly one chunk",
                    sd->sd_name);
-               goto done;
+               return (rv);
        }
 
-       if (coerced_size > SR_CRYPTO_MAXSIZE) {
+       sd->sd_meta->ssdi.ssd_size = coerced_size;
+
+       rv = sr_crypto_meta_create(sd, bc);
+       if (rv)
+               return (rv);
+
+       sd->sd_max_ccb_per_wu = no_chunk;
+       return (0);
+}
+
+int
+sr_crypto_meta_create(struct sr_discipline *sd, struct bioc_createraid *bc)
+{
+       struct sr_meta_opt_item *omi;
+       int                     rv = EINVAL;
+
+       if (sd->sd_meta->ssdi.ssd_size > SR_CRYPTO_MAXSIZE) {
                sr_error(sd->sd_sc, "%s exceeds maximum size (%lli > %llu)",
-                   sd->sd_name, coerced_size, SR_CRYPTO_MAXSIZE);
+                   sd->sd_name, sd->sd_meta->ssdi.ssd_size,
+                   SR_CRYPTO_MAXSIZE);
                goto done;
        }
 
@@ -184,12 +188,8 @@ sr_crypto_create(struct sr_discipline *sd, struct bioc_createraid *bc,
        if (!(bc->bc_flags & BIOC_SCNOAUTOASSEMBLE) && bc->bc_key_disk == NODEV)
                goto done;
 
-       sd->sd_meta->ssdi.ssd_size = coerced_size;
-
        sr_crypto_create_keys(sd);
 
-       sd->sd_max_ccb_per_wu = no_chunk;
-
        rv = 0;
 done:
        return (rv);
@@ -1183,6 +1183,9 @@ sr_crypto_done(struct sr_workunit *wu)
        struct sr_crypto_wu     *crwu;
        int                     s;
 
+       if (ISSET(wu->swu_flags, SR_WUF_REBUILD)) /* RAID 1C */
+               return;
+
        /* If this was a successful read, initiate decryption of the data. */
        if (ISSET(xs->flags, SCSI_DATA_IN) && xs->error == XS_NOERROR) {
                crwu = sr_crypto_prepare(wu, 0);
index 5490957..e66adcc 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraidvar.h,v 1.171 2020/07/22 13:16:04 krw Exp $ */
+/* $OpenBSD: softraidvar.h,v 1.172 2021/02/08 11:20:04 stsp Exp $ */
 /*
  * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us>
  * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
@@ -444,6 +444,19 @@ struct sr_raid6 {
 TAILQ_HEAD(sr_crypto_wu_head, sr_crypto_wu);
 #define SR_CRYPTO_NOWU         16
 
+/*
+ * The per-I/O data that we need to preallocate. We cannot afford to allow I/O
+ * to start failing when memory pressure kicks in. We can store this in the WU
+ * because we assert that only one ccb per WU will ever be active during crypto.
+ */
+struct sr_crypto_wu {
+       struct sr_workunit               cr_wu;         /* Must be first. */
+       struct uio                       cr_uio;
+       struct iovec                     cr_iov;
+       struct cryptop                  *cr_crp;
+       void                            *cr_dmabuf;
+};
+
 struct sr_crypto {
        struct sr_meta_crypto   *scr_meta;
        struct sr_chunk         *key_disk;
@@ -455,12 +468,18 @@ struct sr_crypto {
        u_int8_t                scr_key[SR_CRYPTO_MAXKEYS][SR_CRYPTO_KEYBYTES];
        u_int8_t                scr_maskkey[SR_CRYPTO_MAXKEYBYTES];
        u_int64_t               scr_sid[SR_CRYPTO_MAXKEYS];
+
+       struct sr_raid1         scr_raid1; /* for RAID1C */
 };
 
 #define SR_CONCAT_NOWU         16
 struct sr_concat {
 };
 
+/* RAID 1C */
+#define SR_RAID1C_NOWU         16
+/* Uses sr_crypto */
+
 struct sr_chunk {
        struct sr_meta_chunk    src_meta;       /* chunk meta data */
 
@@ -505,6 +524,7 @@ struct sr_discipline {
        /* SR_MD_RAID4 was 7. */
 #define        SR_MD_RAID6             8
 #define        SR_MD_CONCAT            9
+#define        SR_MD_RAID1C            10
        char                    sd_name[10];    /* human readable dis name */
        u_int16_t               sd_target;      /* scsibus target discipline uses */
 
@@ -707,6 +727,7 @@ void                        sr_raid5_discipline_init(struct sr_discipline *);
 void                   sr_raid6_discipline_init(struct sr_discipline *);
 void                   sr_crypto_discipline_init(struct sr_discipline *);
 void                   sr_concat_discipline_init(struct sr_discipline *);
+void                   sr_raid1c_discipline_init(struct sr_discipline *);
 
 /* Crypto discipline hooks. */
 int                    sr_crypto_get_kdf(struct bioc_createraid *,