| File: | dev/softraid_raid1c.c |
| Warning: | line 295, column 10 Access to field 'cr_crp' results in a dereference of a null pointer (loaded from variable 'crwu') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: softraid_raid1c.c,v 1.6 2021/10/24 14:50:42 tobhe Exp $ */ | |||
| 2 | /* | |||
| 3 | * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us> | |||
| 4 | * Copyright (c) 2008 Hans-Joerg Hoexer <hshoexer@openbsd.org> | |||
| 5 | * Copyright (c) 2008 Damien Miller <djm@mindrot.org> | |||
| 6 | * Copyright (c) 2009 Joel Sing <jsing@openbsd.org> | |||
| 7 | * Copyright (c) 2020 Stefan Sperling <stsp@openbsd.org> | |||
| 8 | * | |||
| 9 | * Permission to use, copy, modify, and distribute this software for any | |||
| 10 | * purpose with or without fee is hereby granted, provided that the above | |||
| 11 | * copyright notice and this permission notice appear in all copies. | |||
| 12 | * | |||
| 13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 20 | */ | |||
| 21 | ||||
| 22 | #include "bio.h" | |||
| 23 | ||||
| 24 | #include <sys/param.h> | |||
| 25 | #include <sys/systm.h> | |||
| 26 | #include <sys/buf.h> | |||
| 27 | #include <sys/device.h> | |||
| 28 | #include <sys/ioctl.h> | |||
| 29 | #include <sys/malloc.h> | |||
| 30 | #include <sys/kernel.h> | |||
| 31 | #include <sys/disk.h> | |||
| 32 | #include <sys/rwlock.h> | |||
| 33 | #include <sys/queue.h> | |||
| 34 | #include <sys/fcntl.h> | |||
| 35 | #include <sys/mount.h> | |||
| 36 | #include <sys/sensors.h> | |||
| 37 | #include <sys/stat.h> | |||
| 38 | #include <sys/task.h> | |||
| 39 | #include <sys/conf.h> | |||
| 40 | #include <sys/uio.h> | |||
| 41 | ||||
| 42 | #include <crypto/cryptodev.h> | |||
| 43 | ||||
| 44 | #include <scsi/scsi_all.h> | |||
| 45 | #include <scsi/scsiconf.h> | |||
| 46 | #include <scsi/scsi_disk.h> | |||
| 47 | ||||
| 48 | #include <dev/softraidvar.h> | |||
| 49 | ||||
| 50 | /* RAID 1C functions. */ | |||
| 51 | int sr_raid1c_create(struct sr_discipline *, struct bioc_createraid *, | |||
| 52 | int, int64_t); | |||
| 53 | int sr_raid1c_add_offline_chunks(struct sr_discipline *, int); | |||
| 54 | int sr_raid1c_assemble(struct sr_discipline *, struct bioc_createraid *, | |||
| 55 | int, void *); | |||
| 56 | int sr_raid1c_alloc_resources(struct sr_discipline *); | |||
| 57 | void sr_raid1c_free_resources(struct sr_discipline *sd); | |||
| 58 | int sr_raid1c_ioctl(struct sr_discipline *sd, struct bioc_discipline *bd); | |||
| 59 | int sr_raid1c_meta_opt_handler(struct sr_discipline *, | |||
| 60 | struct sr_meta_opt_hdr *); | |||
| 61 | int sr_raid1c_rw(struct sr_workunit *); | |||
| 62 | int sr_raid1c_dev_rw(struct sr_workunit *, struct sr_crypto_wu *); | |||
| 63 | void sr_raid1c_done(struct sr_workunit *wu); | |||
| 64 | ||||
| 65 | /* RAID1 functions */ | |||
| 66 | extern int sr_raid1_init(struct sr_discipline *sd); | |||
| 67 | extern int sr_raid1_assemble(struct sr_discipline *, | |||
| 68 | struct bioc_createraid *, int, void *); | |||
| 69 | extern int sr_raid1_wu_done(struct sr_workunit *); | |||
| 70 | extern void sr_raid1_set_chunk_state(struct sr_discipline *, int, int); | |||
| 71 | extern void sr_raid1_set_vol_state(struct sr_discipline *); | |||
| 72 | ||||
| 73 | /* CRYPTO raid functions */ | |||
| 74 | extern struct sr_crypto_wu *sr_crypto_prepare(struct sr_workunit *, | |||
| 75 | struct sr_crypto *, int); | |||
| 76 | extern int sr_crypto_meta_create(struct sr_discipline *, | |||
| 77 | struct sr_crypto *, struct bioc_createraid *); | |||
| 78 | extern int sr_crypto_set_key(struct sr_discipline *, | |||
| 79 | struct sr_crypto *, struct bioc_createraid *, int, void *); | |||
| 80 | extern int sr_crypto_alloc_resources_internal(struct sr_discipline *, | |||
| 81 | struct sr_crypto *); | |||
| 82 | extern void sr_crypto_free_resources_internal(struct sr_discipline *, | |||
| 83 | struct sr_crypto *); | |||
| 84 | extern int sr_crypto_ioctl_internal(struct sr_discipline *, | |||
| 85 | struct sr_crypto *, struct bioc_discipline *); | |||
| 86 | int sr_crypto_meta_opt_handler_internal(struct sr_discipline *, | |||
| 87 | struct sr_crypto *, struct sr_meta_opt_hdr *); | |||
| 88 | void sr_crypto_done_internal(struct sr_workunit *, | |||
| 89 | struct sr_crypto *); | |||
| 90 | ||||
| 91 | /* Discipline initialisation. */ | |||
| 92 | void | |||
| 93 | sr_raid1c_discipline_init(struct sr_discipline *sd) | |||
| 94 | { | |||
| 95 | int i; | |||
| 96 | ||||
| 97 | /* Fill out discipline members. */ | |||
| 98 | sd->sd_wu_size = sizeof(struct sr_crypto_wu); | |||
| 99 | sd->sd_type = SR_MD_RAID1C10; | |||
| 100 | strlcpy(sd->sd_name, "RAID 1C", sizeof(sd->sd_name)); | |||
| 101 | sd->sd_capabilities = SR_CAP_SYSTEM_DISK0x00000001 | SR_CAP_AUTO_ASSEMBLE0x00000002 | | |||
| 102 | SR_CAP_REBUILD0x00000004 | SR_CAP_REDUNDANT0x00000010; | |||
| 103 | sd->sd_max_wu = SR_RAID1C_NOWU16; | |||
| 104 | ||||
| 105 | for (i = 0; i < SR_CRYPTO_MAXKEYS32; i++) | |||
| 106 | sd->mdssd_dis_specific.mdd_raid1c.sr1c_crypto.scr_sid[i] = (u_int64_t)-1; | |||
| 107 | ||||
| 108 | /* Setup discipline specific function pointers. */ | |||
| 109 | sd->sd_alloc_resources = sr_raid1c_alloc_resources; | |||
| 110 | sd->sd_assemble = sr_raid1c_assemble; | |||
| 111 | sd->sd_create = sr_raid1c_create; | |||
| 112 | sd->sd_free_resources = sr_raid1c_free_resources; | |||
| 113 | sd->sd_ioctl_handler = sr_raid1c_ioctl; | |||
| 114 | sd->sd_meta_opt_handler = sr_raid1c_meta_opt_handler; | |||
| 115 | sd->sd_scsi_rw = sr_raid1c_rw; | |||
| 116 | sd->sd_scsi_done = sr_raid1c_done; | |||
| 117 | sd->sd_scsi_wu_done = sr_raid1_wu_done; | |||
| 118 | sd->sd_set_chunk_state = sr_raid1_set_chunk_state; | |||
| 119 | sd->sd_set_vol_state = sr_raid1_set_vol_state; | |||
| 120 | } | |||
| 121 | ||||
| 122 | int | |||
| 123 | sr_raid1c_create(struct sr_discipline *sd, struct bioc_createraid *bc, | |||
| 124 | int no_chunk, int64_t coerced_size) | |||
| 125 | { | |||
| 126 | int rv; | |||
| 127 | ||||
| 128 | if (no_chunk < 2) { | |||
| 129 | sr_error(sd->sd_sc, "%s requires two or more chunks", | |||
| 130 | sd->sd_name); | |||
| 131 | return EINVAL22; | |||
| 132 | } | |||
| 133 | ||||
| 134 | sd->sd_meta->ssdi_sdd_invariant.ssd_size = coerced_size; | |||
| 135 | ||||
| 136 | rv = sr_raid1_init(sd); | |||
| 137 | if (rv) | |||
| 138 | return rv; | |||
| 139 | ||||
| 140 | return sr_crypto_meta_create(sd, &sd->mdssd_dis_specific.mdd_raid1c.sr1c_crypto, bc); | |||
| 141 | } | |||
| 142 | ||||
| 143 | int | |||
| 144 | sr_raid1c_add_offline_chunks(struct sr_discipline *sd, int no_chunk) | |||
| 145 | { | |||
| 146 | struct sr_chunk *ch_entry, *ch_prev; | |||
| 147 | struct sr_chunk **chunks; | |||
| 148 | int c; | |||
| 149 | ||||
| 150 | chunks = mallocarray(sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no, | |||
| 151 | sizeof(struct sr_chunk *), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 152 | ||||
| 153 | for (c = 0; c < no_chunk; c++) | |||
| 154 | chunks[c] = sd->sd_vol.sv_chunks[c]; | |||
| 155 | ||||
| 156 | for (c = no_chunk; c < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; c++) { | |||
| 157 | ch_prev = chunks[c - 1]; | |||
| 158 | ch_entry = malloc(sizeof(struct sr_chunk), M_DEVBUF2, | |||
| 159 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 160 | ch_entry->src_meta.scm_status = BIOC_SDOFFLINE0x01; | |||
| 161 | ch_entry->src_dev_mm = NODEV(dev_t)(-1); | |||
| 162 | SLIST_INSERT_AFTER(ch_prev, ch_entry, src_link)do { (ch_entry)->src_link.sle_next = (ch_prev)->src_link .sle_next; (ch_prev)->src_link.sle_next = (ch_entry); } while (0); | |||
| 163 | chunks[c] = ch_entry; | |||
| 164 | } | |||
| 165 | ||||
| 166 | free(sd->sd_vol.sv_chunks, M_DEVBUF2, | |||
| 167 | sizeof(struct sr_chunk *) * no_chunk); | |||
| 168 | sd->sd_vol.sv_chunks = chunks; | |||
| 169 | ||||
| 170 | return (0); | |||
| 171 | } | |||
| 172 | ||||
| 173 | int | |||
| 174 | sr_raid1c_assemble(struct sr_discipline *sd, struct bioc_createraid *bc, | |||
| 175 | int no_chunk, void *data) | |||
| 176 | { | |||
| 177 | struct sr_raid1c *mdd_raid1c = &sd->mdssd_dis_specific.mdd_raid1c; | |||
| 178 | int rv; | |||
| 179 | ||||
| 180 | /* Create NODEV place-holders for missing chunks. */ | |||
| 181 | if (no_chunk < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no) { | |||
| 182 | rv = sr_raid1c_add_offline_chunks(sd, no_chunk); | |||
| 183 | if (rv) | |||
| 184 | return (rv); | |||
| 185 | } | |||
| 186 | ||||
| 187 | rv = sr_raid1_assemble(sd, bc, no_chunk, NULL((void *)0)); | |||
| 188 | if (rv) | |||
| 189 | return (rv); | |||
| 190 | ||||
| 191 | return sr_crypto_set_key(sd, &mdd_raid1c->sr1c_crypto, bc, | |||
| 192 | no_chunk, data); | |||
| 193 | } | |||
| 194 | ||||
| 195 | int | |||
| 196 | sr_raid1c_ioctl(struct sr_discipline *sd, struct bioc_discipline *bd) | |||
| 197 | { | |||
| 198 | struct sr_raid1c *mdd_raid1c = &sd->mdssd_dis_specific.mdd_raid1c; | |||
| 199 | return sr_crypto_ioctl_internal(sd, &mdd_raid1c->sr1c_crypto, bd); | |||
| 200 | } | |||
| 201 | ||||
| 202 | int | |||
| 203 | sr_raid1c_alloc_resources(struct sr_discipline *sd) | |||
| 204 | { | |||
| 205 | struct sr_raid1c *mdd_raid1c = &sd->mdssd_dis_specific.mdd_raid1c; | |||
| 206 | return sr_crypto_alloc_resources_internal(sd, &mdd_raid1c->sr1c_crypto); | |||
| 207 | } | |||
| 208 | ||||
| 209 | void | |||
| 210 | sr_raid1c_free_resources(struct sr_discipline *sd) | |||
| 211 | { | |||
| 212 | struct sr_raid1c *mdd_raid1c = &sd->mdssd_dis_specific.mdd_raid1c; | |||
| 213 | sr_crypto_free_resources_internal(sd, &mdd_raid1c->sr1c_crypto); | |||
| 214 | } | |||
| 215 | ||||
| 216 | int | |||
| 217 | sr_raid1c_dev_rw(struct sr_workunit *wu, struct sr_crypto_wu *crwu) | |||
| 218 | { | |||
| 219 | struct sr_discipline *sd = wu->swu_dis; | |||
| 220 | struct scsi_xfer *xs = wu->swu_xs; | |||
| 221 | struct sr_raid1c *mdd_raid1c = &sd->mdssd_dis_specific.mdd_raid1c; | |||
| 222 | struct sr_ccb *ccb; | |||
| 223 | struct uio *uio; | |||
| 224 | struct sr_chunk *scp; | |||
| 225 | int ios, chunk, i, rt; | |||
| 226 | daddr_t blkno; | |||
| 227 | ||||
| 228 | blkno = wu->swu_blk_start; | |||
| 229 | ||||
| 230 | if (xs->flags & SCSI_DATA_IN0x00800) | |||
| 231 | ios = 1; | |||
| 232 | else | |||
| 233 | ios = sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; | |||
| 234 | ||||
| 235 | for (i = 0; i < ios; i++) { | |||
| 236 | if (xs->flags & SCSI_DATA_IN0x00800) { | |||
| 237 | rt = 0; | |||
| 238 | ragain: | |||
| 239 | /* interleave reads */ | |||
| 240 | chunk = mdd_raid1c->sr1c_raid1.sr1_counter++ % | |||
| 241 | sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no; | |||
| 242 | scp = sd->sd_vol.sv_chunks[chunk]; | |||
| 243 | switch (scp->src_meta.scm_status) { | |||
| 244 | case BIOC_SDONLINE0x00: | |||
| 245 | case BIOC_SDSCRUB0x06: | |||
| 246 | break; | |||
| 247 | ||||
| 248 | case BIOC_SDOFFLINE0x01: | |||
| 249 | case BIOC_SDREBUILD0x03: | |||
| 250 | case BIOC_SDHOTSPARE0x04: | |||
| 251 | if (rt++ < sd->sd_meta->ssdi_sdd_invariant.ssd_chunk_no) | |||
| 252 | goto ragain; | |||
| 253 | ||||
| 254 | /* FALLTHROUGH */ | |||
| 255 | default: | |||
| 256 | /* volume offline */ | |||
| 257 | printf("%s: is offline, cannot read\n", | |||
| 258 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname)); | |||
| 259 | goto bad; | |||
| 260 | } | |||
| 261 | } else { | |||
| 262 | /* writes go on all working disks */ | |||
| 263 | chunk = i; | |||
| 264 | scp = sd->sd_vol.sv_chunks[chunk]; | |||
| 265 | switch (scp->src_meta.scm_status) { | |||
| 266 | case BIOC_SDONLINE0x00: | |||
| 267 | if (ISSET(wu->swu_flags, SR_WUF_REBUILD)((wu->swu_flags) & ((1<<0)))) | |||
| 268 | continue; | |||
| 269 | break; | |||
| 270 | ||||
| 271 | case BIOC_SDSCRUB0x06: | |||
| 272 | case BIOC_SDREBUILD0x03: | |||
| 273 | break; | |||
| 274 | ||||
| 275 | case BIOC_SDHOTSPARE0x04: /* should never happen */ | |||
| 276 | case BIOC_SDOFFLINE0x01: | |||
| 277 | continue; | |||
| 278 | ||||
| 279 | default: | |||
| 280 | goto bad; | |||
| 281 | } | |||
| 282 | } | |||
| 283 | ||||
| 284 | ccb = sr_ccb_rw(sd, chunk, blkno, xs->datalen, xs->data, | |||
| 285 | xs->flags, 0); | |||
| 286 | if (!ccb) { | |||
| 287 | /* should never happen but handle more gracefully */ | |||
| 288 | printf("%s: %s: too many ccbs queued\n", | |||
| 289 | DEVNAME(sd->sd_sc)((sd->sd_sc)->sc_dev.dv_xname), | |||
| 290 | sd->sd_meta->ssd_devname); | |||
| 291 | goto bad; | |||
| 292 | } | |||
| 293 | if (!ISSET(xs->flags, SCSI_DATA_IN)((xs->flags) & (0x00800)) && | |||
| 294 | !ISSET(wu->swu_flags, SR_WUF_REBUILD)((wu->swu_flags) & ((1<<0)))) { | |||
| 295 | uio = crwu->cr_crp->crp_buf; | |||
| ||||
| 296 | ccb->ccb_buf.b_data = uio->uio_iov->iov_base; | |||
| 297 | ccb->ccb_opaque = crwu; | |||
| 298 | } | |||
| 299 | sr_wu_enqueue_ccb(wu, ccb); | |||
| 300 | } | |||
| 301 | ||||
| 302 | sr_schedule_wu(wu); | |||
| 303 | ||||
| 304 | return (0); | |||
| 305 | ||||
| 306 | bad: | |||
| 307 | return (EINVAL22); | |||
| 308 | } | |||
| 309 | ||||
| 310 | int | |||
| 311 | sr_raid1c_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt_hdr *om) | |||
| 312 | { | |||
| 313 | struct sr_raid1c *mdd_raid1c = &sd->mdssd_dis_specific.mdd_raid1c; | |||
| 314 | return sr_crypto_meta_opt_handler_internal(sd, | |||
| 315 | &mdd_raid1c->sr1c_crypto, om); | |||
| 316 | } | |||
| 317 | ||||
| 318 | int | |||
| 319 | sr_raid1c_rw(struct sr_workunit *wu) | |||
| 320 | { | |||
| 321 | struct sr_crypto_wu *crwu; | |||
| 322 | struct sr_raid1c *mdd_raid1c; | |||
| 323 | daddr_t blkno; | |||
| 324 | int rv, err; | |||
| 325 | int s; | |||
| 326 | ||||
| 327 | DNPRINTF(SR_D_DIS, "%s: sr_raid1c_rw wu %p\n", | |||
| 328 | DEVNAME(wu->swu_dis->sd_sc), wu); | |||
| 329 | ||||
| 330 | if (sr_validate_io(wu, &blkno, "sr_raid1c_rw")) | |||
| ||||
| 331 | return (1); | |||
| 332 | ||||
| 333 | if (ISSET(wu->swu_xs->flags, SCSI_DATA_OUT)((wu->swu_xs->flags) & (0x01000)) && | |||
| 334 | !ISSET(wu->swu_flags, SR_WUF_REBUILD)((wu->swu_flags) & ((1<<0)))) { | |||
| 335 | mdd_raid1c = &wu->swu_dis->mdssd_dis_specific.mdd_raid1c; | |||
| 336 | crwu = sr_crypto_prepare(wu, &mdd_raid1c->sr1c_crypto, 1); | |||
| 337 | rv = crypto_invoke(crwu->cr_crp); | |||
| 338 | ||||
| 339 | DNPRINTF(SR_D_INTR, "%s: sr_raid1c_rw: wu %p xs: %p\n", | |||
| 340 | DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs); | |||
| 341 | ||||
| 342 | if (rv) { | |||
| 343 | /* fail io */ | |||
| 344 | wu->swu_xs->error = XS_DRIVER_STUFFUP2; | |||
| 345 | s = splbio()splraise(0x3); | |||
| 346 | sr_scsi_done(wu->swu_dis, wu->swu_xs); | |||
| 347 | splx(s)spllower(s); | |||
| 348 | } | |||
| 349 | ||||
| 350 | if ((err = sr_raid1c_dev_rw(wu, crwu)) != 0) | |||
| 351 | return (err); | |||
| 352 | } else | |||
| 353 | rv = sr_raid1c_dev_rw(wu, NULL((void *)0)); | |||
| 354 | ||||
| 355 | return (rv); | |||
| 356 | } | |||
| 357 | ||||
| 358 | void | |||
| 359 | sr_raid1c_done(struct sr_workunit *wu) | |||
| 360 | { | |||
| 361 | struct sr_raid1c *mdd_raid1c = &wu->swu_dis->mdssd_dis_specific.mdd_raid1c; | |||
| 362 | sr_crypto_done_internal(wu, &mdd_raid1c->sr1c_crypto); | |||
| 363 | } |