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