PUBLIC block_t ext2_alloc_block(ext2_inode_t * pin) { ext2_superblock_t * psb = pin->i_sb; block_t block = 0; if (psb->sb_readonly) { printl("ext2fs: alloc_block: try to allocate block on readonly filesystem!"); err_code = EROFS; return 0; } int group = (pin->i_num - 1) / psb->sb_inodes_per_group; block_t goal = psb->sb_blocks_per_group*group + psb->sb_first_data_block; off_t startp= ((goal - psb->sb_first_data_block) % psb->sb_blocks_per_group) / (sizeof(bitchunk_t) * CHAR_BIT); int i; for (i = 0; i <= psb->sb_groups_count; i++, group++) { ext2_buffer_t * pb; ext2_bgdescriptor_t * gd; if (group >= psb->sb_groups_count) group = 0; gd = get_ext2_group_desc(psb, group); if (gd == NULL) panic("ext2fs: alloc_block: can't get block group descriptor to alloc block"); if (gd->free_blocks_count == 0) { startp = 0; continue; } pb = ext2_get_buffer(psb->sb_dev, gd->block_bitmap); int bit = ext2_setbit((bitchunk_t*)pb->b_data, psb->sb_blocks_per_group, startp); if (bit == -1) { if (startp == 0) { panic("ext2fs: alloc_block: failed to allocate bit in bitmap with free bits"); } else { startp = 0; continue; } } block = psb->sb_first_data_block + group * psb->sb_blocks_per_group + bit; pb->b_dirt = 1; ext2_put_buffer(pb); gd->free_blocks_count--; psb->sb_free_blocks_count--; ext2_update_group_desc(psb, group); return block; } return block; }
/** * Allocate a bit in the inode bitmap. * @param psb Ptr to the superblock. * @param parent The parent directory. * @param mode Inode mode. * @return Inode number. */ PRIVATE int ext2_alloc_inode_bit(ext2_superblock_t * psb, ext2_inode_t * parent, mode_t mode) { /* Can't allocate inode on readonly filesystem */ if (psb->sb_readonly) { panic("ext2fs: ext2_alloc_inode_bit: can't allocate inode on readonly filesystem."); } ext2_bgdescriptor_t * group = NULL; ext2_bgdescriptor_t * bgdesc = psb->sb_bgdescs; int i; for (i = 0; i < psb->sb_groups_count; i++, bgdesc++) { if (bgdesc->free_inodes_count > 0) { group = bgdesc; break; } } /* No space */ if (group == NULL) return 0; ext2_buffer_t * pb = ext2_get_buffer(psb->sb_dev, group->inode_bitmap); int bit = ext2_setbit((bitchunk_t*)(pb->b_data), psb->sb_inodes_per_group, 0); ino_t num = (group - psb->sb_bgdescs) * psb->sb_inodes_per_group + bit + 1; if (num > psb->sb_inodes_count) { panic("ext2fs: ext2_alloc_inode_bit: num > total number of inodes."); } if (num < psb->sb_first_ino) { panic("ext2fs: ext2_alloc_inode_bit: try to allocate reserved inode."); } pb->b_dirt = 1; ext2_put_buffer(pb); psb->sb_free_inodes_count--; group->free_inodes_count--; /* write back the changes */ write_ext2_super_block(psb->sb_dev); ext2_update_group_desc(psb, group - psb->sb_bgdescs); return num; }
static uint32_t ext2_alloc_block_bit(struct nas *nas, uint32_t goal) { /* try to allocate near this block */ uint32_t block; /* allocated block */ int word; /* word in block bitmap */ uint32_t bit; int group; char update_bsearch = 0; int i; struct ext2_gd *gd; struct ext2_file_info *fi; struct ext2_fs_info *fsi; fi = nas->fi->privdata; fsi = nas->fs->fsi; block = NO_BLOCK; bit = -1; if (goal >= fsi->e2sb.s_blocks_count || (goal < fsi->e2sb.s_first_data_block && goal != 0)) { goal = fsi->s_bsearch; } if (goal <= fsi->s_bsearch) { /* No reason to search in a place with no free blocks */ goal = fsi->s_bsearch; update_bsearch = DIRTY; } /* Figure out where to start the bit search. */ word = ((goal - fsi->e2sb.s_first_data_block) % fsi->e2sb.s_blocks_per_group) / FS_BITCHUNK_BITS; /* Try to allocate block at any group starting from the goal's group. * First time goal's group is checked from the word=goal, after all * groups checked, it's checked again from word=0, that's why "i <=". */ group = (goal - fsi->e2sb.s_first_data_block) / fsi->e2sb.s_blocks_per_group; for (i = 0; i <= fsi->s_groups_count; i++, group++) { if (group >= fsi->s_groups_count) { group = 0; } gd = ext2_get_group_desc(group, fsi); if (gd->free_blocks_count == 0) { word = 0; continue; } ext2_read_sector(nas, fi->f_buf, 1, gd->block_bitmap); bit = ext2_setbit(b_bitmap(fi->f_buf), fsi->e2sb.s_blocks_per_group, word); if (-1 == bit) { if (0 == word) { /* allocator failed to allocate a bit in bitmap with free bits.*/ return 0; } else { word = 0; continue; } } block = fsi->e2sb.s_first_data_block + group * fsi->e2sb.s_blocks_per_group + bit; if (ext2_check_block_number(block, fsi, gd)) { return 0; } ext2_write_sector(nas, fi->f_buf, 1, gd->block_bitmap); fsi->e2sb.s_free_blocks_count--; ext2_write_sblock(nas); gd->free_blocks_count--; ext2_write_gdblock(nas); if (update_bsearch && block != -1 && block != NO_BLOCK) { /* We searched from the beginning, update bsearch. */ fsi->s_bsearch = block; } return block; } return block; }