Deleted Added
full compact
geom_slice.c (131408) geom_slice.c (131568)
1/*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/sys/geom/geom_slice.c 131408 2004-07-01 12:42:13Z pjd $");
37__FBSDID("$FreeBSD: head/sys/geom/geom_slice.c 131568 2004-07-04 13:44:48Z phk $");
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/malloc.h>
43#include <sys/bio.h>
44#include <sys/sysctl.h>
45#include <sys/proc.h>
46#include <sys/kthread.h>
47#include <sys/lock.h>
48#include <sys/mutex.h>
49#include <sys/errno.h>
50#include <sys/sbuf.h>
51#include <geom/geom.h>
52#include <geom/geom_slice.h>
53#include <machine/stdarg.h>
54
55static g_orphan_t g_slice_orphan;
56static g_access_t g_slice_access;
57static g_start_t g_slice_start;
58
59static struct g_slicer *
60g_slice_alloc(unsigned nslice, unsigned scsize)
61{
62 struct g_slicer *gsp;
63
64 gsp = g_malloc(sizeof *gsp, M_WAITOK | M_ZERO);
65 if (scsize > 0)
66 gsp->softc = g_malloc(scsize, M_WAITOK | M_ZERO);
67 else
68 gsp->softc = NULL;
69 gsp->slices = g_malloc(nslice * sizeof(struct g_slice),
70 M_WAITOK | M_ZERO);
71 gsp->nslice = nslice;
72 return (gsp);
73}
74
75static void
76g_slice_free(struct g_slicer *gsp)
77{
78
79 g_free(gsp->slices);
80 if (gsp->hotspot != NULL)
81 g_free(gsp->hotspot);
82 if (gsp->softc != NULL)
83 g_free(gsp->softc);
84 g_free(gsp);
85}
86
87static int
88g_slice_access(struct g_provider *pp, int dr, int dw, int de)
89{
90 int error;
91 u_int u;
92 struct g_geom *gp;
93 struct g_consumer *cp;
94 struct g_provider *pp2;
95 struct g_slicer *gsp;
96 struct g_slice *gsl, *gsl2;
97
98 gp = pp->geom;
99 cp = LIST_FIRST(&gp->consumer);
100 KASSERT (cp != NULL, ("g_slice_access but no consumer"));
101 gsp = gp->softc;
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/malloc.h>
43#include <sys/bio.h>
44#include <sys/sysctl.h>
45#include <sys/proc.h>
46#include <sys/kthread.h>
47#include <sys/lock.h>
48#include <sys/mutex.h>
49#include <sys/errno.h>
50#include <sys/sbuf.h>
51#include <geom/geom.h>
52#include <geom/geom_slice.h>
53#include <machine/stdarg.h>
54
55static g_orphan_t g_slice_orphan;
56static g_access_t g_slice_access;
57static g_start_t g_slice_start;
58
59static struct g_slicer *
60g_slice_alloc(unsigned nslice, unsigned scsize)
61{
62 struct g_slicer *gsp;
63
64 gsp = g_malloc(sizeof *gsp, M_WAITOK | M_ZERO);
65 if (scsize > 0)
66 gsp->softc = g_malloc(scsize, M_WAITOK | M_ZERO);
67 else
68 gsp->softc = NULL;
69 gsp->slices = g_malloc(nslice * sizeof(struct g_slice),
70 M_WAITOK | M_ZERO);
71 gsp->nslice = nslice;
72 return (gsp);
73}
74
75static void
76g_slice_free(struct g_slicer *gsp)
77{
78
79 g_free(gsp->slices);
80 if (gsp->hotspot != NULL)
81 g_free(gsp->hotspot);
82 if (gsp->softc != NULL)
83 g_free(gsp->softc);
84 g_free(gsp);
85}
86
87static int
88g_slice_access(struct g_provider *pp, int dr, int dw, int de)
89{
90 int error;
91 u_int u;
92 struct g_geom *gp;
93 struct g_consumer *cp;
94 struct g_provider *pp2;
95 struct g_slicer *gsp;
96 struct g_slice *gsl, *gsl2;
97
98 gp = pp->geom;
99 cp = LIST_FIRST(&gp->consumer);
100 KASSERT (cp != NULL, ("g_slice_access but no consumer"));
101 gsp = gp->softc;
102 gsl = &gsp->slices[pp->index];
103 for (u = 0; u < gsp->nslice; u++) {
104 gsl2 = &gsp->slices[u];
105 if (gsl2->length == 0)
106 continue;
107 if (u == pp->index)
108 continue;
109 if (gsl->offset + gsl->length <= gsl2->offset)
110 continue;
111 if (gsl2->offset + gsl2->length <= gsl->offset)
112 continue;
113 /* overlap */
114 pp2 = gsl2->provider;
115 if ((pp->acw + dw) > 0 && pp2->ace > 0)
116 return (EPERM);
117 if ((pp->ace + de) > 0 && pp2->acw > 0)
118 return (EPERM);
102 if (dr > 0 || dw > 0 || de > 0) {
103 gsl = &gsp->slices[pp->index];
104 for (u = 0; u < gsp->nslice; u++) {
105 gsl2 = &gsp->slices[u];
106 if (gsl2->length == 0)
107 continue;
108 if (u == pp->index)
109 continue;
110 if (gsl->offset + gsl->length <= gsl2->offset)
111 continue;
112 if (gsl2->offset + gsl2->length <= gsl->offset)
113 continue;
114 /* overlap */
115 pp2 = gsl2->provider;
116 if ((pp->acw + dw) > 0 && pp2->ace > 0)
117 return (EPERM);
118 if ((pp->ace + de) > 0 && pp2->acw > 0)
119 return (EPERM);
120 }
119 }
120 /* On first open, grab an extra "exclusive" bit */
121 if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
122 de++;
123 /* ... and let go of it on last close */
124 if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
125 de--;
126 error = g_access(cp, dr, dw, de);
127 return (error);
128}
129
130/*
131 * XXX: It should be possible to specify here if we should finish all of the
132 * XXX: bio, or only the non-hot bits. This would get messy if there were
133 * XXX: two hot spots in the same bio, so for now we simply finish off the
134 * XXX: entire bio. Modifying hot data on the way to disk is frowned on
135 * XXX: so making that considerably harder is not a bad idea anyway.
136 */
137void
138g_slice_finish_hot(struct bio *bp)
139{
140 struct bio *bp2;
141 struct g_geom *gp;
142 struct g_consumer *cp;
143 struct g_slicer *gsp;
144 struct g_slice *gsl;
145 int idx;
146
147 KASSERT(bp->bio_to != NULL,
148 ("NULL bio_to in g_slice_finish_hot(%p)", bp));
149 KASSERT(bp->bio_from != NULL,
150 ("NULL bio_from in g_slice_finish_hot(%p)", bp));
151 gp = bp->bio_to->geom;
152 gsp = gp->softc;
153 cp = LIST_FIRST(&gp->consumer);
154 KASSERT(cp != NULL, ("NULL consumer in g_slice_finish_hot(%p)", bp));
155 idx = bp->bio_to->index;
156 gsl = &gsp->slices[idx];
157
158 bp2 = g_clone_bio(bp);
159 if (bp2 == NULL) {
160 g_io_deliver(bp, ENOMEM);
161 return;
162 }
163 if (bp2->bio_offset + bp2->bio_length > gsl->length)
164 bp2->bio_length = gsl->length - bp2->bio_offset;
165 bp2->bio_done = g_std_done;
166 bp2->bio_offset += gsl->offset;
167 g_io_request(bp2, cp);
168 return;
169}
170
171static void
172g_slice_start(struct bio *bp)
173{
174 struct bio *bp2;
175 struct g_provider *pp;
176 struct g_geom *gp;
177 struct g_consumer *cp;
178 struct g_slicer *gsp;
179 struct g_slice *gsl;
180 struct g_slice_hot *ghp;
181 int idx, error;
182 u_int m_index;
183 off_t t;
184
185 pp = bp->bio_to;
186 gp = pp->geom;
187 gsp = gp->softc;
188 cp = LIST_FIRST(&gp->consumer);
189 idx = pp->index;
190 gsl = &gsp->slices[idx];
191 switch(bp->bio_cmd) {
192 case BIO_READ:
193 case BIO_WRITE:
194 case BIO_DELETE:
195 if (bp->bio_offset > gsl->length) {
196 g_io_deliver(bp, EINVAL); /* XXX: EWHAT ? */
197 return;
198 }
199 /*
200 * Check if we collide with any hot spaces, and call the
201 * method once if so.
202 */
203 t = bp->bio_offset + gsl->offset;
204 for (m_index = 0; m_index < gsp->nhotspot; m_index++) {
205 ghp = &gsp->hotspot[m_index];
206 if (t >= ghp->offset + ghp->length)
207 continue;
208 if (t + bp->bio_length <= ghp->offset)
209 continue;
210 switch(bp->bio_cmd) {
211 case BIO_READ: idx = ghp->ract; break;
212 case BIO_WRITE: idx = ghp->wact; break;
213 case BIO_DELETE: idx = ghp->dact; break;
214 }
215 switch(idx) {
216 case G_SLICE_HOT_ALLOW:
217 /* Fall out and continue normal processing */
218 continue;
219 case G_SLICE_HOT_DENY:
220 g_io_deliver(bp, EROFS);
221 return;
222 case G_SLICE_HOT_START:
223 error = gsp->start(bp);
224 if (error && error != EJUSTRETURN)
225 g_io_deliver(bp, error);
226 return;
227 case G_SLICE_HOT_CALL:
228 error = g_post_event(gsp->hot, bp, M_NOWAIT,
229 gp, NULL);
230 if (error)
231 g_io_deliver(bp, error);
232 return;
233 }
234 break;
235 }
236 bp2 = g_clone_bio(bp);
237 if (bp2 == NULL) {
238 g_io_deliver(bp, ENOMEM);
239 return;
240 }
241 if (bp2->bio_offset + bp2->bio_length > gsl->length)
242 bp2->bio_length = gsl->length - bp2->bio_offset;
243 bp2->bio_done = g_std_done;
244 bp2->bio_offset += gsl->offset;
245 g_io_request(bp2, cp);
246 return;
247 case BIO_GETATTR:
248 /* Give the real method a chance to override */
249 if (gsp->start != NULL && gsp->start(bp))
250 return;
251 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
252 struct g_kerneldump *gkd;
253
254 gkd = (struct g_kerneldump *)bp->bio_data;
255 gkd->offset += gsp->slices[idx].offset;
256 if (gkd->length > gsp->slices[idx].length)
257 gkd->length = gsp->slices[idx].length;
258 /* now, pass it on downwards... */
259 }
260 bp2 = g_clone_bio(bp);
261 if (bp2 == NULL) {
262 g_io_deliver(bp, ENOMEM);
263 return;
264 }
265 bp2->bio_done = g_std_done;
266 g_io_request(bp2, cp);
267 break;
268 default:
269 g_io_deliver(bp, EOPNOTSUPP);
270 return;
271 }
272}
273
274void
275g_slice_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
276{
277 struct g_slicer *gsp;
278
279 gsp = gp->softc;
280 if (indent == NULL) {
281 sbuf_printf(sb, " i %u", pp->index);
282 sbuf_printf(sb, " o %ju",
283 (uintmax_t)gsp->slices[pp->index].offset);
284 return;
285 }
286 if (pp != NULL) {
287 sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index);
288 sbuf_printf(sb, "%s<length>%ju</length>\n",
289 indent, (uintmax_t)gsp->slices[pp->index].length);
290 sbuf_printf(sb, "%s<seclength>%ju</seclength>\n", indent,
291 (uintmax_t)gsp->slices[pp->index].length / 512);
292 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
293 (uintmax_t)gsp->slices[pp->index].offset);
294 sbuf_printf(sb, "%s<secoffset>%ju</secoffset>\n", indent,
295 (uintmax_t)gsp->slices[pp->index].offset / 512);
296 }
297}
298
299int
300g_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...)
301{
302 struct g_provider *pp, *pp2;
303 struct g_slicer *gsp;
304 struct g_slice *gsl;
305 va_list ap;
306 struct sbuf *sb;
307 int acc;
308
309 g_trace(G_T_TOPOLOGY, "g_slice_config(%s, %d, %d)",
310 gp->name, idx, how);
311 g_topology_assert();
312 gsp = gp->softc;
313 if (idx >= gsp->nslice)
314 return(EINVAL);
315 gsl = &gsp->slices[idx];
316 pp = gsl->provider;
317 if (pp != NULL)
318 acc = pp->acr + pp->acw + pp->ace;
319 else
320 acc = 0;
321 if (acc != 0 && how != G_SLICE_CONFIG_FORCE) {
322 if (length < gsl->length)
323 return(EBUSY);
324 if (offset != gsl->offset)
325 return(EBUSY);
326 }
327 /* XXX: check offset + length <= MEDIASIZE */
328 if (how == G_SLICE_CONFIG_CHECK)
329 return (0);
330 gsl->length = length;
331 gsl->offset = offset;
332 gsl->sectorsize = sectorsize;
333 if (length == 0) {
334 if (pp == NULL)
335 return (0);
336 if (bootverbose)
337 printf("GEOM: Deconfigure %s\n", pp->name);
338 g_orphan_provider(pp, ENXIO);
339 gsl->provider = NULL;
340 gsp->nprovider--;
341 return (0);
342 }
343 if (pp != NULL) {
344 if (bootverbose)
345 printf("GEOM: Reconfigure %s, start %jd length %jd end %jd\n",
346 pp->name, (intmax_t)offset, (intmax_t)length,
347 (intmax_t)(offset + length - 1));
348 pp->mediasize = gsl->length;
349 return (0);
350 }
351 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
352 va_start(ap, fmt);
353 sbuf_vprintf(sb, fmt, ap);
354 va_end(ap);
355 sbuf_finish(sb);
356 pp = g_new_providerf(gp, sbuf_data(sb));
357 pp2 = LIST_FIRST(&gp->consumer)->provider;
358 pp->flags = pp2->flags & G_PF_CANDELETE;
359 if (pp2->stripesize > 0) {
360 pp->stripesize = pp2->stripesize;
361 pp->stripeoffset = (pp2->stripeoffset + offset) % pp->stripesize;
362 }
363 if (bootverbose)
364 printf("GEOM: Configure %s, start %jd length %jd end %jd\n",
365 pp->name, (intmax_t)offset, (intmax_t)length,
366 (intmax_t)(offset + length - 1));
367 pp->index = idx;
368 pp->mediasize = gsl->length;
369 pp->sectorsize = gsl->sectorsize;
370 gsl->provider = pp;
371 gsp->nprovider++;
372 g_error_provider(pp, 0);
373 sbuf_delete(sb);
374 return(0);
375}
376
377/*
378 * Configure "hotspots". A hotspot is a piece of the parent device which
379 * this particular slicer cares about for some reason. Typically because
380 * it contains meta-data used to configure the slicer.
381 * A hotspot is identified by its index number. The offset and length are
382 * relative to the parent device, and the three "?act" fields specify
383 * what action to take on BIO_READ, BIO_DELETE and BIO_WRITE.
384 *
385 * XXX: There may be a race relative to g_slice_start() here, if an existing
386 * XXX: hotspot is changed wile I/O is happening. Should this become a problem
387 * XXX: we can protect the hotspot stuff with a mutex.
388 */
389
390int
391g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact)
392{
393 struct g_slicer *gsp;
394 struct g_slice_hot *gsl, *gsl2;
395
396 g_trace(G_T_TOPOLOGY, "g_slice_conf_hot(%s, idx: %d, off: %jd, len: %jd)",
397 gp->name, idx, (intmax_t)offset, (intmax_t)length);
398 g_topology_assert();
399 gsp = gp->softc;
400 gsl = gsp->hotspot;
401 if(idx >= gsp->nhotspot) {
402 gsl2 = g_malloc((idx + 1) * sizeof *gsl2, M_WAITOK | M_ZERO);
403 if (gsp->hotspot != NULL)
404 bcopy(gsp->hotspot, gsl2, gsp->nhotspot * sizeof *gsl2);
405 gsp->hotspot = gsl2;
406 if (gsp->hotspot != NULL)
407 g_free(gsl);
408 gsl = gsl2;
409 gsp->nhotspot = idx + 1;
410 }
411 gsl[idx].offset = offset;
412 gsl[idx].length = length;
413 KASSERT(!((ract | dact | wact) & G_SLICE_HOT_START)
414 || gsp->start != NULL, ("G_SLICE_HOT_START but no slice->start"));
415 /* XXX: check that we _have_ a start function if HOT_START specified */
416 gsl[idx].ract = ract;
417 gsl[idx].dact = dact;
418 gsl[idx].wact = wact;
419 return (0);
420}
421
422void
423g_slice_spoiled(struct g_consumer *cp)
424{
425 struct g_geom *gp;
426 struct g_slicer *gsp;
427
428 g_topology_assert();
429 gp = cp->geom;
430 g_trace(G_T_TOPOLOGY, "g_slice_spoiled(%p/%s)", cp, gp->name);
431 gsp = gp->softc;
432 gp->softc = NULL;
433 g_slice_free(gsp);
434 g_wither_geom(gp, ENXIO);
435}
436
437int
438g_slice_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
439{
440
441 g_slice_spoiled(LIST_FIRST(&gp->consumer));
442 return (0);
443}
444
445struct g_geom *
446g_slice_new(struct g_class *mp, u_int slices, struct g_provider *pp, struct g_consumer **cpp, void *extrap, int extra, g_slice_start_t *start)
447{
448 struct g_geom *gp;
449 struct g_slicer *gsp;
450 struct g_consumer *cp;
451 void **vp;
452 int error;
453
454 g_topology_assert();
455 vp = (void **)extrap;
456 gp = g_new_geomf(mp, "%s", pp->name);
457 gsp = g_slice_alloc(slices, extra);
458 gsp->start = start;
459 gp->access = g_slice_access;
460 gp->orphan = g_slice_orphan;
461 gp->softc = gsp;
462 gp->start = g_slice_start;
463 gp->spoiled = g_slice_spoiled;
464 gp->dumpconf = g_slice_dumpconf;
465 if (gp->class->destroy_geom == NULL)
466 gp->class->destroy_geom = g_slice_destroy_geom;
467 cp = g_new_consumer(gp);
468 error = g_attach(cp, pp);
469 if (error == 0)
470 error = g_access(cp, 1, 0, 0);
471 if (error) {
472 g_wither_geom(gp, ENXIO);
473 return (NULL);
474 }
475 if (extrap != NULL)
476 *vp = gsp->softc;
477 *cpp = cp;
478 return (gp);
479}
480
481static void
482g_slice_orphan(struct g_consumer *cp)
483{
484
485 g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name);
486 g_topology_assert();
487 KASSERT(cp->provider->error != 0,
488 ("g_slice_orphan with error == 0"));
489
490 /* XXX: Not good enough we leak the softc and its suballocations */
491 g_slice_free(cp->geom->softc);
492 g_wither_geom(cp->geom, cp->provider->error);
493}
121 }
122 /* On first open, grab an extra "exclusive" bit */
123 if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
124 de++;
125 /* ... and let go of it on last close */
126 if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
127 de--;
128 error = g_access(cp, dr, dw, de);
129 return (error);
130}
131
132/*
133 * XXX: It should be possible to specify here if we should finish all of the
134 * XXX: bio, or only the non-hot bits. This would get messy if there were
135 * XXX: two hot spots in the same bio, so for now we simply finish off the
136 * XXX: entire bio. Modifying hot data on the way to disk is frowned on
137 * XXX: so making that considerably harder is not a bad idea anyway.
138 */
139void
140g_slice_finish_hot(struct bio *bp)
141{
142 struct bio *bp2;
143 struct g_geom *gp;
144 struct g_consumer *cp;
145 struct g_slicer *gsp;
146 struct g_slice *gsl;
147 int idx;
148
149 KASSERT(bp->bio_to != NULL,
150 ("NULL bio_to in g_slice_finish_hot(%p)", bp));
151 KASSERT(bp->bio_from != NULL,
152 ("NULL bio_from in g_slice_finish_hot(%p)", bp));
153 gp = bp->bio_to->geom;
154 gsp = gp->softc;
155 cp = LIST_FIRST(&gp->consumer);
156 KASSERT(cp != NULL, ("NULL consumer in g_slice_finish_hot(%p)", bp));
157 idx = bp->bio_to->index;
158 gsl = &gsp->slices[idx];
159
160 bp2 = g_clone_bio(bp);
161 if (bp2 == NULL) {
162 g_io_deliver(bp, ENOMEM);
163 return;
164 }
165 if (bp2->bio_offset + bp2->bio_length > gsl->length)
166 bp2->bio_length = gsl->length - bp2->bio_offset;
167 bp2->bio_done = g_std_done;
168 bp2->bio_offset += gsl->offset;
169 g_io_request(bp2, cp);
170 return;
171}
172
173static void
174g_slice_start(struct bio *bp)
175{
176 struct bio *bp2;
177 struct g_provider *pp;
178 struct g_geom *gp;
179 struct g_consumer *cp;
180 struct g_slicer *gsp;
181 struct g_slice *gsl;
182 struct g_slice_hot *ghp;
183 int idx, error;
184 u_int m_index;
185 off_t t;
186
187 pp = bp->bio_to;
188 gp = pp->geom;
189 gsp = gp->softc;
190 cp = LIST_FIRST(&gp->consumer);
191 idx = pp->index;
192 gsl = &gsp->slices[idx];
193 switch(bp->bio_cmd) {
194 case BIO_READ:
195 case BIO_WRITE:
196 case BIO_DELETE:
197 if (bp->bio_offset > gsl->length) {
198 g_io_deliver(bp, EINVAL); /* XXX: EWHAT ? */
199 return;
200 }
201 /*
202 * Check if we collide with any hot spaces, and call the
203 * method once if so.
204 */
205 t = bp->bio_offset + gsl->offset;
206 for (m_index = 0; m_index < gsp->nhotspot; m_index++) {
207 ghp = &gsp->hotspot[m_index];
208 if (t >= ghp->offset + ghp->length)
209 continue;
210 if (t + bp->bio_length <= ghp->offset)
211 continue;
212 switch(bp->bio_cmd) {
213 case BIO_READ: idx = ghp->ract; break;
214 case BIO_WRITE: idx = ghp->wact; break;
215 case BIO_DELETE: idx = ghp->dact; break;
216 }
217 switch(idx) {
218 case G_SLICE_HOT_ALLOW:
219 /* Fall out and continue normal processing */
220 continue;
221 case G_SLICE_HOT_DENY:
222 g_io_deliver(bp, EROFS);
223 return;
224 case G_SLICE_HOT_START:
225 error = gsp->start(bp);
226 if (error && error != EJUSTRETURN)
227 g_io_deliver(bp, error);
228 return;
229 case G_SLICE_HOT_CALL:
230 error = g_post_event(gsp->hot, bp, M_NOWAIT,
231 gp, NULL);
232 if (error)
233 g_io_deliver(bp, error);
234 return;
235 }
236 break;
237 }
238 bp2 = g_clone_bio(bp);
239 if (bp2 == NULL) {
240 g_io_deliver(bp, ENOMEM);
241 return;
242 }
243 if (bp2->bio_offset + bp2->bio_length > gsl->length)
244 bp2->bio_length = gsl->length - bp2->bio_offset;
245 bp2->bio_done = g_std_done;
246 bp2->bio_offset += gsl->offset;
247 g_io_request(bp2, cp);
248 return;
249 case BIO_GETATTR:
250 /* Give the real method a chance to override */
251 if (gsp->start != NULL && gsp->start(bp))
252 return;
253 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
254 struct g_kerneldump *gkd;
255
256 gkd = (struct g_kerneldump *)bp->bio_data;
257 gkd->offset += gsp->slices[idx].offset;
258 if (gkd->length > gsp->slices[idx].length)
259 gkd->length = gsp->slices[idx].length;
260 /* now, pass it on downwards... */
261 }
262 bp2 = g_clone_bio(bp);
263 if (bp2 == NULL) {
264 g_io_deliver(bp, ENOMEM);
265 return;
266 }
267 bp2->bio_done = g_std_done;
268 g_io_request(bp2, cp);
269 break;
270 default:
271 g_io_deliver(bp, EOPNOTSUPP);
272 return;
273 }
274}
275
276void
277g_slice_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
278{
279 struct g_slicer *gsp;
280
281 gsp = gp->softc;
282 if (indent == NULL) {
283 sbuf_printf(sb, " i %u", pp->index);
284 sbuf_printf(sb, " o %ju",
285 (uintmax_t)gsp->slices[pp->index].offset);
286 return;
287 }
288 if (pp != NULL) {
289 sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index);
290 sbuf_printf(sb, "%s<length>%ju</length>\n",
291 indent, (uintmax_t)gsp->slices[pp->index].length);
292 sbuf_printf(sb, "%s<seclength>%ju</seclength>\n", indent,
293 (uintmax_t)gsp->slices[pp->index].length / 512);
294 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
295 (uintmax_t)gsp->slices[pp->index].offset);
296 sbuf_printf(sb, "%s<secoffset>%ju</secoffset>\n", indent,
297 (uintmax_t)gsp->slices[pp->index].offset / 512);
298 }
299}
300
301int
302g_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...)
303{
304 struct g_provider *pp, *pp2;
305 struct g_slicer *gsp;
306 struct g_slice *gsl;
307 va_list ap;
308 struct sbuf *sb;
309 int acc;
310
311 g_trace(G_T_TOPOLOGY, "g_slice_config(%s, %d, %d)",
312 gp->name, idx, how);
313 g_topology_assert();
314 gsp = gp->softc;
315 if (idx >= gsp->nslice)
316 return(EINVAL);
317 gsl = &gsp->slices[idx];
318 pp = gsl->provider;
319 if (pp != NULL)
320 acc = pp->acr + pp->acw + pp->ace;
321 else
322 acc = 0;
323 if (acc != 0 && how != G_SLICE_CONFIG_FORCE) {
324 if (length < gsl->length)
325 return(EBUSY);
326 if (offset != gsl->offset)
327 return(EBUSY);
328 }
329 /* XXX: check offset + length <= MEDIASIZE */
330 if (how == G_SLICE_CONFIG_CHECK)
331 return (0);
332 gsl->length = length;
333 gsl->offset = offset;
334 gsl->sectorsize = sectorsize;
335 if (length == 0) {
336 if (pp == NULL)
337 return (0);
338 if (bootverbose)
339 printf("GEOM: Deconfigure %s\n", pp->name);
340 g_orphan_provider(pp, ENXIO);
341 gsl->provider = NULL;
342 gsp->nprovider--;
343 return (0);
344 }
345 if (pp != NULL) {
346 if (bootverbose)
347 printf("GEOM: Reconfigure %s, start %jd length %jd end %jd\n",
348 pp->name, (intmax_t)offset, (intmax_t)length,
349 (intmax_t)(offset + length - 1));
350 pp->mediasize = gsl->length;
351 return (0);
352 }
353 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
354 va_start(ap, fmt);
355 sbuf_vprintf(sb, fmt, ap);
356 va_end(ap);
357 sbuf_finish(sb);
358 pp = g_new_providerf(gp, sbuf_data(sb));
359 pp2 = LIST_FIRST(&gp->consumer)->provider;
360 pp->flags = pp2->flags & G_PF_CANDELETE;
361 if (pp2->stripesize > 0) {
362 pp->stripesize = pp2->stripesize;
363 pp->stripeoffset = (pp2->stripeoffset + offset) % pp->stripesize;
364 }
365 if (bootverbose)
366 printf("GEOM: Configure %s, start %jd length %jd end %jd\n",
367 pp->name, (intmax_t)offset, (intmax_t)length,
368 (intmax_t)(offset + length - 1));
369 pp->index = idx;
370 pp->mediasize = gsl->length;
371 pp->sectorsize = gsl->sectorsize;
372 gsl->provider = pp;
373 gsp->nprovider++;
374 g_error_provider(pp, 0);
375 sbuf_delete(sb);
376 return(0);
377}
378
379/*
380 * Configure "hotspots". A hotspot is a piece of the parent device which
381 * this particular slicer cares about for some reason. Typically because
382 * it contains meta-data used to configure the slicer.
383 * A hotspot is identified by its index number. The offset and length are
384 * relative to the parent device, and the three "?act" fields specify
385 * what action to take on BIO_READ, BIO_DELETE and BIO_WRITE.
386 *
387 * XXX: There may be a race relative to g_slice_start() here, if an existing
388 * XXX: hotspot is changed wile I/O is happening. Should this become a problem
389 * XXX: we can protect the hotspot stuff with a mutex.
390 */
391
392int
393g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int ract, int dact, int wact)
394{
395 struct g_slicer *gsp;
396 struct g_slice_hot *gsl, *gsl2;
397
398 g_trace(G_T_TOPOLOGY, "g_slice_conf_hot(%s, idx: %d, off: %jd, len: %jd)",
399 gp->name, idx, (intmax_t)offset, (intmax_t)length);
400 g_topology_assert();
401 gsp = gp->softc;
402 gsl = gsp->hotspot;
403 if(idx >= gsp->nhotspot) {
404 gsl2 = g_malloc((idx + 1) * sizeof *gsl2, M_WAITOK | M_ZERO);
405 if (gsp->hotspot != NULL)
406 bcopy(gsp->hotspot, gsl2, gsp->nhotspot * sizeof *gsl2);
407 gsp->hotspot = gsl2;
408 if (gsp->hotspot != NULL)
409 g_free(gsl);
410 gsl = gsl2;
411 gsp->nhotspot = idx + 1;
412 }
413 gsl[idx].offset = offset;
414 gsl[idx].length = length;
415 KASSERT(!((ract | dact | wact) & G_SLICE_HOT_START)
416 || gsp->start != NULL, ("G_SLICE_HOT_START but no slice->start"));
417 /* XXX: check that we _have_ a start function if HOT_START specified */
418 gsl[idx].ract = ract;
419 gsl[idx].dact = dact;
420 gsl[idx].wact = wact;
421 return (0);
422}
423
424void
425g_slice_spoiled(struct g_consumer *cp)
426{
427 struct g_geom *gp;
428 struct g_slicer *gsp;
429
430 g_topology_assert();
431 gp = cp->geom;
432 g_trace(G_T_TOPOLOGY, "g_slice_spoiled(%p/%s)", cp, gp->name);
433 gsp = gp->softc;
434 gp->softc = NULL;
435 g_slice_free(gsp);
436 g_wither_geom(gp, ENXIO);
437}
438
439int
440g_slice_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
441{
442
443 g_slice_spoiled(LIST_FIRST(&gp->consumer));
444 return (0);
445}
446
447struct g_geom *
448g_slice_new(struct g_class *mp, u_int slices, struct g_provider *pp, struct g_consumer **cpp, void *extrap, int extra, g_slice_start_t *start)
449{
450 struct g_geom *gp;
451 struct g_slicer *gsp;
452 struct g_consumer *cp;
453 void **vp;
454 int error;
455
456 g_topology_assert();
457 vp = (void **)extrap;
458 gp = g_new_geomf(mp, "%s", pp->name);
459 gsp = g_slice_alloc(slices, extra);
460 gsp->start = start;
461 gp->access = g_slice_access;
462 gp->orphan = g_slice_orphan;
463 gp->softc = gsp;
464 gp->start = g_slice_start;
465 gp->spoiled = g_slice_spoiled;
466 gp->dumpconf = g_slice_dumpconf;
467 if (gp->class->destroy_geom == NULL)
468 gp->class->destroy_geom = g_slice_destroy_geom;
469 cp = g_new_consumer(gp);
470 error = g_attach(cp, pp);
471 if (error == 0)
472 error = g_access(cp, 1, 0, 0);
473 if (error) {
474 g_wither_geom(gp, ENXIO);
475 return (NULL);
476 }
477 if (extrap != NULL)
478 *vp = gsp->softc;
479 *cpp = cp;
480 return (gp);
481}
482
483static void
484g_slice_orphan(struct g_consumer *cp)
485{
486
487 g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name);
488 g_topology_assert();
489 KASSERT(cp->provider->error != 0,
490 ("g_slice_orphan with error == 0"));
491
492 /* XXX: Not good enough we leak the softc and its suballocations */
493 g_slice_free(cp->geom->softc);
494 g_wither_geom(cp->geom, cp->provider->error);
495}