PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
bitmap.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9#
10# PFS bitmap manipulation routines
11*/
12
13#include <errno.h>
14#include <stdio.h>
15#include <limits.h>
16
17#include "libpfs.h"
18
19extern u32 pfsMetaSize;
20extern u32 pfsBlockSize;
21
22u32 pfsBitsPerBitmapChunk = 8192; // number of bitmap bits in each bitmap data chunk (1024 bytes)
23
24void pfsBitmapSetupInfo(pfs_mount_t *pfsMount, pfs_bitmapInfo_t *info, u32 subpart, u32 number)
25{
26 u32 size;
27
28 size = pfsMount->blockDev->getSize(pfsMount->fd, subpart) >> pfsMount->sector_scale;
29
30 info->chunk = number / pfsBitsPerBitmapChunk;
31 info->bit = number & 31;
32 info->index = (number % pfsBitsPerBitmapChunk) / 32;
33 info->partitionChunks = size / pfsBitsPerBitmapChunk;
34 info->partitionRemainder = size % pfsBitsPerBitmapChunk;
35}
36
37// Allocates or frees (depending on operation) the bitmap area starting at chunk/index/bit, of size count
38void pfsBitmapAllocFree(pfs_cache_t *clink, u32 operation, u32 subpart, u32 chunk, u32 index, u32 _bit, u32 count)
39{
40 int result;
41 u32 sector, bit;
42 u32 *bitmapWord;
43
44 while (clink)
45 {
46 u32 *bitmapEnd;
47
48 bitmapEnd = (u32*)&((u8*)clink->u.bitmap)[pfsMetaSize];
49 for (bitmapWord = &clink->u.bitmap[index]; (bitmapWord < bitmapEnd) && count; bitmapWord++, _bit = 0)
50 {
51 for (bit = _bit; bit < 32 && count; bit++, count--)
52 {
53 if(operation == PFS_BITMAP_ALLOC)
54 {
55 if (*bitmapWord & (1 << bit))
56 PFS_PRINTF(PFS_DRV_NAME": Error: Tried to allocate used block!\n");
57
58 *bitmapWord |= (1 << bit);
59 }
60 else
61 {
62 if ((*bitmapWord & (1 << bit))==0)
63 PFS_PRINTF(PFS_DRV_NAME": Error: Tried to free unused block!\n");
64
65 *bitmapWord &= ~(1 << bit);
66 }
67 }
68 }
69
70 index = 0;
71 clink->flags |= PFS_CACHE_FLAG_DIRTY;
72 pfsCacheFree(clink);
73
74 if (count==0)
75 break;
76
77 chunk++;
78
79 sector = (1 << clink->pfsMount->inode_scale) + chunk;
80 if(subpart==0)
81 sector += 0x2000 >> pfsBlockSize;
82
83 clink = pfsCacheGetData(clink->pfsMount, subpart, sector, PFS_CACHE_FLAG_BITMAP, &result);
84 }
85}
86
87// Attempts to allocate 'count' more continuous zones for 'bi'
88int pfsBitmapAllocateAdditionalZones(pfs_mount_t *pfsMount, pfs_blockinfo_t *bi, u32 count)
89{
90 int result;
92 pfs_cache_t *c;
93 int res=0;
94 u32 bitmapMax;
95 u32 *bitmapWord, *bitmapEnd;
96
97 pfsBitmapSetupInfo(pfsMount, &info, bi->subpart, bi->number+bi->count);
98
99 // Make sure we're not trying to allocate more than is possible
100 if ((u32)USHRT_MAX - bi->count < count)
101 count = USHRT_MAX - bi->count;
102
103 // Loop over each bitmap chunk (each is 1024 bytes in size) until either we have allocated
104 // the requested amount of blocks, or until we have run out of space on the current partition
105 while ((((info.partitionRemainder==0) && (info.chunk < info.partitionChunks )) ||
106 ((info.partitionRemainder!=0) && (info.chunk < info.partitionChunks+1))) && count)
107 {
108 u32 sector=(1<<pfsMount->inode_scale) + info.chunk;
109
110 // if main partition, add offset (in units of blocks)
111 if (bi->subpart==0)
112 sector += 0x2000 >> pfsBlockSize;
113
114 // Read the bitmap chunk from the hdd
115 c=pfsCacheGetData(pfsMount, bi->subpart, sector, PFS_CACHE_FLAG_BITMAP, &result);
116 if (c==NULL)break;
117
118 // Loop over each 32-bit word in the current bitmap chunk until
119 // we find a used zone or we've allocated all the zones we need
120 bitmapMax = info.chunk==info.partitionChunks ? info.partitionRemainder / 8 : pfsMetaSize;
121 bitmapEnd = (u32*)&((u8*)c->u.bitmap)[bitmapMax];
122 for (bitmapWord=&c->u.bitmap[info.index]; (bitmapWord < bitmapEnd) && count; bitmapWord++, info.bit=0)
123 {
124 // Loop over each of the 32 bits in the current word from the current bitmap chunk,
125 // trying to allocate the requested number of zones
126 for ( ; (info.bit < 32) && count; count--)
127 {
128 // We only want to allocate a continuous area, so if we come
129 // accross a used zone bail
130 if (*bitmapWord & (1<<info.bit))
131 {
132 pfsCacheFree(c);
133 goto exit;
134 }
135
136 // If the current bit in the bitmap is marked as free, mark it was used
137 res++;
138 *bitmapWord |= 1<<info.bit;
139 info.bit++;
140 c->flags |= PFS_CACHE_FLAG_DIRTY;
141 }
142 }
143 pfsCacheFree(c);
144 info.index=0;
145 info.chunk++;
146 }
147exit:
148
149 // Adjust global free zone counts
150 pfsMount->free_zone[bi->subpart]-=res;
151 pfsMount->zfree-=res;
152 return res;
153}
154
155// Searches for 'amount' free zones, starting from the position specified in 'bi'.
156// Returns 1 if allocation was successful, otherwise 0.
157int pfsBitmapAllocZones(pfs_mount_t *pfsMount, pfs_blockinfo_t *bi, u32 amount)
158{
160 int result;
161 u32 startBit = 0, startPos = 0, startChunk = 0, count = 0;
162 u32 sector;
163 pfs_cache_t *bitmap;
164 u32 *bitmapWord;
165 u32 i, bitmapMax;
166
167 pfsBitmapSetupInfo(pfsMount, &info, bi->subpart, bi->number);
168
169 for ( ; ((info.partitionRemainder==0) && (info.chunk < info.partitionChunks))||
170 ((info.partitionRemainder!=0) && (info.chunk < info.partitionChunks+1)); info.chunk++){
171 u32 *bitmapEnd;
172
173 sector = info.chunk + (1 << pfsMount->inode_scale);
174 if(bi->subpart==0)
175 sector += 0x2000 >> pfsBlockSize;
176
177 // read in the bitmap chunk
178 bitmap = pfsCacheGetData(pfsMount, bi->subpart, sector, PFS_CACHE_FLAG_BITMAP, &result);
179 if(bitmap==0)
180 return 0;
181
182 bitmapMax = info.chunk == info.partitionChunks ? info.partitionRemainder / 8 : pfsMetaSize;
183 bitmapEnd = (u32*)&((u8*)bitmap->u.bitmap)[bitmapMax];
184 for (bitmapWord=&bitmap->u.bitmap[info.index]; bitmapWord < bitmapEnd; info.bit=0, bitmapWord++)
185 {
186 for (i=info.bit; i < 32; i++)
187 {
188 // if this bit is marked as free..
189 if (((*bitmapWord >> i) & 1)==0)
190 {
191 if (count==0)
192 {
193 startBit = i;
194 startChunk = info.chunk;
195 startPos = bitmapWord - bitmap->u.bitmap;
196 }
197 if (++count == amount)
198 {
199 bi->number = (startPos * 32) + (startChunk * pfsBitsPerBitmapChunk) + startBit;
201 bi->count=count;
202
203 if (bitmap->block != (startChunk + (1 << pfsMount->inode_scale)))
204 {
205 pfsCacheFree(bitmap);
206 sector = (1 << pfsMount->inode_scale) + startChunk;
207 if(bi->subpart==0)
208 sector += 0x2000 >> pfsBlockSize;
209
210 bitmap = pfsCacheGetData(pfsMount, bi->subpart, sector, PFS_CACHE_FLAG_BITMAP, &result);
211 }
212
213 pfsBitmapAllocFree(bitmap, PFS_BITMAP_ALLOC, bi->subpart, startChunk, startPos, startBit, bi->count);
214 return 1;
215 }
216 }
217 else
218 count=0;
219 }
220 }
221 pfsCacheFree(bitmap);
222 info.index=0;
223 }
224 return 0;
225}
226
227// Searches for 'max_count' free zones over all the partitions, and
228// allocates them. Returns 0 on success, -ENOSPC if the zones could
229// not be allocated.
230int pfsBitmapSearchFreeZone(pfs_mount_t *pfsMount, pfs_blockinfo_t *bi, u32 max_count)
231{
232 u32 num, count, n, i;
233
234 num = pfsMount->num_subs + 1;
235
236 if (bi->subpart >= num)
237 bi->subpart = 0;
238 if (bi->number)
239 num = pfsMount->num_subs + 2;
240
241 count = max_count < 33 ? max_count : 32; //min(max_count, 32)
243 count = bi->count; //max(count, bi->count)
244 // => count = bound(bi->count, 32);
245
246 for(i = num - 1; i < num; i--)
247 {
248 for (n = count; n; n /= 2)
249 {
250 if ((pfsMount->free_zone[bi->subpart] >= n) &&
251 pfsBitmapAllocZones(pfsMount, bi, n))
252 {
253 pfsMount->free_zone[bi->subpart] -= bi->count;
254 pfsMount->zfree -= bi->count;
255 return 0; // the good exit ;)
256 }
257 }
258
259 bi->number=0;
260 bi->subpart++;
261
262 if(bi->subpart == pfsMount->num_subs + 1)
263 bi->subpart=0;
264 }
265 return -ENOSPC;
266}
267
268// De-allocates the block segment 'bi' in the bitmaps
269void pfsBitmapFreeBlockSegment(pfs_mount_t *pfsMount, pfs_blockinfo_t *bi)
270{
272 pfs_cache_t *clink;
273 u32 sector;
274 int rv;
275
276 pfsBitmapSetupInfo(pfsMount, &info, bi->subpart, bi->number);
277
278 sector = (1 << pfsMount->inode_scale) + info.chunk;
279 if(bi->subpart==0)
280 sector += 0x2000 >> pfsBlockSize;
281
282 if((clink=pfsCacheGetData(pfsMount, (u16)bi->subpart, sector, PFS_CACHE_FLAG_BITMAP, &rv)) != NULL)
283 {
284 pfsBitmapAllocFree(clink, PFS_BITMAP_FREE, bi->subpart, info.chunk, info.index, info.bit, bi->count);
285 pfsMount->free_zone[(u16)bi->subpart]+=bi->count;
286 pfsMount->zfree+=bi->count;
287 }
288}
289
290// Returns the number of free zones for the partition 'sub'
291int pfsBitmapCalcFreeZones(pfs_mount_t *pfsMount, int sub)
292{
293 // "Free zone" map. Used to get number of free zone in bitmap, 4-bits at a time
294 const u32 pfsFreeZoneBitmap[16]={4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
295 int result;
297 u32 i, bitmapSize, zoneFree=0, sector;
298
299 pfsBitmapSetupInfo(pfsMount, &info, sub, 0);
300
301 while (((info.partitionRemainder!=0) && (info.chunk<info.partitionChunks+1)) ||
302 ((info.partitionRemainder==0) && (info.chunk<info.partitionChunks)))
303 {
304 pfs_cache_t *clink;
305
306 bitmapSize = info.chunk==info.partitionChunks ? info.partitionRemainder / 8 : pfsMetaSize;
307
308 sector = (1<<pfsMount->inode_scale) + info.chunk;
309 if (sub==0)
310 sector +=0x2000>>pfsBlockSize;
311
312 if ((clink=pfsCacheGetData(pfsMount, sub, sector, PFS_CACHE_FLAG_BITMAP, &result)))
313 {
314 for (i=0; i<bitmapSize; i++)
315 {
316 zoneFree+=pfsFreeZoneBitmap[((u8*)clink->u.bitmap)[i] & 0xF]
317 +pfsFreeZoneBitmap[((u8*)clink->u.bitmap)[i] >> 4];
318 }
319
320 pfsCacheFree(clink);
321 }
322 info.chunk++;
323 }
324
325 return zoneFree;
326}
327
328// Debugging function, prints bitmap information
329void pfsBitmapShow(pfs_mount_t *pfsMount)
330{
331 int result;
333 u32 pn, bitcnt;
334
335 for (pn=0; pn < pfsMount->num_subs+1; pn++)
336 {
337 bitcnt=pfsBitsPerBitmapChunk;
338 pfsBitmapSetupInfo(pfsMount, &info, pn, 0);
339
340 while (((info.partitionRemainder!=0) && (info.chunk<info.partitionChunks+1)) ||
341 ((info.partitionRemainder==0) && (info.chunk<info.partitionChunks)))
342 {
343 pfs_cache_t *clink;
344 u32 sector = (1<<pfsMount->inode_scale) + info.chunk;
345 u32 i;
346
347 if(pn==0)
348 sector += 0x2000 >> pfsBlockSize;
349 clink=pfsCacheGetData(pfsMount, pn, sector, PFS_CACHE_FLAG_BITMAP, &result);
350
351 if (info.chunk == info.partitionChunks)
352 bitcnt=info.partitionRemainder;
353
354 PFS_PRINTF(PFS_DRV_NAME": Zone show: pn %ld, bn %ld, bitcnt %ld\n", pn, info.chunk, bitcnt);
355
356 for(i=0; (i < (u32)(1<<pfsBlockSize)) && ((i * 512) < (bitcnt / 8)); i++)
357 pfsPrintBitmap(clink->u.bitmap+128*i);
358
359 pfsCacheFree(clink);
360 info.chunk++;
361 }
362 }
363}
364
365// Free's all blocks allocated to an inode
366void pfsBitmapFreeInodeBlocks(pfs_cache_t *clink)
367{
368 pfs_mount_t *pfsMount=clink->pfsMount;
369 u32 i;
370
371 pfsCacheUsedAdd(clink);
372 for(i=0;i < clink->u.inode->number_data; i++)
373 {
374 u32 index = pfsFixIndex(i);
375 pfs_blockinfo_t *bi=&clink->u.inode->data[index];
376 int err;
377
378 if(i!=0) {
379 if(index==0)
380 if((clink = pfsBlockGetNextSegment(clink, &err))==NULL)
381 return;
382 }
383
384 pfsBitmapFreeBlockSegment(pfsMount, bi);
385 pfsCacheMarkClean(pfsMount, (u16)bi->subpart, bi->number << pfsMount->inode_scale,
386 (bi->number + bi->count) << pfsMount->inode_scale);
387 }
388 pfsCacheFree(clink);
389}
#define ENOSPC
Definition errno.h:75
u32 count
start sector of fragmented bd/file