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 * $FreeBSD: head/sys/geom/geom_slice.c 107953 2002-12-16 22:33:27Z phk $
36 */
37
38
39#include <sys/param.h>
40#include <sys/stdint.h>
41#ifndef _KERNEL
42#include <stdio.h>
43#include <unistd.h>
44#include <stdlib.h>
45#include <signal.h>
46#include <string.h>
47#include <err.h>
48#else
49#include <sys/systm.h>
50#include <sys/kernel.h>
51#include <sys/malloc.h>
52#include <sys/bio.h>
53#include <sys/sysctl.h>
54#include <sys/proc.h>
55#include <sys/kthread.h>
56#include <sys/lock.h>
57#include <sys/mutex.h>
58#endif
59#include <sys/errno.h>
60#include <sys/sbuf.h>
61#include <geom/geom.h>
62#include <geom/geom_slice.h>
63#include <machine/stdarg.h>
64
65static g_orphan_t g_slice_orphan;
66static g_access_t g_slice_access;
67static g_start_t g_slice_start;
68
69static struct g_slicer *
70g_slice_init(unsigned nslice, unsigned scsize)
71{
72 struct g_slicer *gsp;
73
74 gsp = g_malloc(sizeof *gsp, M_WAITOK | M_ZERO);
75 gsp->softc = g_malloc(scsize, M_WAITOK | M_ZERO);
76 gsp->slices = g_malloc(nslice * sizeof(struct g_slice),
77 M_WAITOK | M_ZERO);
78 gsp->nslice = nslice;
79 return (gsp);
80}
81
82static int
83g_slice_access(struct g_provider *pp, int dr, int dw, int de)
84{
85 int error;
86 u_int u;
87 struct g_geom *gp;
88 struct g_consumer *cp;
89 struct g_provider *pp2;
90 struct g_slicer *gsp;
91 struct g_slice *gsl, *gsl2;
92
93 gp = pp->geom;
94 cp = LIST_FIRST(&gp->consumer);
95 KASSERT (cp != NULL, ("g_slice_access but no consumer"));
96 gsp = gp->softc;
97 gsl = &gsp->slices[pp->index];
98 for (u = 0; u < gsp->nslice; u++) {
99 gsl2 = &gsp->slices[u];
100 if (gsl2->length == 0)
101 continue;
102 if (u == pp->index)
103 continue;
104 if (gsl->offset + gsl->length <= gsl2->offset)
105 continue;
106 if (gsl2->offset + gsl2->length <= gsl->offset)
107 continue;
108 /* overlap */
109 pp2 = gsl2->provider;
110 if ((pp->acw + dw) > 0 && pp2->ace > 0)
111 return (EPERM);
112 if ((pp->ace + de) > 0 && pp2->acw > 0)
113 return (EPERM);
114 }
115 /* On first open, grab an extra "exclusive" bit */
116 if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
117 de++;
118 /* ... and let go of it on last close */
119 if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
120 de--;
121 error = g_access_rel(cp, dr, dw, de);
122 return (error);
123}
124
125void
126g_slice_finish_hot(struct bio *bp)
127{
128 struct bio *bp2;
129 struct g_geom *gp;
130 struct g_consumer *cp;
131 struct g_slicer *gsp;
132 struct g_slice *gsl;
133 int idx;
134
135 KASSERT(bp->bio_to != NULL, ("NULL bio_to in g_slice_finish_hot(%p)", bp));
136 KASSERT(bp->bio_from != NULL, ("NULL bio_from in g_slice_finish_hot(%p)", bp));
137 gp = bp->bio_to->geom;
138 gsp = gp->softc;
139 cp = LIST_FIRST(&gp->consumer);
140 KASSERT(cp != NULL, ("NULL consumer in g_slice_finish_hot(%p)", bp));
141 idx = bp->bio_to->index;
142 gsl = &gsp->slices[idx];
143
144 bp2 = g_clone_bio(bp);
145 if (bp2 == NULL) {
146 g_io_deliver(bp, ENOMEM);
147 return;
148 }
149 if (bp2->bio_offset + bp2->bio_length > gsl->length)
150 bp2->bio_length = gsl->length - bp2->bio_offset;
151 bp2->bio_done = g_std_done;
152 bp2->bio_offset += gsl->offset;
153 g_io_request(bp2, cp);
154 return;
155}
156
157static void
158g_slice_start(struct bio *bp)
159{
160 struct bio *bp2;
161 struct g_provider *pp;
162 struct g_geom *gp;
163 struct g_consumer *cp;
164 struct g_slicer *gsp;
165 struct g_slice *gsl, *gmp;
166 int idx, error;
167 u_int m_index;
168 off_t t;
169
170 pp = bp->bio_to;
171 gp = pp->geom;
172 gsp = gp->softc;
173 cp = LIST_FIRST(&gp->consumer);
174 idx = pp->index;
175 gsl = &gsp->slices[idx];
176 switch(bp->bio_cmd) {
177 case BIO_READ:
178 case BIO_WRITE:
179 case BIO_DELETE:
180 if (bp->bio_offset > gsl->length) {
181 g_io_deliver(bp, EINVAL); /* XXX: EWHAT ? */
182 return;
183 }
184 /*
185 * Check if we collide with any hot spaces, and call the
186 * method once if so.
187 */
188 t = bp->bio_offset + gsl->offset;
189 for (m_index = 0; m_index < gsp->nhot; m_index++) {
190 gmp = &gsp->hot[m_index];
191 if (t >= gmp->offset + gmp->length)
192 continue;
193 if (t + bp->bio_length <= gmp->offset)
194 continue;
195 error = gsp->start(bp);
196 if (error == EJUSTRETURN)
197 return;
198 else if (error) {
199 g_io_deliver(bp, error);
200 return;
201 }
202 break;
203 }
204 bp2 = g_clone_bio(bp);
205 if (bp2 == NULL) {
206 g_io_deliver(bp, ENOMEM);
207 return;
208 }
209 if (bp2->bio_offset + bp2->bio_length > gsl->length)
210 bp2->bio_length = gsl->length - bp2->bio_offset;
211 bp2->bio_done = g_std_done;
212 bp2->bio_offset += gsl->offset;
213 g_io_request(bp2, cp);
214 return;
215 case BIO_GETATTR:
216 case BIO_SETATTR:
217 /* Give the real method a chance to override */
218 if (gsp->start(bp))
219 return;
220 if (!strcmp("GEOM::frontstuff", bp->bio_attribute)) {
221 t = gsp->cfrontstuff;
222 if (gsp->frontstuff > t)
223 t = gsp->frontstuff;
224 t -= gsl->offset;
225 if (t < 0)
226 t = 0;
227 if (t > gsl->length)
228 t = gsl->length;
229 g_handleattr_off_t(bp, "GEOM::frontstuff", t);
230 return;
231 }
232#ifdef _KERNEL
233 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
234 struct g_kerneldump *gkd;
235
236 gkd = (struct g_kerneldump *)bp->bio_data;
237 gkd->offset += gsp->slices[idx].offset;
238 if (gkd->length > gsp->slices[idx].length)
239 gkd->length = gsp->slices[idx].length;
240 /* now, pass it on downwards... */
241 }
242#endif
243 bp2 = g_clone_bio(bp);
244 if (bp2 == NULL) {
245 g_io_deliver(bp, ENOMEM);
246 return;
247 }
248 bp2->bio_done = g_std_done;
249 g_io_request(bp2, cp);
250 break;
251 default:
252 g_io_deliver(bp, EOPNOTSUPP);
253 return;
254 }
255}
256
257void
258g_slice_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
259{
260 struct g_slicer *gsp;
261
262 gsp = gp->softc;
263 if (indent == NULL) {
264 sbuf_printf(sb, " i %u", pp->index);
265 sbuf_printf(sb, " o %ju",
266 (uintmax_t)gsp->slices[pp->index].offset);
267 return;
268 }
269 if (gp != NULL && (pp == NULL && cp == NULL)) {
270 sbuf_printf(sb, "%s<frontstuff>%ju</frontstuff>\n",
271 indent, (intmax_t)gsp->frontstuff);
272 }
273 if (pp != NULL) {
274 sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index);
275 sbuf_printf(sb, "%s<length>%ju</length>\n",
276 indent, (uintmax_t)gsp->slices[pp->index].length);
277 sbuf_printf(sb, "%s<seclength>%ju</seclength>\n", indent,
278 (uintmax_t)gsp->slices[pp->index].length / 512);
279 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
280 (uintmax_t)gsp->slices[pp->index].offset);
281 sbuf_printf(sb, "%s<secoffset>%ju</secoffset>\n", indent,
282 (uintmax_t)gsp->slices[pp->index].offset / 512);
283 }
284}
285
286int
287g_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...)
288{
289 struct g_provider *pp;
290 struct g_slicer *gsp;
291 struct g_slice *gsl;
292 va_list ap;
293 struct sbuf *sb;
294 int error, acc;
295
296 g_trace(G_T_TOPOLOGY, "g_slice_config(%s, %d, %d)",
297 gp->name, idx, how);
298 g_topology_assert();
299 gsp = gp->softc;
300 error = 0;
301 if (idx >= gsp->nslice)
302 return(EINVAL);
303 gsl = &gsp->slices[idx];
304 pp = gsl->provider;
305 if (pp != NULL)
306 acc = pp->acr + pp->acw + pp->ace;
307 else
308 acc = 0;
309 if (acc != 0 && how != G_SLICE_CONFIG_FORCE) {
310 if (length < gsl->length)
311 return(EBUSY);
312 if (offset != gsl->offset)
313 return(EBUSY);
314 }
315 /* XXX: check offset + length <= MEDIASIZE */
316 if (how == G_SLICE_CONFIG_CHECK)
317 return (0);
318 gsl->length = length;
319 gsl->offset = offset;
320 gsl->sectorsize = sectorsize;
321 if (length == 0) {
322 if (pp == NULL)
323 return (0);
324 if (bootverbose)
325 printf("GEOM: Deconfigure %s\n", pp->name);
326 g_orphan_provider(pp, ENXIO);
327 gsl->provider = NULL;
328 gsp->nprovider--;
329 return (0);
330 }
331 if (pp != NULL) {
332 if (bootverbose)
333 printf("GEOM: Reconfigure %s, start %jd length %jd end %jd\n",
334 pp->name, (intmax_t)offset, (intmax_t)length,
335 (intmax_t)(offset + length - 1));
336 pp->mediasize = gsl->length;
337 return (0);
338 }
339 va_start(ap, fmt);
340 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
341 sbuf_vprintf(sb, fmt, ap);
342 sbuf_finish(sb);
343 pp = g_new_providerf(gp, sbuf_data(sb));
344 if (bootverbose)
345 printf("GEOM: Configure %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->index = idx;
349 pp->mediasize = gsl->length;
350 pp->sectorsize = gsl->sectorsize;
351 gsl->provider = pp;
352 gsp->nprovider++;
353 g_error_provider(pp, 0);
354 sbuf_delete(sb);
355 return(0);
356}
357
358int
359g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length)
360{
361 struct g_slicer *gsp;
362 struct g_slice *gsl, *gsl2;
363
364 g_trace(G_T_TOPOLOGY, "g_slice_conf_hot()");
365 g_topology_assert();
366 gsp = gp->softc;
367 gsl = gsp->hot;
368 if(idx >= gsp->nhot) {
369 gsl2 = g_malloc((idx + 1) * sizeof *gsl2, M_WAITOK | M_ZERO);
370 if (gsp->hot != NULL)
371 bcopy(gsp->hot, gsl2, gsp->nhot * sizeof *gsl2);
372 gsp->hot = gsl2;
373 if (gsp->hot != NULL)
374 g_free(gsl);
375 gsl = gsl2;
376 gsp->nhot = idx + 1;
377 }
378 if (bootverbose)
379 printf("GEOM: Add %s hot[%d] start %jd length %jd end %jd\n",
380 gp->name, idx, (intmax_t)offset, (intmax_t)length,
381 (intmax_t)(offset + length - 1));
382 gsl[idx].offset = offset;
383 gsl[idx].length = length;
384 return (0);
385}
386
387struct g_provider *
388g_slice_addslice(struct g_geom *gp, int idx, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...)
389{
390 struct g_provider *pp;
391 struct g_slicer *gsp;
392 va_list ap;
393 struct sbuf *sb;
394
395 g_trace(G_T_TOPOLOGY, "g_slice_addslice()");
396 g_topology_assert();
397 gsp = gp->softc;
398 va_start(ap, fmt);
399 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
400 sbuf_vprintf(sb, fmt, ap);
401 sbuf_finish(sb);
402 pp = g_new_providerf(gp, sbuf_data(sb));
403
404 pp->index = idx;
405 gsp->slices[idx].length = length;
406 gsp->slices[idx].offset = offset;
407 gsp->slices[idx].provider = pp;
408 gsp->slices[idx].sectorsize = sectorsize;
409 pp->mediasize = gsp->slices[idx].length;
410 pp->sectorsize = gsp->slices[idx].sectorsize;
411 sbuf_delete(sb);
412 if (bootverbose)
413 printf("GEOM: Add %s, start %jd length %jd end %jd\n",
414 pp->name, (intmax_t)offset, (intmax_t)length,
415 (intmax_t)(offset + length - 1));
416 return(pp);
417}
418
419struct g_geom *
420g_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)
421{
422 struct g_geom *gp;
423 struct g_slicer *gsp;
424 struct g_consumer *cp;
425 void **vp;
426 int error, i;
427
428 g_topology_assert();
429 vp = (void **)extrap;
430 gp = g_new_geomf(mp, "%s", pp->name);
431 gsp = g_slice_init(slices, extra);
432 gsp->start = start;
433 gp->access = g_slice_access;
434 gp->orphan = g_slice_orphan;
435 gp->softc = gsp;
436 gp->start = g_slice_start;
437 gp->spoiled = g_std_spoiled;
438 gp->dumpconf = g_slice_dumpconf;
439 cp = g_new_consumer(gp);
440 error = g_attach(cp, pp);
441 if (error == 0)
442 error = g_access_rel(cp, 1, 0, 0);
443 if (error) {
444 if (cp->provider != NULL)
445 g_detach(cp);
446 g_destroy_consumer(cp);
447 g_free(gsp->slices);
448 g_free(gp->softc);
449 g_destroy_geom(gp);
450 return (NULL);
451 }
452 /* Find out if there are any magic bytes on the consumer */
453 i = sizeof gsp->cfrontstuff;
454 error = g_io_getattr("GEOM::frontstuff", cp, &i, &gsp->cfrontstuff);
455 if (error)
456 gsp->cfrontstuff = 0;
457 *vp = gsp->softc;
458 *cpp = cp;
459 return (gp);
460}
461
462static void
463g_slice_orphan(struct g_consumer *cp)
464{
465 struct g_geom *gp;
466 struct g_provider *pp;
467 int error;
468
469 g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name);
470 g_topology_assert();
471 KASSERT(cp->provider->error != 0,
472 ("g_slice_orphan with error == 0"));
473
474 gp = cp->geom;
475 /* XXX: Not good enough we leak the softc and its suballocations */
476 gp->flags |= G_GEOM_WITHER;
477 error = cp->provider->error;
478 LIST_FOREACH(pp, &gp->provider, provider)
479 g_orphan_provider(pp, error);
480 return;
481}
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 * $FreeBSD: head/sys/geom/geom_slice.c 107953 2002-12-16 22:33:27Z phk $
36 */
37
38
39#include <sys/param.h>
40#include <sys/stdint.h>
41#ifndef _KERNEL
42#include <stdio.h>
43#include <unistd.h>
44#include <stdlib.h>
45#include <signal.h>
46#include <string.h>
47#include <err.h>
48#else
49#include <sys/systm.h>
50#include <sys/kernel.h>
51#include <sys/malloc.h>
52#include <sys/bio.h>
53#include <sys/sysctl.h>
54#include <sys/proc.h>
55#include <sys/kthread.h>
56#include <sys/lock.h>
57#include <sys/mutex.h>
58#endif
59#include <sys/errno.h>
60#include <sys/sbuf.h>
61#include <geom/geom.h>
62#include <geom/geom_slice.h>
63#include <machine/stdarg.h>
64
65static g_orphan_t g_slice_orphan;
66static g_access_t g_slice_access;
67static g_start_t g_slice_start;
68
69static struct g_slicer *
70g_slice_init(unsigned nslice, unsigned scsize)
71{
72 struct g_slicer *gsp;
73
74 gsp = g_malloc(sizeof *gsp, M_WAITOK | M_ZERO);
75 gsp->softc = g_malloc(scsize, M_WAITOK | M_ZERO);
76 gsp->slices = g_malloc(nslice * sizeof(struct g_slice),
77 M_WAITOK | M_ZERO);
78 gsp->nslice = nslice;
79 return (gsp);
80}
81
82static int
83g_slice_access(struct g_provider *pp, int dr, int dw, int de)
84{
85 int error;
86 u_int u;
87 struct g_geom *gp;
88 struct g_consumer *cp;
89 struct g_provider *pp2;
90 struct g_slicer *gsp;
91 struct g_slice *gsl, *gsl2;
92
93 gp = pp->geom;
94 cp = LIST_FIRST(&gp->consumer);
95 KASSERT (cp != NULL, ("g_slice_access but no consumer"));
96 gsp = gp->softc;
97 gsl = &gsp->slices[pp->index];
98 for (u = 0; u < gsp->nslice; u++) {
99 gsl2 = &gsp->slices[u];
100 if (gsl2->length == 0)
101 continue;
102 if (u == pp->index)
103 continue;
104 if (gsl->offset + gsl->length <= gsl2->offset)
105 continue;
106 if (gsl2->offset + gsl2->length <= gsl->offset)
107 continue;
108 /* overlap */
109 pp2 = gsl2->provider;
110 if ((pp->acw + dw) > 0 && pp2->ace > 0)
111 return (EPERM);
112 if ((pp->ace + de) > 0 && pp2->acw > 0)
113 return (EPERM);
114 }
115 /* On first open, grab an extra "exclusive" bit */
116 if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
117 de++;
118 /* ... and let go of it on last close */
119 if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1)
120 de--;
121 error = g_access_rel(cp, dr, dw, de);
122 return (error);
123}
124
125void
126g_slice_finish_hot(struct bio *bp)
127{
128 struct bio *bp2;
129 struct g_geom *gp;
130 struct g_consumer *cp;
131 struct g_slicer *gsp;
132 struct g_slice *gsl;
133 int idx;
134
135 KASSERT(bp->bio_to != NULL, ("NULL bio_to in g_slice_finish_hot(%p)", bp));
136 KASSERT(bp->bio_from != NULL, ("NULL bio_from in g_slice_finish_hot(%p)", bp));
137 gp = bp->bio_to->geom;
138 gsp = gp->softc;
139 cp = LIST_FIRST(&gp->consumer);
140 KASSERT(cp != NULL, ("NULL consumer in g_slice_finish_hot(%p)", bp));
141 idx = bp->bio_to->index;
142 gsl = &gsp->slices[idx];
143
144 bp2 = g_clone_bio(bp);
145 if (bp2 == NULL) {
146 g_io_deliver(bp, ENOMEM);
147 return;
148 }
149 if (bp2->bio_offset + bp2->bio_length > gsl->length)
150 bp2->bio_length = gsl->length - bp2->bio_offset;
151 bp2->bio_done = g_std_done;
152 bp2->bio_offset += gsl->offset;
153 g_io_request(bp2, cp);
154 return;
155}
156
157static void
158g_slice_start(struct bio *bp)
159{
160 struct bio *bp2;
161 struct g_provider *pp;
162 struct g_geom *gp;
163 struct g_consumer *cp;
164 struct g_slicer *gsp;
165 struct g_slice *gsl, *gmp;
166 int idx, error;
167 u_int m_index;
168 off_t t;
169
170 pp = bp->bio_to;
171 gp = pp->geom;
172 gsp = gp->softc;
173 cp = LIST_FIRST(&gp->consumer);
174 idx = pp->index;
175 gsl = &gsp->slices[idx];
176 switch(bp->bio_cmd) {
177 case BIO_READ:
178 case BIO_WRITE:
179 case BIO_DELETE:
180 if (bp->bio_offset > gsl->length) {
181 g_io_deliver(bp, EINVAL); /* XXX: EWHAT ? */
182 return;
183 }
184 /*
185 * Check if we collide with any hot spaces, and call the
186 * method once if so.
187 */
188 t = bp->bio_offset + gsl->offset;
189 for (m_index = 0; m_index < gsp->nhot; m_index++) {
190 gmp = &gsp->hot[m_index];
191 if (t >= gmp->offset + gmp->length)
192 continue;
193 if (t + bp->bio_length <= gmp->offset)
194 continue;
195 error = gsp->start(bp);
196 if (error == EJUSTRETURN)
197 return;
198 else if (error) {
199 g_io_deliver(bp, error);
200 return;
201 }
202 break;
203 }
204 bp2 = g_clone_bio(bp);
205 if (bp2 == NULL) {
206 g_io_deliver(bp, ENOMEM);
207 return;
208 }
209 if (bp2->bio_offset + bp2->bio_length > gsl->length)
210 bp2->bio_length = gsl->length - bp2->bio_offset;
211 bp2->bio_done = g_std_done;
212 bp2->bio_offset += gsl->offset;
213 g_io_request(bp2, cp);
214 return;
215 case BIO_GETATTR:
216 case BIO_SETATTR:
217 /* Give the real method a chance to override */
218 if (gsp->start(bp))
219 return;
220 if (!strcmp("GEOM::frontstuff", bp->bio_attribute)) {
221 t = gsp->cfrontstuff;
222 if (gsp->frontstuff > t)
223 t = gsp->frontstuff;
224 t -= gsl->offset;
225 if (t < 0)
226 t = 0;
227 if (t > gsl->length)
228 t = gsl->length;
229 g_handleattr_off_t(bp, "GEOM::frontstuff", t);
230 return;
231 }
232#ifdef _KERNEL
233 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
234 struct g_kerneldump *gkd;
235
236 gkd = (struct g_kerneldump *)bp->bio_data;
237 gkd->offset += gsp->slices[idx].offset;
238 if (gkd->length > gsp->slices[idx].length)
239 gkd->length = gsp->slices[idx].length;
240 /* now, pass it on downwards... */
241 }
242#endif
243 bp2 = g_clone_bio(bp);
244 if (bp2 == NULL) {
245 g_io_deliver(bp, ENOMEM);
246 return;
247 }
248 bp2->bio_done = g_std_done;
249 g_io_request(bp2, cp);
250 break;
251 default:
252 g_io_deliver(bp, EOPNOTSUPP);
253 return;
254 }
255}
256
257void
258g_slice_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
259{
260 struct g_slicer *gsp;
261
262 gsp = gp->softc;
263 if (indent == NULL) {
264 sbuf_printf(sb, " i %u", pp->index);
265 sbuf_printf(sb, " o %ju",
266 (uintmax_t)gsp->slices[pp->index].offset);
267 return;
268 }
269 if (gp != NULL && (pp == NULL && cp == NULL)) {
270 sbuf_printf(sb, "%s<frontstuff>%ju</frontstuff>\n",
271 indent, (intmax_t)gsp->frontstuff);
272 }
273 if (pp != NULL) {
274 sbuf_printf(sb, "%s<index>%u</index>\n", indent, pp->index);
275 sbuf_printf(sb, "%s<length>%ju</length>\n",
276 indent, (uintmax_t)gsp->slices[pp->index].length);
277 sbuf_printf(sb, "%s<seclength>%ju</seclength>\n", indent,
278 (uintmax_t)gsp->slices[pp->index].length / 512);
279 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
280 (uintmax_t)gsp->slices[pp->index].offset);
281 sbuf_printf(sb, "%s<secoffset>%ju</secoffset>\n", indent,
282 (uintmax_t)gsp->slices[pp->index].offset / 512);
283 }
284}
285
286int
287g_slice_config(struct g_geom *gp, u_int idx, int how, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...)
288{
289 struct g_provider *pp;
290 struct g_slicer *gsp;
291 struct g_slice *gsl;
292 va_list ap;
293 struct sbuf *sb;
294 int error, acc;
295
296 g_trace(G_T_TOPOLOGY, "g_slice_config(%s, %d, %d)",
297 gp->name, idx, how);
298 g_topology_assert();
299 gsp = gp->softc;
300 error = 0;
301 if (idx >= gsp->nslice)
302 return(EINVAL);
303 gsl = &gsp->slices[idx];
304 pp = gsl->provider;
305 if (pp != NULL)
306 acc = pp->acr + pp->acw + pp->ace;
307 else
308 acc = 0;
309 if (acc != 0 && how != G_SLICE_CONFIG_FORCE) {
310 if (length < gsl->length)
311 return(EBUSY);
312 if (offset != gsl->offset)
313 return(EBUSY);
314 }
315 /* XXX: check offset + length <= MEDIASIZE */
316 if (how == G_SLICE_CONFIG_CHECK)
317 return (0);
318 gsl->length = length;
319 gsl->offset = offset;
320 gsl->sectorsize = sectorsize;
321 if (length == 0) {
322 if (pp == NULL)
323 return (0);
324 if (bootverbose)
325 printf("GEOM: Deconfigure %s\n", pp->name);
326 g_orphan_provider(pp, ENXIO);
327 gsl->provider = NULL;
328 gsp->nprovider--;
329 return (0);
330 }
331 if (pp != NULL) {
332 if (bootverbose)
333 printf("GEOM: Reconfigure %s, start %jd length %jd end %jd\n",
334 pp->name, (intmax_t)offset, (intmax_t)length,
335 (intmax_t)(offset + length - 1));
336 pp->mediasize = gsl->length;
337 return (0);
338 }
339 va_start(ap, fmt);
340 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
341 sbuf_vprintf(sb, fmt, ap);
342 sbuf_finish(sb);
343 pp = g_new_providerf(gp, sbuf_data(sb));
344 if (bootverbose)
345 printf("GEOM: Configure %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->index = idx;
349 pp->mediasize = gsl->length;
350 pp->sectorsize = gsl->sectorsize;
351 gsl->provider = pp;
352 gsp->nprovider++;
353 g_error_provider(pp, 0);
354 sbuf_delete(sb);
355 return(0);
356}
357
358int
359g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length)
360{
361 struct g_slicer *gsp;
362 struct g_slice *gsl, *gsl2;
363
364 g_trace(G_T_TOPOLOGY, "g_slice_conf_hot()");
365 g_topology_assert();
366 gsp = gp->softc;
367 gsl = gsp->hot;
368 if(idx >= gsp->nhot) {
369 gsl2 = g_malloc((idx + 1) * sizeof *gsl2, M_WAITOK | M_ZERO);
370 if (gsp->hot != NULL)
371 bcopy(gsp->hot, gsl2, gsp->nhot * sizeof *gsl2);
372 gsp->hot = gsl2;
373 if (gsp->hot != NULL)
374 g_free(gsl);
375 gsl = gsl2;
376 gsp->nhot = idx + 1;
377 }
378 if (bootverbose)
379 printf("GEOM: Add %s hot[%d] start %jd length %jd end %jd\n",
380 gp->name, idx, (intmax_t)offset, (intmax_t)length,
381 (intmax_t)(offset + length - 1));
382 gsl[idx].offset = offset;
383 gsl[idx].length = length;
384 return (0);
385}
386
387struct g_provider *
388g_slice_addslice(struct g_geom *gp, int idx, off_t offset, off_t length, u_int sectorsize, const char *fmt, ...)
389{
390 struct g_provider *pp;
391 struct g_slicer *gsp;
392 va_list ap;
393 struct sbuf *sb;
394
395 g_trace(G_T_TOPOLOGY, "g_slice_addslice()");
396 g_topology_assert();
397 gsp = gp->softc;
398 va_start(ap, fmt);
399 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
400 sbuf_vprintf(sb, fmt, ap);
401 sbuf_finish(sb);
402 pp = g_new_providerf(gp, sbuf_data(sb));
403
404 pp->index = idx;
405 gsp->slices[idx].length = length;
406 gsp->slices[idx].offset = offset;
407 gsp->slices[idx].provider = pp;
408 gsp->slices[idx].sectorsize = sectorsize;
409 pp->mediasize = gsp->slices[idx].length;
410 pp->sectorsize = gsp->slices[idx].sectorsize;
411 sbuf_delete(sb);
412 if (bootverbose)
413 printf("GEOM: Add %s, start %jd length %jd end %jd\n",
414 pp->name, (intmax_t)offset, (intmax_t)length,
415 (intmax_t)(offset + length - 1));
416 return(pp);
417}
418
419struct g_geom *
420g_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)
421{
422 struct g_geom *gp;
423 struct g_slicer *gsp;
424 struct g_consumer *cp;
425 void **vp;
426 int error, i;
427
428 g_topology_assert();
429 vp = (void **)extrap;
430 gp = g_new_geomf(mp, "%s", pp->name);
431 gsp = g_slice_init(slices, extra);
432 gsp->start = start;
433 gp->access = g_slice_access;
434 gp->orphan = g_slice_orphan;
435 gp->softc = gsp;
436 gp->start = g_slice_start;
437 gp->spoiled = g_std_spoiled;
438 gp->dumpconf = g_slice_dumpconf;
439 cp = g_new_consumer(gp);
440 error = g_attach(cp, pp);
441 if (error == 0)
442 error = g_access_rel(cp, 1, 0, 0);
443 if (error) {
444 if (cp->provider != NULL)
445 g_detach(cp);
446 g_destroy_consumer(cp);
447 g_free(gsp->slices);
448 g_free(gp->softc);
449 g_destroy_geom(gp);
450 return (NULL);
451 }
452 /* Find out if there are any magic bytes on the consumer */
453 i = sizeof gsp->cfrontstuff;
454 error = g_io_getattr("GEOM::frontstuff", cp, &i, &gsp->cfrontstuff);
455 if (error)
456 gsp->cfrontstuff = 0;
457 *vp = gsp->softc;
458 *cpp = cp;
459 return (gp);
460}
461
462static void
463g_slice_orphan(struct g_consumer *cp)
464{
465 struct g_geom *gp;
466 struct g_provider *pp;
467 int error;
468
469 g_trace(G_T_TOPOLOGY, "g_slice_orphan(%p/%s)", cp, cp->provider->name);
470 g_topology_assert();
471 KASSERT(cp->provider->error != 0,
472 ("g_slice_orphan with error == 0"));
473
474 gp = cp->geom;
475 /* XXX: Not good enough we leak the softc and its suballocations */
476 gp->flags |= G_GEOM_WITHER;
477 error = cp->provider->error;
478 LIST_FOREACH(pp, &gp->provider, provider)
479 g_orphan_provider(pp, error);
480 return;
481}