2 * Copyright (c) 2011 Maurizio Lombardi
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 find_free_bit_and_set(bitchunk_t
*b
, const int bsize
,
38 const bool native
, unsigned start_bit
);
41 mfs_free_bit(struct mfs_instance
*inst
, uint32_t idx
, bmap_id_t bid
);
44 mfs_alloc_bit(struct mfs_instance
*inst
, uint32_t *idx
, bmap_id_t bid
);
47 mfs_count_free_bits(struct mfs_instance
*inst
, bmap_id_t bid
, uint32_t *free
);
50 /**Allocate a new inode.
52 * @param inst Pointer to the filesystem instance.
53 * @param inum Pointer to a 32 bit number where the index of
54 * the new inode will be saved.
56 * @return EOK on success or a negative error code.
59 mfs_alloc_inode(struct mfs_instance
*inst
, uint32_t *inum
)
61 int r
= mfs_alloc_bit(inst
, inum
, BMAP_INODE
);
67 * @param inst Pointer to the filesystem instance.
68 * @param inum Number of the inode to free.
70 * @return EOK on success or a negative error code.
73 mfs_free_inode(struct mfs_instance
*inst
, uint32_t inum
)
75 return mfs_free_bit(inst
, inum
, BMAP_INODE
);
78 /**Allocate a new zone.
80 * @param inst Pointer to the filesystem instance.
81 * @param zone Pointer to a 32 bit number where the index
82 * of the zone will be saved.
84 * @return EOK on success or a negative error code.
87 mfs_alloc_zone(struct mfs_instance
*inst
, uint32_t *zone
)
89 int r
= mfs_alloc_bit(inst
, zone
, BMAP_ZONE
);
93 /* Update the cached number of free zones */
94 struct mfs_sb_info
*sbi
= inst
->sbi
;
95 if (sbi
->nfree_zones_valid
)
98 *zone
+= inst
->sbi
->firstdatazone
- 1;
104 * @param inst Pointer to the filesystem instance.
105 * @param zone Index of the zone to free.
107 * @return EOK on success or a negative error code.
110 mfs_free_zone(struct mfs_instance
*inst
, uint32_t zone
)
114 zone
-= inst
->sbi
->firstdatazone
- 1;
116 r
= mfs_free_bit(inst
, zone
, BMAP_ZONE
);
120 /* Update the cached number of free zones */
121 struct mfs_sb_info
*sbi
= inst
->sbi
;
122 if (sbi
->nfree_zones_valid
)
128 /** Count the number of free zones
130 * @param inst Pointer to the instance structure.
131 * @param zones Pointer to the memory location where the result
134 * @return EOK on success or a negative error code.
137 mfs_count_free_zones(struct mfs_instance
*inst
, uint32_t *zones
)
139 return mfs_count_free_bits(inst
, BMAP_ZONE
, zones
);
142 /** Count the number of free inodes
144 * @param inst Pointer to the instance structure.
145 * @param zones Pointer to the memory location where the result
148 * @return EOK on success or a negative error code.
152 mfs_count_free_inodes(struct mfs_instance
*inst
, uint32_t *inodes
)
154 return mfs_count_free_bits(inst
, BMAP_INODE
, inodes
);
157 /** Count the number of free bits in a bitmap
159 * @param inst Pointer to the instance structure.
160 * @param bid Type of the bitmap (inode or zone).
161 * @param free Pointer to the memory location where the result
164 * @return EOK on success or a negative error code.
167 mfs_count_free_bits(struct mfs_instance
*inst
, bmap_id_t bid
, uint32_t *free
)
170 unsigned start_block
;
171 unsigned long nblocks
;
174 unsigned long free_bits
= 0;
176 size_t const bitchunk_bits
= sizeof(bitchunk_t
) * 8;
178 struct mfs_sb_info
*sbi
= inst
->sbi
;
180 start_block
= MFS_BMAP_START_BLOCK(sbi
, bid
);
181 nblocks
= MFS_BMAP_SIZE_BLOCKS(sbi
, bid
);
182 nbits
= MFS_BMAP_SIZE_BITS(sbi
, bid
);
184 for (block
= 0; block
< nblocks
; ++block
) {
185 r
= block_get(&b
, inst
->service_id
, block
+ start_block
,
191 bitchunk_t
*data
= (bitchunk_t
*) b
->data
;
193 /* Read the bitmap block, chunk per chunk,
194 * counting the zero bits.
196 for (i
= 0; i
< sbi
->block_size
/ sizeof(bitchunk_t
); ++i
) {
197 chunk
= conv32(sbi
->native
, data
[i
]);
200 for (bit
= 0; bit
< bitchunk_bits
&& nbits
> 0;
202 if (!(chunk
& (1 << bit
)))
221 /**Clear a bit in a bitmap.
223 * @param inst Pointer to the filesystem instance.
224 * @param idx Index of the bit to clear.
225 * @param bid BMAP_ZONE if operating on the zone's bitmap,
226 * BMAP_INODE if operating on the inode's bitmap.
228 * @return EOK on success or a negative error code.
231 mfs_free_bit(struct mfs_instance
*inst
, uint32_t idx
, bmap_id_t bid
)
233 struct mfs_sb_info
*sbi
;
235 unsigned start_block
;
241 start_block
= MFS_BMAP_START_BLOCK(sbi
, bid
);
243 if (bid
== BMAP_ZONE
) {
244 search
= &sbi
->zsearch
;
245 if (idx
> sbi
->nzones
) {
246 printf(NAME
": Error! Trying to free beyond the "
247 "bitmap max size\n");
251 /* bid == BMAP_INODE */
252 search
= &sbi
->isearch
;
253 if (idx
> sbi
->ninodes
) {
254 printf(NAME
": Error! Trying to free beyond the "
255 "bitmap max size\n");
260 /* Compute the bitmap block */
261 uint32_t block
= idx
/ (sbi
->block_size
* 8) + start_block
;
263 r
= block_get(&b
, inst
->service_id
, block
, BLOCK_FLAGS_NONE
);
267 /* Compute the bit index in the block */
268 idx
%= (sbi
->block_size
* 8);
269 bitchunk_t
*ptr
= b
->data
;
271 const size_t chunk_bits
= sizeof(bitchunk_t
) * 8;
273 chunk
= conv32(sbi
->native
, ptr
[idx
/ chunk_bits
]);
274 chunk
&= ~(1 << (idx
% chunk_bits
));
275 ptr
[idx
/ chunk_bits
] = conv32(sbi
->native
, chunk
);
287 /**Search a free bit in a bitmap and mark it as used.
289 * @param inst Pointer to the filesystem instance.
290 * @param idx Pointer of a 32 bit number where the index
291 * of the found bit will be stored.
292 * @param bid BMAP_ZONE if operating on the zone's bitmap,
293 * BMAP_INODE if operating on the inode's bitmap.
295 * @return EOK on success or a negative error code.
298 mfs_alloc_bit(struct mfs_instance
*inst
, uint32_t *idx
, bmap_id_t bid
)
300 struct mfs_sb_info
*sbi
;
302 unsigned long nblocks
;
303 unsigned *search
, i
, start_block
;
304 unsigned bits_per_block
;
309 start_block
= MFS_BMAP_START_BLOCK(sbi
, bid
);
310 limit
= MFS_BMAP_SIZE_BITS(sbi
, bid
);
311 nblocks
= MFS_BMAP_SIZE_BLOCKS(sbi
, bid
);
313 if (bid
== BMAP_ZONE
) {
314 search
= &sbi
->zsearch
;
316 /* bid == BMAP_INODE */
317 search
= &sbi
->isearch
;
319 bits_per_block
= sbi
->block_size
* 8;
325 for (i
= *search
/ bits_per_block
; i
< nblocks
; ++i
) {
326 r
= block_get(&b
, inst
->service_id
, i
+ start_block
,
332 unsigned tmp
= *search
% bits_per_block
;
334 freebit
= find_free_bit_and_set(b
->data
, sbi
->block_size
,
337 /* No free bit in this block */
344 /* Free bit found in this block, compute the real index */
345 *idx
= freebit
+ bits_per_block
* i
;
347 /* Index is beyond the limit, it is invalid */
361 /* Repeat the search from the first bitmap block */
366 /* Free bit not found, return error */
374 find_free_bit_and_set(bitchunk_t
*b
, const int bsize
,
375 const bool native
, unsigned start_bit
)
380 const size_t chunk_bits
= sizeof(bitchunk_t
) * 8;
382 for (i
= start_bit
/ chunk_bits
;
383 i
< bsize
/ sizeof(bitchunk_t
); ++i
) {
386 /* No free bit in this chunk */
390 chunk
= conv32(native
, b
[i
]);
392 for (j
= 0; j
< chunk_bits
; ++j
) {
393 if (!(chunk
& (1 << j
))) {
394 r
= i
* chunk_bits
+ j
;
396 b
[i
] = conv32(native
, chunk
);