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(0x6); | |||
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 | } |