1    | /* space_bitmap.c
2    |    --------------
3    |    Simple space allocator using a bitmap
4    | 
5    |    $Id: space_bitmap.c,v 1.11 2003/10/20 07:18:11 stewart Exp $
6    | 
7    |    (C)2003 Stewart Smith
8    |    Distributed under the GNU Public License
9    | */
10   | 
11   | #include <stdio.h>
12   | #include <stdlib.h>
13   | #include "testkit/block_dev.h"
14   | #include "testkit/bitops.h"
15   | #include "super_block.h"
16   | #include "disk.h"
17   | #include "space_bitmap.h"
18   | 
19   | #define MAX_DIV(a,b) (((a%b)==0)?(a/b):(a/b)+1)
20   | 
21   | u64 next_free = 300;
22   | 
23   | u32 space_bitmap_size(struct fcfs_sb *sb, int ag)
24   | {
25   |   /* if last ag, is remaining no. of blocks */
26   |   if(ag == sb->allocation_groupsnr-1)
27   |     return MAX_DIV(MAX_DIV((sb->ag_blocksnr+(sb->blocksnr%sb->allocation_groupsnr)),8),sb->bsize);
28   |   else
29   |     /* 1 bit per block */
30   |     return MAX_DIV(MAX_DIV(sb->ag_blocksnr,8),sb->bsize);
31   | }
32   | 
33   | int space_bitmap_allocate_block(struct fcfs_disk *disk, u32 allocation_group,u32 block)
34   | {
35   |   struct fcfs_disk_block *b;
36   | 
37   | #ifdef DEBUG_SPACE_BITMAP
38   |   printf("ALLOC %u %u\n",allocation_group,block);
39   | #endif
40   | 
41   |   b = disk_getblock(disk,
42   | 		    (allocation_group)*disk->sb->ag_blocksnr
43   | 		    +(block/(disk->sb->bsize*8))
44   | 		    +1);
45   |   set_bit(block%8,
46   | 	  (b->data+((block%(disk->sb->bsize*8))/8)));
47   |   
48   |   disk_writeblock(b);
49   |   disk_freeblock(b);
50   |   return 0;
51   | }
52   | 
53   | struct fcfs_block_run *ag_allocate_block(struct fcfs_disk *disk, u32 allocation_group, u32 near, u32 blocksnr)
54   | {
55   |   struct fcfs_block_run *br;
56   |   int i;
57   | 
58   | #ifdef DEBUG_SPACE_BITMAP
59   |   printf("%u %u\n",allocation_group,near);
60   | #endif
61   | 
62   |   br = (struct fcfs_block_run*)malloc(sizeof(struct fcfs_block_run));
63   |   if(!br)
64   |     {
65   |       fprintf(stderr,"ag_allocate_block: Unable to allocate block_run\n");
66   |       abort();
67   |     }
68   | 
69   |   br->start = 0;
70   |   br->len = 0;
71   | 
72   |   if(near+blocksnr > disk->sb->ag_blocksnr)
73   |     blocksnr = disk->sb->ag_blocksnr - near;
74   | 
75   |   for(i=1;i<=blocksnr+1;i++)
76   |     {
77   |       if(near+i>=disk->sb->ag_blocksnr)
78   | 	{allocation_group++;near=0;i=0; br->start=0;br->len=0;/*printf("RESTARTING BLOCK SEARCH IN NEW ALLOCATION GROUP\n");*/}
79   |       if(ag_block_free(disk,allocation_group,near+i))
80   | 	{
81   | #ifdef DEBUG_SPACE_BITMAP
82   | 	  fprintf(stderr,"BLOCK %lu %lu is free\n",allocation_group,near+i);
83   | #endif
84   | 	  if(br->start==0)
85   | 	    {  br->start=near+i; br->len=1;}
86   | 	  else
87   | 	    if((br->start+br->len)==(near+i-1))
88   | 	      br->len++;
89   | 	}
90   |       else
91   | 	{
92   | 	  //fprintf(stderr,"BLOCK %lu %lu isn't free\n",allocation_group,near+i);
93   | 	  near++;
94   | 	  i=0;
95   | 	}
96   |     }
97   | 
98   |   br->allocation_group = allocation_group;
99   | 
100  |   for(i=0;i<br->len;i++)
101  |     space_bitmap_allocate_block(disk,br->allocation_group,br->start+i);
102  | 
103  |   next_free = br->start + br->len;
104  | 
105  |   return br;
106  | }
107  | 
108  | u64 ag_block_free_last;
109  | struct fcfs_disk_block *ag_block_free_last_block;
110  | 
111  | int ag_block_free(struct fcfs_disk *disk,u32 allocation_group, u32 block)
112  | {
113  |   struct fcfs_disk_block *b;
114  |   int retval;
115  | 
116  | #ifdef DEBUG_SPACE_BITMAP
117  |   printf("\t%u %u\n",allocation_group,block);
118  | #endif
119  | 
120  |   if(block > disk->sb->ag_blocksnr)
121  |     {
122  |       fprintf(stderr,"ERROR: ag_black_free() can't check block that's out of this AG\n");
123  |       abort();
124  |     }
125  | 
126  |   if(ag_block_free_last==0 ||
127  |      ag_block_free_last!=
128  |      (allocation_group)*disk->sb->ag_blocksnr+(block/(disk->sb->bsize*8))+1
129  |      )
130  |     {
131  |       if(ag_block_free_last!=0) disk_freeblock(ag_block_free_last_block);
132  |       ag_block_free_last = (allocation_group)*disk->sb->ag_blocksnr
133  | 	+(block/(disk->sb->bsize*8))
134  | 	+1;
135  |       ag_block_free_last_block = b = disk_getblock(disk,ag_block_free_last);
136  |     }
137  |   else
138  |     {
139  |       b = ag_block_free_last_block;
140  |     }
141  |   
142  | 
143  |   retval =  !test_bit(block%8,
144  | 		      (b->data+((block%(disk->sb->bsize*8))/8)));
145  | 
146  | 
147  |   return retval;
148  | }