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
;