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.
10 # $Id: bitmap.c 911 2005-03-14 21:02:17Z oopo $
11 # PFS bitmap manipulation routines
16 u32 bitsPerBitmapChunk
= 8192; // number of bitmap bits in each bitmap data chunk (1024 bytes)
18 // "Free zone" map. Used to get number of free zone in bitmap, 4-bits at a time
19 u32 free_bitmap
[16]={4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
21 void bitmapSetupInfo(pfs_mount_t
*pfsMount
, t_bitmapInfo
*info
, u32 subpart
, u32 number
)
25 size
= pfsMount
->blockDev
->getSize(pfsMount
->fd
, subpart
) >> pfsMount
->sector_scale
;
27 info
->chunk
= number
/ bitsPerBitmapChunk
;
28 info
->bit
= number
& 31;
29 info
->index
= (number
% bitsPerBitmapChunk
) / 32;
30 info
->partitionChunks
= size
/ bitsPerBitmapChunk
;
31 info
->partitionRemainder
= size
% bitsPerBitmapChunk
;
34 // Allocates or frees (depending on operation) the bitmap area starting at chunk/index/bit, of size count
35 void bitmapAllocFree(pfs_cache_t
*clink
, u32 operation
, u32 subpart
, u32 chunk
, u32 index
, u32 _bit
, u32 count
)
42 for ( ; index
< (metaSize
/ 4) && count
; index
++, _bit
= 0)
44 for (bit
= _bit
; bit
< 32 && count
; bit
++, count
--)
46 if(operation
== BITMAP_ALLOC
)
48 if (clink
->u
.bitmap
[index
] & (1 << bit
))
49 printf("ps2fs: Error: Tried to allocate used block!\n");
51 clink
->u
.bitmap
[index
] |= (1 << bit
);
55 if ((clink
->u
.bitmap
[index
] & (1 << bit
))==0)
56 printf("ps2fs: Error: Tried to free unused block!\n");
58 clink
->u
.bitmap
[index
] &= ~(1 << bit
);
64 clink
->flags
|= CACHE_FLAG_DIRTY
;
72 sector
= (1 << clink
->pfsMount
->inode_scale
) + chunk
;
74 sector
+= 0x2000 >> blockSize
;
76 clink
= cacheGetData(clink
->pfsMount
, subpart
, sector
, CACHE_FLAG_BITMAP
, &result
);
80 // Attempts to allocate 'count' more continuous zones for 'bi'
81 int bitmapAllocateAdditionalZones(pfs_mount_t
*pfsMount
, pfs_blockinfo
*bi
, u32 count
)
88 bitmapSetupInfo(pfsMount
, &info
, bi
->subpart
, bi
->number
+bi
->count
);
90 // Make sure we're not trying to allocate more than is possible
91 if (65535-bi
->count
< count
)
92 count
=65535-bi
->count
;
94 // Loop over each bitmap chunk (each is 1024 bytes in size) until either we have allocated
95 // the requested amount of blocks, or until we have run out of space on the current partition
96 while ((((info
.partitionRemainder
==0) && (info
.chunk
< info
.partitionChunks
)) ||
97 ((info
.partitionRemainder
!=0) && (info
.chunk
< info
.partitionChunks
+1))) && count
)
99 u32 sector
=(1<<pfsMount
->inode_scale
) + info
.chunk
;
101 // if main partition, add offset (in units of blocks)
103 sector
+= 0x2000 >> blockSize
;
105 // Read the bitmap chunk from the hdd
106 c
=cacheGetData(pfsMount
, bi
->subpart
, sector
, CACHE_FLAG_BITMAP
, &result
);
109 // Loop over each 32-bit word in the current bitmap chunk until
110 // we find a used zone or we've allocated all the zones we need
111 while ((info
.index
< (info
.chunk
==info
.partitionChunks
? info
.partitionRemainder
/ 32 : metaSize
/ 4)) && count
)
113 // Loop over each of the 32 bits in the current word from the current bitmap chunk,
114 // trying to allocate the requested number of zones
115 for ( ; (info
.bit
< 32) && count
; count
--)
117 // We only want to allocate a continuous area, so if we come
118 // accross a used zone bail
119 if (c
->u
.bitmap
[info
.index
] & (1<<info
.bit
))
125 // If the current bit in the bitmap is marked as free, mark it was used
127 c
->u
.bitmap
[info
.index
] |= 1<<info
.bit
;
129 c
->flags
|= CACHE_FLAG_DIRTY
;
141 // Adjust global free zone counts
142 pfsMount
->free_zone
[bi
->subpart
]-=res
;
143 pfsMount
->zfree
-=res
;
147 // Searches for 'amount' free zones, starting from the position specified in 'bi'.
148 // Returns 1 if allocation was successful, otherwise 0.
149 int bitmapAllocZones(pfs_mount_t
*pfsMount
, pfs_blockinfo
*bi
, u32 amount
)
153 u32 startBit
= 0, startPos
= 0, startChunk
= 0, count
= 0;
156 u32
*bitmapEnd
, *bitmapWord
;
159 bitmapSetupInfo(pfsMount
, &info
, bi
->subpart
, bi
->number
);
161 for ( ; ((info
.partitionRemainder
==0) && (info
.chunk
< info
.partitionChunks
))||
162 ((info
.partitionRemainder
!=0) && (info
.chunk
< info
.partitionChunks
+1)); info
.chunk
++){
164 sector
= info
.chunk
+ (1 << pfsMount
->inode_scale
);
166 sector
+= 0x2000 >> blockSize
;
168 // read in the bitmap chunk
169 bitmap
= cacheGetData(pfsMount
, bi
->subpart
, sector
, CACHE_FLAG_BITMAP
, &result
);
173 bitmapEnd
=bitmap
->u
.bitmap
+
174 (info
.chunk
== info
.partitionChunks
? info
.partitionRemainder
/ 32 : metaSize
/ 4);
176 for (bitmapWord
=bitmap
->u
.bitmap
+ info
.index
; bitmapWord
< bitmapEnd
; info
.bit
=0, bitmapWord
++)
178 for (i
=info
.bit
; i
< 32; i
++)
180 // if this bit is marked as free..
181 if (((*bitmapWord
>> i
) & 1)==0)
186 startChunk
= info
.chunk
;
187 startPos
= bitmapWord
- bitmap
->u
.bitmap
;
189 if (++count
== amount
)
191 bi
->number
= (startPos
* 32) + (startChunk
* bitsPerBitmapChunk
) + startBit
;
192 if (count
< bi
->count
)
195 if (bitmap
->sector
!= (startChunk
+ (1 << pfsMount
->inode_scale
)))
198 sector
= (1 << pfsMount
->inode_scale
) + startChunk
;
200 sector
+= 0x2000 >> blockSize
;
202 bitmap
= cacheGetData(pfsMount
, bi
->subpart
, sector
, CACHE_FLAG_BITMAP
, &result
);
205 bitmapAllocFree(bitmap
, BITMAP_ALLOC
, bi
->subpart
, startChunk
, startPos
, startBit
, bi
->count
);
219 // Searches for 'max_count' free zones over all the partitions, and
220 // allocates them. Returns 0 on success, -ENOSPC if the zones could
222 int searchFreeZone(pfs_mount_t
*pfsMount
, pfs_blockinfo
*bi
, u32 max_count
)
226 num
= pfsMount
->num_subs
+ 1;
228 if (bi
->subpart
> pfsMount
->num_subs
)
231 num
= pfsMount
->num_subs
+ 2;
233 count
= max_count
< 33 ? max_count
: 32; //min(max_count, 32)
234 count
= count
< bi
->count
? bi
->count
: count
; //max(count, bi->count)
235 // => count = bound(bi->count, 32);
236 for(; num
>= 0; num
--)
238 for (n
= count
; n
; n
/= 2)
240 if ((pfsMount
->free_zone
[bi
->subpart
] >= n
) &&
241 bitmapAllocZones(pfsMount
, bi
, n
))
243 pfsMount
->free_zone
[bi
->subpart
] -= bi
->count
;
244 pfsMount
->zfree
-= bi
->count
;
245 return 0; // the good exit ;)
252 if(bi
->subpart
== pfsMount
->num_subs
+ 1)
258 // De-allocates the block segment 'bi' in the bitmaps
259 void bitmapFreeBlockSegment(pfs_mount_t
*pfsMount
, pfs_blockinfo
*bi
)
266 bitmapSetupInfo(pfsMount
, &info
, bi
->subpart
, bi
->number
);
268 sector
= (1 << pfsMount
->inode_scale
) + info
.chunk
;
270 sector
+= 0x2000 >> blockSize
;
272 if((clink
=cacheGetData(pfsMount
, (u16
)bi
->subpart
, sector
, CACHE_FLAG_BITMAP
, &rv
)) != NULL
)
274 bitmapAllocFree(clink
, BITMAP_FREE
, bi
->subpart
, info
.chunk
, info
.index
, info
.bit
, bi
->count
);
275 pfsMount
->free_zone
[(u16
)bi
->subpart
]+=bi
->count
;
276 pfsMount
->zfree
+=bi
->count
;
280 // Returns the number of free zones for the partition 'sub'
281 int calcFreeZones(pfs_mount_t
*pfsMount
, int sub
)
286 u32 i
, bitmapSize
, zoneFree
=0, sector
;
288 bitmapSetupInfo(pfsMount
, &info
, sub
, 0);
290 while (((info
.partitionRemainder
!=0) && (info
.chunk
<info
.partitionChunks
+1)) ||
291 ((info
.partitionRemainder
==0) && (info
.chunk
<info
.partitionChunks
)))
293 bitmapSize
= info
.chunk
==info
.partitionChunks
? info
.partitionRemainder
>>3 : metaSize
;
295 sector
= (1<<pfsMount
->inode_scale
) + info
.chunk
;
297 sector
+=0x2000>>blockSize
;
299 if ((clink
=cacheGetData(pfsMount
, sub
, sector
, CACHE_FLAG_BITMAP
, &result
)))
301 for (i
=0; i
<bitmapSize
; i
++)
303 zoneFree
+=free_bitmap
[((u8
*)clink
->u
.bitmap
)[i
] & 0xF]
304 +free_bitmap
[((u8
*)clink
->u
.bitmap
)[i
] >> 4];
315 // Debugging function, prints bitmap information
316 void bitmapShow(pfs_mount_t
*pfsMount
)
322 for (pn
=0; pn
< pfsMount
->num_subs
+1; pn
++)
324 bitcnt
=bitsPerBitmapChunk
;
325 bitmapSetupInfo(pfsMount
, &info
, pn
, 0);
327 while (((info
.partitionRemainder
!=0) && (info
.chunk
<info
.partitionChunks
+1)) ||
328 ((info
.partitionRemainder
==0) && (info
.chunk
<info
.partitionChunks
)))
331 u32 sector
= (1<<pfsMount
->inode_scale
) + info
.chunk
;
335 sector
+= 0x2000 >> blockSize
;
336 clink
=cacheGetData(pfsMount
, pn
, sector
, CACHE_FLAG_BITMAP
, &result
);
338 if (info
.chunk
== info
.partitionChunks
)
339 bitcnt
=info
.partitionRemainder
;
341 printf("ps2fs: Zone show: pn %ld, bn %ld, bitcnt %ld\n", pn
, info
.chunk
, bitcnt
);
343 for(i
=0; (i
< (1<<blockSize
)) && ((i
* 512) < (bitcnt
/ 8)); i
++)
344 printBitmap(clink
->u
.bitmap
+128*i
);
352 // Free's all blocks allocated to an inode
353 void bitmapFreeInodeBlocks(pfs_cache_t
*clink
)
355 pfs_mount_t
*pfsMount
=clink
->pfsMount
;
359 for(i
=0;i
< clink
->u
.inode
->number_data
; i
++)
361 u32 index
= fixIndex(i
);
362 pfs_blockinfo
*bi
=&clink
->u
.inode
->data
[index
];
367 if((clink
= blockGetNextSegment(clink
, &err
))==NULL
)
371 bitmapFreeBlockSegment(pfsMount
, bi
);
372 cacheMarkClean(pfsMount
, (u16
)bi
->subpart
, bi
->number
<< pfsMount
->inode_scale
,
373 (bi
->number
+ bi
->count
) << pfsMount
->inode_scale
);