2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
10 #include <sys/cdefs.h>
11 __FBSDID("$FreeBSD$");
13 #include <sys/types.h>
14 #include <sys/stdint.h>
27 c = malloc(sizeof *c);
29 memset(c, 0, sizeof *c);
33 /* Is c2 completely inside c1 ? */
36 Chunk_Inside(const struct chunk *c1, const struct chunk *c2)
38 /* if c1 ends before c2 do */
39 if (c1->end < c2->end)
41 /* if c1 starts after c2 do */
42 if (c1->offset > c2->offset)
48 Find_Mother_Chunk(struct chunk *chunks, daddr_t offset, daddr_t end,
51 struct chunk *c1, *c2, ct;
57 if (Chunk_Inside(chunks, &ct))
60 for (c1 = chunks->part; c1; c1 = c1->next) {
63 if (Chunk_Inside(c1, &ct))
68 for (c1 = chunks->part; c1; c1 = c1->next) {
70 if (Chunk_Inside(c1, &ct))
72 if (c1->type != extended)
74 for (c2 = c1->part; c2; c2 = c2->next)
75 if (c2->type == type && Chunk_Inside(c2, &ct))
81 for (c1 = chunks->part; c1; c1 = c1->next) {
83 if (Chunk_Inside(c1, &ct))
89 warn("Unsupported mother type in Find_Mother_Chunk");
95 Free_Chunk(struct chunk *c1)
99 if(c1->private_data && c1->private_free)
100 (*c1->private_free)(c1->private_data);
102 Free_Chunk(c1->part);
104 Free_Chunk(c1->next);
105 if (c1->name != NULL)
107 if (c1->sname != NULL)
113 Clone_Chunk(const struct chunk *c1)
123 if (c1->private_data && c1->private_clone)
124 c2->private_data = c2->private_clone(c2->private_data);
125 c2->name = strdup(c2->name);
126 if (c2->sname != NULL)
127 c2->sname = strdup(c2->sname);
128 c2->next = Clone_Chunk(c2->next);
129 c2->part = Clone_Chunk(c2->part);
134 Insert_Chunk(struct chunk *c2, daddr_t offset, daddr_t size, const char *name,
135 chunk_e type, int subtype, u_long flags, const char *sname)
137 struct chunk *ct,*cs;
139 /* We will only insert into empty spaces */
140 if (c2->type != unused)
149 ct->end = offset + size - 1;
152 ct->sname = strdup(sname);
153 ct->name = strdup(name);
154 ct->subtype = subtype;
157 if (!Chunk_Inside(c2, ct)) {
162 if ((type == freebsd || type == extended || type == apple)) {
169 cs->end = offset + size - 1;
172 cs->sname = strdup(sname);
173 cs->name = strdup("-");
177 /* Make a new chunk for any trailing unused space */
178 if (c2->end > ct->end) {
184 cs->offset = ct->end + 1;
185 cs->size = c2->end - ct->end;
186 if (c2->sname != NULL)
187 cs->sname = strdup(c2->sname);
189 cs->name = strdup(c2->name);
191 c2->size -= c2->end - ct->end;
194 /* If no leading unused space just occupy the old chunk */
195 if (c2->offset == ct->offset) {
196 c2->sname = ct->sname;
200 c2->subtype = ct->subtype;
201 c2->flags = ct->flags;
208 /* else insert new chunk and adjust old one */
209 c2->end = ct->offset - 1;
210 c2->size -= ct->size;
217 Add_Chunk(struct disk *d, daddr_t offset, daddr_t size, const char *name,
218 chunk_e type, int subtype, u_long flags, const char *sname)
220 struct chunk *c1, *c2, ct;
221 daddr_t end = offset + size - 1;
227 d->chunks = c1 = New_Chunk();
230 c2 = c1->part = New_Chunk();
233 c2->disk = c1->disk = d;
234 c2->offset = c1->offset = offset;
235 c2->size = c1->size = size;
236 c2->end = c1->end = end;
237 c1->sname = strdup(sname);
238 c2->sname = strdup("-");
239 c1->name = strdup(name);
240 c2->name = strdup("-");
244 c1->subtype = subtype;
249 /* PLATFORM POLICY BEGIN ------------------------------------- */
259 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
262 c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
276 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
279 c1 = Find_Mother_Chunk(d->chunks, offset, end,
282 c1 = Find_Mother_Chunk(d->chunks, offset, end,
294 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
297 c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
307 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
310 c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
319 c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
322 c1 = Find_Mother_Chunk(d->chunks, offset, end, apple);
331 /* PLATFORM POLICY END ---------------------------------------- */
335 for(c2 = c1->part; c2; c2 = c2->next) {
336 if (c2->type != unused)
338 if(!Chunk_Inside(c2, &ct))
340 /* PLATFORM POLICY BEGIN ------------------------------------- */
341 if (platform == p_sparc64) {
342 offset = Prev_Cyl_Aligned(d, offset);
343 size = Next_Cyl_Aligned(d, size);
344 } else if (platform == p_i386 || platform == p_pc98 ||
345 platform == p_amd64) {
348 if (!(flags & CHUNK_ALIGN))
350 if (offset == d->chunks->offset &&
351 end == d->chunks->end)
354 /* Round down to prev cylinder */
355 offset = Prev_Cyl_Aligned(d,offset);
356 /* Stay inside the parent */
357 if (offset < c2->offset)
359 /* Round up to next cylinder */
360 offset = Next_Cyl_Aligned(d, offset);
361 /* Keep one track clear in front of parent */
362 if (offset == c1->offset)
363 offset = Next_Track_Aligned(d, offset + 1);
364 /* Work on the (end+1) */
366 /* Round up to cylinder */
367 size = Next_Cyl_Aligned(d, size);
368 /* Stay inside parent */
369 if ((size-1) > c2->end)
371 /* Round down to cylinder */
372 size = Prev_Cyl_Aligned(d, size);
374 /* Convert back to size */
379 /* PLATFORM POLICY END ------------------------------------- */
383 return Insert_Chunk(c2, offset, size, name, type, subtype, flags,
388 ShowChunkFlags(struct chunk *c)
393 if (c->flags & CHUNK_ACTIVE)
395 if (c->flags & CHUNK_ALIGN)
397 if (c->flags & CHUNK_IS_ROOT)
405 Print_Chunk(struct chunk *c1, int offset)
411 for (i = 0; i < offset - 2; i++)
413 for (; i < offset; i++)
421 printf("%8jd %8jd %8jd %-8s %-16s %-8s 0x%02x %s",
422 (intmax_t)c1->offset, (intmax_t)c1->size, (intmax_t)c1->end,
423 c1->name, c1->sname, chunk_name(c1->type), c1->subtype,
426 Print_Chunk(c1->part, offset + 2);
427 Print_Chunk(c1->next, offset);
431 Debug_Chunk(struct chunk *c1)
438 Delete_Chunk(struct disk *d, struct chunk *c)
441 return (Delete_Chunk2(d, c, 0));
445 Delete_Chunk2(struct disk *d, struct chunk *c, int rflags)
447 struct chunk *c1, *c2, *c3;
448 daddr_t offset = c->offset;
455 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole);
458 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, freebsd);
461 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
466 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
471 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, extended);
473 c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
479 for (c2 = c1->part; c2; c2 = c2->next) {
484 if (c2->sname != NULL)
486 c2->sname = strdup("-");
488 c2->name = strdup("-");
489 Free_Chunk(c2->part);
497 * Collapse multiple unused elements together, and attempt
498 * to extend the previous chunk into the freed chunk.
500 * We only extend non-unused elements which are marked
501 * for newfs (we can't extend working filesystems), and
502 * only if we are called with DELCHUNK_RECOVER.
504 for (c2 = c1->part; c2; c2 = c2->next) {
505 if (c2->type != unused) {
506 if (c2->offset + c2->size != offset ||
507 (rflags & DELCHUNK_RECOVER) == 0 ||
508 (c2->flags & CHUNK_NEWFS) == 0) {
511 /* else extend into free area */
515 if (c2->next->type != unused)
518 c2->size += c3->size;
531 Collapse_Chunk(struct disk *d, struct chunk *c1)
533 struct chunk *c2, *c3;
535 if (c1->next && Collapse_Chunk(d, c1->next))
538 if (c1->type == unused && c1->next && c1->next->type == unused) {
540 c1->size += c3->size;
550 if (Collapse_Chunk(d, c1->part))
553 if (c1->type == whole)
556 if (c3->type == unused && c3->size == c1->size) {
560 if (c3->type == unused) {
563 barfout(1, "malloc failed");
567 c1->sname = strdup("-");
568 c1->name = strdup("-");
575 c2->offset += c1->size;
576 c2->size -= c1->size;
582 for (c2 = c3; c2->next; c2 = c2->next)
584 if (c2 && c2->type == unused) {
588 c1->size -= c2->size;