| /* |
| * 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 */ |