| 1 | #include <block/bcache.h> |
| 2 | #include <console/printf.h> |
| 3 | #include <fs/ext2.h> |
| 4 | #include <stdbool.h> |
| 5 | #include <stdint.h> |
| 6 | |
| 7 | static 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 | |
| 21 | static 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 | |
| 47 | static 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 | |
| 58 | static 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 | |
| 65 | uint32_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 | |
| 80 | bool 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 | |
| 115 | inode_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 | |
| 130 | bool 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 | |