1#include <block/bcache.h>
2#include <console/printf.h>
3#include <fs/ext2.h>
4#include <stdbool.h>
5#include <stdint.h>
6
7static bool find_free_bit(uint8_t *bitmap, uint32_t size, uint32_t *byte_pos,
8 uint32_t *bit_pos) {
9 for (*byte_pos = 0; *byte_pos < size; ++(*byte_pos)) {
10 if (bitmap[*byte_pos] != 0xFF) {
11 for (*bit_pos = 0; *bit_pos < 8; ++(*bit_pos)) {
12 if (!(bitmap[*byte_pos] & (1 << *bit_pos))) {
13 return true;
14 }
15 }
16 }
17 }
18 return false;
19}
20
21static uint32_t alloc_from_bitmap(struct ext2_fs *fs, uint32_t bitmap_block,
22 uint32_t items_per_group, uint32_t group,
23 void (*update_counts)(struct ext2_fs *,
24 uint32_t)) {
25 uint32_t byte_pos, bit_pos;
26
27 struct bcache_entry *ent;
28 uint8_t *bitmap = ext2_block_read(fs, block_num: bitmap_block, out: &ent);
29 if (!bitmap)
30 return -1;
31
32 if (!find_free_bit(bitmap, size: fs->block_size, byte_pos: &byte_pos, bit_pos: &bit_pos)) {
33 bcache_ent_release(ent);
34 return -1;
35 }
36
37 bitmap[byte_pos] |= (1 << bit_pos);
38 bcache_ent_release(ent);
39
40 if (!ext2_block_write(fs, ent, EXT2_PRIO_BITMAPS))
41 return -1;
42
43 update_counts(fs, group);
44 return group * items_per_group + (byte_pos * 8 + bit_pos);
45}
46
47static void update_block_counts(struct ext2_fs *fs, uint32_t group) {
48
49 enum irql irql = ext2_fs_lock(fs);
50 fs->group_desc[group].free_blocks_count--;
51 fs->sblock->free_blocks_count--;
52 ext2_fs_unlock(fs, i: irql);
53
54 ext2_write_group_desc(fs);
55 ext2_write_superblock(fs);
56}
57
58static void update_inode_counts(struct ext2_fs *fs, uint32_t group) {
59 fs->group_desc[group].free_inodes_count--;
60 fs->sblock->free_inodes_count--;
61 ext2_write_group_desc(fs);
62 ext2_write_superblock(fs);
63}
64
65uint32_t ext2_alloc_block(struct ext2_fs *fs) {
66 if (!fs)
67 return -1;
68
69 for (uint32_t group = 0; group < fs->num_groups; ++group) {
70 uint32_t block_num =
71 alloc_from_bitmap(fs, bitmap_block: fs->group_desc[group].block_bitmap,
72 items_per_group: fs->blocks_per_group, group, update_counts: update_block_counts);
73 if (block_num != (uint32_t) -1) {
74 return block_num;
75 }
76 }
77 return -1;
78}
79
80bool ext2_free_block(struct ext2_fs *fs, uint32_t block_num) {
81 if (!fs || block_num == 0)
82 return false;
83
84 uint32_t group = block_num / fs->blocks_per_group;
85 uint32_t index = block_num % fs->blocks_per_group;
86
87 uint32_t bitmap_block = fs->group_desc[group].block_bitmap;
88
89 struct bcache_entry *ent;
90 uint8_t *bitmap = ext2_block_read(fs, block_num: bitmap_block, out: &ent);
91 if (!bitmap)
92 return false;
93
94 uint32_t byte = index / 8;
95 uint8_t bit = 1 << (index % 8);
96
97 /* already free */
98 if (!(bitmap[byte] & bit)) {
99 bcache_ent_release(ent);
100 return false;
101 }
102
103 bitmap[byte] &= ~bit;
104 bcache_ent_release(ent);
105 ext2_block_write(fs, ent, EXT2_PRIO_BITMAPS);
106
107 fs->group_desc[group].free_blocks_count++;
108 fs->sblock->free_blocks_count++;
109
110 ext2_write_group_desc(fs);
111 ext2_write_superblock(fs);
112 return true;
113}
114
115inode_t ext2_alloc_inode(struct ext2_fs *fs) {
116 if (!fs)
117 return -1;
118
119 for (uint32_t group = 0; group < fs->num_groups; ++group) {
120 inode_t inode_num =
121 alloc_from_bitmap(fs, bitmap_block: fs->group_desc[group].inode_bitmap,
122 items_per_group: fs->inodes_per_group, group, update_counts: update_inode_counts);
123 if (inode_num != (inode_t) -1) {
124 return inode_num + 1;
125 }
126 }
127 return -1;
128}
129
130bool ext2_free_inode(struct ext2_fs *fs, inode_t inode_num) {
131 if (!fs || inode_num == 0)
132 return false;
133
134 inode_num -= 1;
135 uint32_t group = inode_num / fs->inodes_per_group;
136 uint32_t index = inode_num % fs->inodes_per_group;
137
138 uint32_t bitmap_block = fs->group_desc[group].inode_bitmap;
139
140 struct bcache_entry *ent;
141 uint8_t *bitmap = ext2_block_read(fs, block_num: bitmap_block, out: &ent);
142 if (!bitmap)
143 return false;
144
145 uint32_t byte = index / 8;
146 uint8_t bit = 1 << (index % 8);
147 if (!(bitmap[byte] & bit)) {
148 bcache_ent_release(ent);
149 printf(format: "ext2: Inode %u already free\n", inode_num + 1);
150 return false;
151 }
152
153 bitmap[byte] &= ~bit;
154 bcache_ent_release(ent);
155 ext2_block_write(fs, ent, EXT2_PRIO_BITMAPS);
156
157 fs->group_desc[group].free_inodes_count++;
158 fs->sblock->free_inodes_count++;
159 ext2_write_group_desc(fs);
160 ext2_write_superblock(fs);
161
162 struct ext2_inode empty = {0};
163 ext2_inode_write(fs, inode_num: inode_num + 1, inode: &empty);
164
165 return true;
166}
167