Fork me on GitHub

root/fs/ext2/bitmaps.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_first_zero
  2. change_bit
  3. ext2_ialloc
  4. ext2_ifree
  5. ext2_balloc
  6. ext2_bfree

   1 /*
   2  * fiwix/fs/ext2/bitmaps.c
   3  *
   4  * Copyright 2019, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/kernel.h>
   9 #include <fiwix/types.h>
  10 #include <fiwix/fs.h>
  11 #include <fiwix/filesystems.h>
  12 #include <fiwix/fs_ext2.h>
  13 #include <fiwix/buffer.h>
  14 #include <fiwix/errno.h>
  15 #include <fiwix/stat.h>
  16 #include <fiwix/stdio.h>
  17 #include <fiwix/string.h>
  18 
  19 static int find_first_zero(struct superblock *sb, __blk_t block)
  20 {
  21         unsigned char c;
  22         int blksize;
  23         int n, n2;
  24         struct buffer *buf;
  25 
  26         blksize = sb->s_blocksize;
  27 
  28         if(!(buf = bread(sb->dev, block, blksize))) {
  29                 return -EIO;
  30         }
  31         for(n = 0; n < blksize; n++) {
  32                 c = (unsigned char)buf->data[n];
  33                 for(n2 = 0; n2 < 8; n2++) {
  34                         if(!(c & (1 << n2))) {
  35                                 brelse(buf);
  36                                 return n2 + (n * 8) + 1;
  37                         }
  38                 }
  39         }
  40         brelse(buf);
  41         return 0;
  42 }
  43 
  44 static int change_bit(int mode, struct superblock *sb, __blk_t block, int item)
  45 {
  46         int byte, bit, mask;
  47         struct buffer *buf;
  48 
  49         block += item / (sb->s_blocksize * 8);
  50         byte = (item % (sb->s_blocksize * 8)) / 8;
  51         bit = (item % (sb->s_blocksize * 8)) % 8;
  52         mask = 1 << bit;
  53 
  54         if(!(buf = bread(sb->dev, block, sb->s_blocksize))) {
  55                 return -EIO;
  56         }
  57 
  58         if(mode == CLEAR_BIT) {
  59                 if(!(buf->data[byte] & mask)) {
  60                         brelse(buf);
  61                         return 1;
  62                 }
  63                 buf->data[byte] &= ~mask;
  64         }
  65         if(mode == SET_BIT) {
  66                 if((buf->data[byte] & mask)) {
  67                         brelse(buf);
  68                         return 1;
  69                 }
  70                 buf->data[byte] |= mask;
  71         }
  72 
  73         bwrite(buf);
  74         return 0;
  75 }
  76 
  77 /*
  78  * Unlike of what Ext2 specifies/suggests, this inode allocation does NOT
  79  * try to assign inodes in the same block group of the directory in which
  80  * they will be created.
  81  */
  82 int ext2_ialloc(struct inode *i, int mode)
  83 {
  84         __ino_t inode;
  85         __blk_t block;
  86         struct superblock *sb;
  87         struct ext2_group_desc *gd;
  88         struct buffer *buf;
  89         int bg, d, errno;
  90 
  91         sb = i->sb;
  92         superblock_lock(sb);
  93 
  94         block = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;
  95         inode = 0;
  96         buf = NULL;
  97 
  98         /* read through all group descriptors to find the first unallocated inode */
  99         for(bg = 0, d = 0; bg < sb->u.ext2.block_groups; bg++, d++) {
 100                 if(!(bg % (sb->s_blocksize / sizeof(struct ext2_group_desc)))) {
 101                         if(buf) {
 102                                 brelse(buf);
 103                                 block++;
 104                                 d = 0;
 105                         }
 106                         if(!(buf = bread(sb->dev, block, sb->s_blocksize))) {
 107                                 superblock_unlock(sb);
 108                                 return -EIO;
 109                         }
 110                 }
 111                 gd = (struct ext2_group_desc *)(buf->data + (d * sizeof(struct ext2_group_desc)));
 112                 if(gd->bg_free_inodes_count) {
 113                         if((inode = find_first_zero(sb, gd->bg_inode_bitmap))) {
 114                                 break;
 115                         }
 116                 }
 117         }
 118         if(!inode) {
 119                 brelse(buf);
 120                 superblock_unlock(sb);
 121                 return -ENOSPC;
 122         }
 123 
 124         errno = change_bit(SET_BIT, sb, gd->bg_inode_bitmap, inode - 1);
 125         if(errno) {
 126                 if(errno < 0) {
 127                         printk("WARNING: %s(): unable to set inode %d.\n", __FUNCTION__, inode);
 128                         brelse(buf);
 129                         superblock_unlock(sb);
 130                         return errno;
 131                 } else {
 132                         printk("WARNING: %s(): inode %d is already marked as used!\n", __FUNCTION__, inode);
 133                 }
 134         }
 135 
 136         inode += bg * EXT2_INODES_PER_GROUP(sb);
 137         gd->bg_free_inodes_count--;
 138         sb->u.ext2.sb.s_free_inodes_count--;
 139         if(S_ISDIR(mode)) {
 140                 gd->bg_used_dirs_count++;
 141         }
 142         bwrite(buf);
 143 
 144         i->inode = inode;
 145         i->i_atime = CURRENT_TIME;
 146         i->i_mtime = CURRENT_TIME;
 147         i->i_ctime = CURRENT_TIME;
 148 
 149         superblock_unlock(sb);
 150         return 0;
 151 }
 152 
 153 void ext2_ifree(struct inode *i)
 154 {
 155         struct ext2_group_desc *gd;
 156         struct buffer *buf;
 157         struct superblock *sb;
 158         __blk_t b, bg;
 159         int errno;
 160 
 161         if(!i->inode || i->inode > i->sb->u.ext2.sb.s_inodes_count) {
 162                 printk("WARNING: %s(): invalid inode %d!\n", __FUNCTION__, i->inode);
 163                 return;
 164         }
 165 
 166         if(i->i_blocks) {
 167                 ext2_truncate(i, 0);
 168         }
 169 
 170         sb = i->sb;
 171         superblock_lock(sb);
 172 
 173         b = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;
 174         bg = (i->inode - 1) / EXT2_INODES_PER_GROUP(sb);
 175         if(!(buf = bread(sb->dev, b + (bg / EXT2_DESC_PER_BLOCK(sb)), sb->s_blocksize))) {
 176                 superblock_unlock(sb);
 177                 return;
 178         }
 179         gd = (struct ext2_group_desc *)(buf->data + ((bg % EXT2_DESC_PER_BLOCK(sb)) * sizeof(struct ext2_group_desc)));
 180         errno = change_bit(CLEAR_BIT, sb, gd->bg_inode_bitmap, (i->inode - 1) % EXT2_INODES_PER_GROUP(sb));
 181 
 182         if(errno) {
 183                 if(errno < 0) {
 184                         printk("WARNING: %s(): unable to clear inode %d.\n", __FUNCTION__, i->inode);
 185                         brelse(buf);
 186                         superblock_unlock(sb);
 187                         return;
 188                 } else {
 189                         printk("WARNING: %s(): inode %d is already marked as free!\n", __FUNCTION__, i->inode);
 190                 }
 191         }
 192 
 193         gd->bg_free_inodes_count++;
 194         sb->u.ext2.sb.s_free_inodes_count++;
 195         if(S_ISDIR(i->i_mode)) {
 196                 gd->bg_used_dirs_count--;
 197         }
 198         bwrite(buf);
 199 
 200         i->i_size = 0;
 201         i->i_mtime = CURRENT_TIME;
 202         i->i_ctime = CURRENT_TIME;
 203         i->dirty = 1;
 204 
 205         superblock_unlock(sb);
 206         return;
 207 }
 208 
 209 int ext2_balloc(struct superblock *sb)
 210 {
 211         __blk_t b, block;
 212         struct ext2_group_desc *gd;
 213         struct buffer *buf;
 214         int bg, d, errno;
 215 
 216         superblock_lock(sb);
 217 
 218         b = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;
 219         block = 0;
 220         buf = NULL;
 221 
 222         /* read through all group descriptors to find the first unallocated block */
 223         for(bg = 0, d = 0; bg < sb->u.ext2.block_groups; bg++, d++) {
 224                 if(!(bg % (sb->s_blocksize / sizeof(struct ext2_group_desc)))) {
 225                         if(buf) {
 226                                 brelse(buf);
 227                                 b++;
 228                                 d = 0;
 229                         }
 230                         if(!(buf = bread(sb->dev, b, sb->s_blocksize))) {
 231                                 superblock_unlock(sb);
 232                                 return -EIO;
 233                         }
 234                 }
 235                 gd = (struct ext2_group_desc *)(buf->data + (d * sizeof(struct ext2_group_desc)));
 236                 if(gd->bg_free_blocks_count) {
 237                         if((block = find_first_zero(sb, gd->bg_block_bitmap))) {
 238                                 break;
 239                         }
 240                 }
 241         }
 242         if(!block) {
 243                 brelse(buf);
 244                 superblock_unlock(sb);
 245                 return -ENOSPC;
 246         }
 247 
 248         errno = change_bit(SET_BIT, sb, gd->bg_block_bitmap, block - 1);
 249         if(errno) {
 250                 if(errno < 0) {
 251                         printk("WARNING: %s(): unable to set block %d.\n", __FUNCTION__, block);
 252                         brelse(buf);
 253                         superblock_unlock(sb);
 254                         return errno;
 255                 } else {
 256                         printk("WARNING: %s(): block %d is already marked as used!\n", __FUNCTION__, block);
 257                 }
 258         }
 259 
 260         block += bg * EXT2_BLOCKS_PER_GROUP(sb);
 261         gd->bg_free_blocks_count--;
 262         sb->u.ext2.sb.s_free_blocks_count--;
 263         bwrite(buf);
 264 
 265         superblock_unlock(sb);
 266         return block;
 267 }
 268 
 269 void ext2_bfree(struct superblock *sb, int block)
 270 {
 271         struct ext2_group_desc *gd;
 272         struct buffer *buf;
 273         __blk_t b, bg;
 274         int errno;
 275 
 276         if(!block || block > sb->u.ext2.sb.s_blocks_count) {
 277                 printk("WARNING: %s(): invalid block %d!\n", __FUNCTION__, block);
 278                 return;
 279         }
 280 
 281         superblock_lock(sb);
 282 
 283         b = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;
 284         bg = (block - 1) / EXT2_BLOCKS_PER_GROUP(sb);
 285         if(!(buf = bread(sb->dev, b + (bg / EXT2_DESC_PER_BLOCK(sb)), sb->s_blocksize))) {
 286                 superblock_unlock(sb);
 287                 return;
 288         }
 289         gd = (struct ext2_group_desc *)(buf->data + ((bg % EXT2_DESC_PER_BLOCK(sb)) * sizeof(struct ext2_group_desc)));
 290         errno = change_bit(CLEAR_BIT, sb, gd->bg_block_bitmap, (block - 1) % EXT2_BLOCKS_PER_GROUP(sb));
 291 
 292         if(errno) {
 293                 if(errno < 0) {
 294                         printk("WARNING: %s(): unable to free block %d.\n", __FUNCTION__, block);
 295                         brelse(buf);
 296                         superblock_unlock(sb);
 297                         return;
 298                 } else {
 299                         printk("WARNING: %s(): block %d is already marked as free!\n", __FUNCTION__, block);
 300                 }
 301         }
 302 
 303         gd->bg_free_blocks_count++;
 304         sb->u.ext2.sb.s_free_blocks_count++;
 305         bwrite(buf);
 306 
 307         superblock_unlock(sb);
 308         return;
 309 }

/* [previous][next][first][last][top][bottom][index][help] */