/*
* region.c --- code which manages allocations within a region.
*
* Copyright (C) 2001 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include "config.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#ifdef TEST_PROGRAM
#undef ENABLE_NLS
#endif
#include "e2fsck.h"
struct region_el {
region_addr_t start;
region_addr_t end;
struct region_el *next;
};
struct region_struct {
region_addr_t min;
region_addr_t max;
struct region_el *allocated;
struct region_el *last;
};
region_t region_create(region_addr_t min, region_addr_t max)
{
region_t region;
region = malloc(sizeof(struct region_struct));
if (!region)
return NULL;
memset(region, 0, sizeof(struct region_struct));
region->min = min;
region->max = max;
region->last = NULL;
return region;
}
void region_free(region_t region)
{
struct region_el *r, *next;
for (r = region->allocated; r; r = next) {
next = r->next;
free(r);
}
memset(region, 0, sizeof(struct region_struct));
free(region);
}
int region_allocate(region_t region, region_addr_t start, int n)
{
struct region_el *r, *new_region, *prev, *next;
region_addr_t end;
end = start+n;
if ((start < region->min) || (end > region->max))
return -1;
if (n == 0)
return 1;
if (region->last && region->last->end == start &&
!region->last->next) {
region->last->end = end;
return 0;
}
if (region->last && start > region->last->end &&
!region->last->next) {
r = NULL;
prev = region->last;
goto append_to_list;
}
/*
* Search through the linked list. If we find that it
* conflicts with something that's already allocated, return
* 1; if we can find an existing region which we can grow, do
* so. Otherwise, stop when we find the appropriate place
* insert a new region element into the linked list.
*/
for (r = region->allocated, prev=NULL; r; prev = r, r = r->next) {
if (((start >= r->start) && (start < r->end)) ||
((end > r->start) && (end <= r->end)) ||
((start <= r->start) && (end >= r->end)))
return 1;
if (end == r->start) {
r->start = start;
return 0;
}
if (start == r->end) {
if ((next = r->next)) {
if (end > next->start)
return 1;
if (end == next->start) {
r->end = next->end;
r->next = next->next;
free(next);
if (!r->next)
region->last = r;
return 0;
}
}
r->end = end;
return 0;
}
if (start < r->start)
break;
}
/*
* Insert a new region element structure into the linked list
*/
append_to_list:
new_region = malloc(sizeof(struct region_el));
if (!new_region)
return -1;
new_region->start = start;
new_region->end = start + n;
new_region->next = r;
if (!new_region->next)
region->last = new_region;
if (prev)
prev->next = new_region;
else
region->allocated = new_region;
return 0;
}
#ifdef TEST_PROGRAM
#include <stdio.h>
#define BCODE_END 0
#define BCODE_CREATE 1
#define BCODE_FREE 2
#define BCODE_ALLOCATE 3
#define BCODE_PRINT 4
int bcode_program[] = {
BCODE_CREATE, 1, 1001,
BCODE_PRINT,
BCODE_ALLOCATE, 10, 10,
BCODE_ALLOCATE, 30, 10,
BCODE_PRINT,
BCODE_ALLOCATE, 1, 15,
BCODE_ALLOCATE, 15, 8,
BCODE_ALLOCATE, 1, 20,
BCODE_ALLOCATE, 1, 8,
BCODE_PRINT,
BCODE_ALLOCATE, 40, 10,
BCODE_PRINT,
BCODE_ALLOCATE, 22, 5,
BCODE_PRINT,
BCODE_ALLOCATE, 27, 3,
BCODE_PRINT,
BCODE_ALLOCATE, 20, 2,
BCODE_PRINT,
BCODE_ALLOCATE, 49, 1,
BCODE_ALLOCATE, 50, 5,
BCODE_ALLOCATE, 9, 2,
BCODE_ALLOCATE, 9, 1,
BCODE_PRINT,
BCODE_FREE,
BCODE_END
};
void region_print(region_t region, FILE *f)
{
struct region_el *r;
int i = 0;
fprintf(f, "Printing region (min=%llu. max=%llu)\n\t", region->min,
region->max);
for (r = region->allocated; r; r = r->next) {
fprintf(f, "(%llu, %llu) ", r->start, r->end);
if (++i >= 8)
fprintf(f, "\n\t");
}
fprintf(f, "\n");
}
int main(int argc, char **argv)
{
region_t r = NULL;
int pc = 0, ret;
region_addr_t start, end;
while (1) {
switch (bcode_program[pc++]) {
case BCODE_END:
exit(0);
case BCODE_CREATE:
start = bcode_program[pc++];
end = bcode_program[pc++];
printf("Creating region with args(%llu, %llu)\n",
start, end);
r = region_create(start, end);
if (!r) {
fprintf(stderr, "Couldn't create region.\n");
exit(1);
}
break;
case BCODE_ALLOCATE:
start = bcode_program[pc++];
end = bcode_program[pc++];
ret = region_allocate(r, start, end);
printf("Region_allocate(%llu, %llu) returns %d\n",
start, end, ret);
break;
case BCODE_PRINT:
region_print(r, stdout);
break;
}
}
if (r)
region_free(r);
}
#endif /* TEST_PROGRAM */