/** * ext2_alloc_block - Allocate a new block id * * This functions allocates a new block from device @dev, and applies * the allocation to the superblock. Outputs to @out */ void ext2_alloc_block(uint32_t *out, struct device *dev) { /* Algorithm: Loop through block group descriptors, * find which bg has a free block * and set that. */ struct ext2_priv_data *priv = EXT2_PRIV(dev); uint8_t *buffer = malloc(priv->blocksize); ext2_read_block(buffer, priv->first_bgd, dev); struct ext2_block_group_desc *bg = (struct ext2_block_group_desc *)buffer; for(int i = 0; i < priv->number_of_bgs; i++) { if(bg->num_of_unalloc_block) { *out = priv->sb.blocks - bg->num_of_unalloc_block + 1; bg->num_of_unalloc_block --; ext2_write_block(buffer, priv->first_bgd + i, dev); ext2_read_block(buffer, priv->sb.superblock_id, dev); struct ext2_superblock *sb = (struct ext2_superblock *)buffer; sb->unallocatedblocks --; ext2_write_block(buffer, priv->sb.superblock_id, dev); goto out; } bg++; } out: free(buffer); }
SFUNC(uint32_t, ext2_allocate_indirect_block, ext2_device_t *device, ext2_inode_t *inode) { int status; size_t block_size = 1024 << device->superblock.block_size_enc; aoff_t size; uint32_t id; status = ext2_alloc_block(device, 0, &id);//TODO: Prevent fragmentation, swap 0 for previous block in inode if (status) THROW(status, 0); inode->blocks += 2 << device->superblock.block_size_enc; if (!ext2_zero_buffer) { ext2_zero_buffer = heapmm_alloc(block_size); memset(ext2_zero_buffer, 0, block_size); } status = ext2_write_block(device, id, 0, ext2_zero_buffer, block_size, &size); if (status) { THROW(status, 0); } RETURN(id); }
SFUNC(aoff_t, ext2_write_inode, inode_t *_inode, void *_buffer, aoff_t f_offset, aoff_t length) { ext2_device_t *device; ext2_vinode_t *inode; aoff_t count; aoff_t block_size; aoff_t in_blk_size; aoff_t rsize; aoff_t in_blk; aoff_t in_file; uint32_t block_addr, p_block_addr; uint8_t *buffer = _buffer; int status; assert( _inode != NULL ); assert( buffer != NULL ); device = (ext2_device_t *) _inode->device; inode = (ext2_vinode_t *) _inode; block_size = 1024 << device->superblock.block_size_enc; p_block_addr = 0; for (count = 0; count < length; count += in_blk_size) { in_file = count + f_offset; in_blk = in_file % block_size; in_blk_size = length - count; if (in_blk_size > (block_size - in_blk)) in_blk_size = block_size - in_blk; status = ext2_decode_block_id (device, &(inode->inode), in_file / block_size, &block_addr); if (status) THROW(status, 0); if (!block_addr) { //debugcon_printf("ext2: growing file!\n"); status = ext2_alloc_block(device, p_block_addr, &block_addr); if (status) THROW(status, 0); status = ext2_set_block_id(device, &(inode->inode), in_file / block_size, block_addr); if (status) THROW(status, 0); inode->inode.blocks += 2 << device->superblock.block_size_enc; } status = ext2_write_block(device, block_addr, in_blk, &(buffer[count]), in_blk_size, &rsize); if (status) THROW(status, 0); p_block_addr = block_addr; } RETURN(count); }
SVFUNC(ext2_free_block, ext2_device_t *device, uint32_t block_id) { uint32_t b_count = device->superblock.block_count; uint32_t bgrp_id = 0; uint32_t bgrp_bcnt = device->superblock.blocks_per_group; uint32_t bm_block_size = 256 << device->superblock.block_size_enc; uint32_t bm_block_bcnt = bm_block_size * 32; uint32_t bm_id; uint32_t block_map[bm_block_size]; uint32_t first_b = device->superblock.block_size_enc ? 0 : 1; uint32_t idx ,nb; aoff_t rsize; int status; ext2_block_group_desc_t *bgd; assert ( device != NULL ); assert (block_id < b_count); assert (block_id > first_b); bgrp_id = (block_id - first_b) / bgrp_bcnt; idx = block_id - first_b - bgrp_id * bgrp_bcnt; bm_id = idx / bm_block_bcnt; idx -= bm_id * bm_block_bcnt; nb = idx % 32; idx -= nb; idx /= 32; status = ext2_load_bgd(device, bgrp_id, &bgd); if (status) THROWV(status); status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize); if (status) THROWV(status); EXT2_BITMAP_CLR(block_map[idx], nb); status = ext2_write_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize); if (status) { debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!"); ext2_handle_error(device); THROWV(status); } bgd->free_block_count++; status = ext2_store_bgd(device, bgrp_id, bgd); if (status) { debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!"); ext2_handle_error(device); THROWV(status); } ext2_free_bgd(device, bgd); device->superblock.free_block_count++; RETURNV; }
int ext2_sb_update(ext2_fs_t *fs, ext2_superblock_t *sb) { int old = sb->block_size; fs->sb->block_size=0; sb->write_time = get_epoch_time(); ext2_write_block(fs, 1, (unsigned char *)sb); fs->sb = sb; sb->block_size = old; return 0; }
/* Write ENTRY item of the inode table from BLOCK_GROUP */ void ext2_write_inode(struct block *b, uint32_t ino_idx, struct inode *inode){ struct ext2_meta_data *meta = NULL; struct bg_desc_table *bg_desc_tabs = NULL; uint32_t block_size = 0; uint32_t inode_table = 0, inodes_per_group = 0, inodes_per_block = 0; uint32_t block_group = 0, block_idx = 0, block_offset = 0; struct inode *inode_tab = NULL; //get meta data ASSERT(b != NULL); meta = ext2_get_meta(b); ASSERT(meta != NULL); bg_desc_tabs = meta->bg_desc_tabs; ASSERT(bg_desc_tabs != NULL); ASSERT(block_group < DIV_ROUND_UP(meta->sb->s_blocks_count, meta->sb->s_blocks_per_group)); inodes_per_group = meta->sb->s_inodes_per_group; block_size = ext2_get_block_size(meta->sb); // get block group ino_idx = ino_idx - 1; // inode index starts from 1 !!! block_group = ino_idx / inodes_per_group; bg_desc_tabs = &bg_desc_tabs[block_group]; // get inode table inode_table = bg_desc_tabs->bg_inode_table; inodes_per_block = block_size/sizeof(struct inode); ASSERT((block_size % sizeof(struct inode)) == 0); // calculate inode index in local table ino_idx -= block_group * inodes_per_group; // get block location of inode block_idx = inode_table + ino_idx/inodes_per_block; block_offset = ino_idx % inodes_per_block; // read block data inode_tab = ext2_read_block(b,block_idx,block_size,NULL); // modify corresponding entry memcpy(&inode_tab[block_offset], inode, sizeof(struct inode)); // write to disk ext2_write_block(b,block_idx,block_size,inode_tab); // release memory kfree(inode_tab); }
SVFUNC(ext2_set_block_id, ext2_device_t *device, ext2_inode_t *inode, uint32_t block_id, uint32_t block_v) { uint32_t indirect_count = 256 << device->superblock.block_size_enc; uint32_t indirect_id, indirect_off, indirect_rd; uint32_t s_indir_l = indirect_count; uint32_t d_indir_l = indirect_count * indirect_count; uint32_t s_indir_s = 12; uint32_t d_indir_s = s_indir_s + s_indir_l; uint32_t t_indir_s = d_indir_s + d_indir_l; int status; aoff_t rsize; assert ( device != NULL ); if (block_id >= t_indir_s) { //Triply indirect indirect_id = inode->block[14]; indirect_off = (block_id - t_indir_s) / d_indir_l; if (!indirect_id) { status = ext2_allocate_indirect_block(device, inode, &indirect_id); if (status) THROWV(status); inode->block[14] = indirect_id; } status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize); if (status) THROWV(status); if (!indirect_rd) { status = ext2_allocate_indirect_block(device, inode, &indirect_id); if (status) THROWV(status); status = ext2_write_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize); if (status) THROWV(status); } indirect_id = indirect_rd; block_id -= indirect_off * d_indir_l + d_indir_l; } else if (block_id >= d_indir_s) { indirect_id = inode->block[13]; if (!indirect_id) { status = ext2_allocate_indirect_block(device, inode, &indirect_id); if (status) THROWV(status); inode->block[13] = indirect_id; } } if (block_id >= d_indir_s) { //Doubly indirect indirect_off = (block_id - d_indir_s) / s_indir_l; status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize); if (status) THROWV(status); if (!indirect_rd) { status = ext2_allocate_indirect_block(device, inode, &indirect_id); if (status) THROWV(status); status = ext2_write_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize); if (status) THROWV(status); } indirect_id = indirect_rd; block_id -= s_indir_l + indirect_off * s_indir_l; } else if (block_id >= s_indir_s){ indirect_id = inode->block[12]; if (!indirect_id) { status = ext2_allocate_indirect_block(device, inode, &indirect_id); if (status) THROWV(status); inode->block[12] = indirect_id; } } if (block_id >= s_indir_s) { //Singly Indirect indirect_off = block_id - s_indir_s; status = ext2_write_block(device, indirect_id, indirect_off * 4, &block_v, 4, &rsize); if (status) THROWV(status); RETURNV; } inode->block[block_id] = block_v; RETURNV; }
SFUNC(uint32_t, ext2_alloc_block, ext2_device_t *device, uint32_t start) { uint32_t b_count = device->superblock.block_count; uint32_t block_id = start; uint32_t bgrp_id = 0; uint32_t bgrp_bcnt = device->superblock.blocks_per_group; uint32_t bgrp_count = ext2_divup(b_count,bgrp_bcnt);//DIVUP uint32_t bm_block_size = 256 << device->superblock.block_size_enc; uint32_t bm_block_bcnt = bm_block_size * 32; uint32_t bgrp_bmcnt = ext2_divup(bgrp_bcnt,bm_block_bcnt);//DIVUP uint32_t bm_id; uint32_t block_map[bm_block_size]; uint32_t first_b = device->superblock.block_size_enc ? 0 : 1; uint32_t idx ,nb; aoff_t rsize; int status; ext2_block_group_desc_t *bgd; assert ( device != NULL ); assert (start < b_count); if (start == 0) block_id = first_b; bgrp_id = (block_id - first_b) / bgrp_bcnt; idx = block_id - first_b - bgrp_id * bgrp_bcnt; bm_id = idx / bm_block_bcnt; idx -= bm_id * bm_block_bcnt; nb = idx % 32; idx -= nb; idx /= 32; for (; bgrp_id < bgrp_count; bgrp_id++) { status = ext2_load_bgd(device, bgrp_id, &bgd); if (status) THROW(status, 0); if (bgd->free_block_count) { for (; bm_id < bgrp_bmcnt; bm_id++) { status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize); if (status) THROW(status, 0); for (; idx < bm_block_size; idx++) { if (block_map[idx] != 0xFFFFFFFF) { for (; nb < 32; nb++) if (!EXT2_BITMAP_GET(block_map[idx], nb)) goto found_it; } nb = 0; } idx = 0; } } bm_id = 0; ext2_free_bgd(device, bgd); } bgrp_id = 0; for (; bgrp_id < bgrp_count; bgrp_id++) { status = ext2_load_bgd(device, bgrp_id, &bgd); if (status) THROW(status, 0); if (bgd->free_block_count) { for (; bm_id < bgrp_bmcnt; bm_id++) { status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize); if (status) THROW(status, 0); for (; idx < bm_block_size; idx++) { if (block_map[idx] != 0xFFFFFFFF) { for (; nb < 32; nb++) if (!EXT2_BITMAP_GET(block_map[idx], nb)) goto found_it; } nb = 0; } idx = 0; } } bm_id = 0; ext2_free_bgd(device, bgd); } THROW(ENOSPC, 0); found_it: block_id = nb + idx * 32 + bm_id * bm_block_bcnt + bgrp_id * bgrp_bcnt + first_b; EXT2_BITMAP_SET(block_map[idx], nb); status = ext2_write_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize); if (status) { debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!"); ext2_handle_error(device); THROW(status, 0); } bgd->free_block_count--; status = ext2_store_bgd(device, bgrp_id, bgd); if (status) { debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!"); ext2_handle_error(device); THROW(status, 0); } ext2_free_bgd(device, bgd); device->superblock.free_block_count--; memset(block_map, 0, bm_block_size * 4); status = ext2_write_block(device, block_id, 0, block_map, bm_block_size * 4, &rsize); if (status) { debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block clear)!"); ext2_handle_error(device); THROW(status, 0); } RETURN(block_id); }
bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, ULONG dwContent, ULONG Index, int layer, ULONG newBlk, ULONG *dwRet, ULONG *off ) { ULONG *pData = NULL; ULONG i = 0, j = 0, temp = 1; ULONG dwBlk; ULONG dwNewBlk = newBlk; bool bDirty = false; bool bRet = true; ULONG Offset = 0; PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize); if (!pData) { bRet = false; goto errorout; } if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) { bRet = false; goto errorout; } if (layer == 1) { *dwRet = dwContent; *off = Index; pData[Index] = newBlk; bDirty = TRUE; } else if (layer <= 3) { temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); i = Index / temp; j = Index % temp; dwBlk = pData[i]; if (dwBlk == 0) { if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) { pData[i] = dwBlk; bDirty = true; Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); } if (!bDirty) goto errorout; } if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset)) { bRet = false; DPRINT1("Mke2fs: ext2_expand_block: ... error recuise...\n"); goto errorout; } } if (bDirty) { bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData); } errorout: if (pData) RtlFreeHeap(RtlGetProcessHeap(), 0, pData); if (bRet && dwRet) *dwRet = dwNewBlk; return bRet; }
static int inode_shrink_range(uint32_t block_id, uint32_t level, uint32_t start, uint32_t end, uint32_t items_per_block,uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3){ struct block *d = block_get_role(BLOCK_FILESYS); uint32_t item_start, item_end; uint32_t *level_data; uint32_t block_id2; int i, ret = 0; enum RANGE range_comparison; ASSERT(d != NULL); ASSERT(level > 0); level_data = ext2_read_block(d,block_id,items_per_block*sizeof(uint32_t),NULL); for(i = 0; i < items_per_block; i++){ // Get Block range the item represents if(level == 1){ item_start = inode_get_direct_block_idx(items_per_block,l0,i,0,0); item_end = inode_get_direct_block_idx(items_per_block,l0,i,items_per_block-1,items_per_block-1); } else if (level == 2){ item_start = inode_get_direct_block_idx(items_per_block,l0,l1,i,0); item_end = inode_get_direct_block_idx(items_per_block,l0,l1,i,items_per_block-1); } else { item_start = inode_get_direct_block_idx(items_per_block,l0,l1,l2,i); item_end = item_start; } // Compare range range_comparison = inode_range_compare(item_start,item_end,start,end); if((range_comparison & RANGE_OVERLAP) > 0){ // In Range block_id2 = level_data[i]; // If the block is cleared already. if(block_id2 == 0) continue; /* If it is a leaf node */ if(item_start == item_end) { // free block and set entry to zero freemap_free_block(block_id2); level_data[i] = 0; continue; } /* If not a leaf node*/ // free sub level if(level == 1) inode_shrink_range(block_id2,level+1,start,end,items_per_block,l0,i,0,0); else if(level == 2) inode_shrink_range(block_id2,level+1,start,end,items_per_block,l0,l1,i,0); else PANIC("Inode Shrink Range Reach Unexpected Level.\n"); // if shrink range contains entire level if(start <= item_start){ // free block and set entry to zero freemap_free_block(block_id2); level_data[i] = 0; } } else if((range_comparison & RANGE_AHEAD) > 0){ //Item Ahead of start continue; } else{ // Item Passed End break; } } ext2_write_block(d,block_id,items_per_block*sizeof(uint32_t),level_data); kfree(level_data); return ret; }
static int inode_expand_range(uint32_t block_id, uint32_t level, uint32_t start, uint32_t end, uint32_t items_per_block,uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3){ struct block *d = block_get_role(BLOCK_FILESYS); uint32_t item_start, item_end; uint32_t *level_data; uint32_t block_id2; int i, ret = 0; enum RANGE range_comparison; ASSERT(d != NULL); ASSERT(level > 0); level_data = ext2_read_block(d,block_id,items_per_block*sizeof(uint32_t),NULL); for(i = 0; i < items_per_block; i++){ // Get Block range the item represents if(level == 1){ item_start = inode_get_direct_block_idx(items_per_block,l0,i,0,0); item_end = inode_get_direct_block_idx(items_per_block,l0,i,items_per_block-1,items_per_block-1); } else if (level == 2){ item_start = inode_get_direct_block_idx(items_per_block,l0,l1,i,0); item_end = inode_get_direct_block_idx(items_per_block,l0,l1,i,items_per_block-1); } else { item_start = inode_get_direct_block_idx(items_per_block,l0,l1,l2,i); item_end = item_start; } // Compare range range_comparison = inode_range_compare(item_start,item_end,start,end); if((range_comparison & RANGE_OVERLAP) > 0){ // In Range block_id2 = level_data[i]; // Allocate block in disk if not exist. if(block_id2 == 0){ if(item_start == item_end) block_id2 = freemap_get_block(false); else block_id2 = freemap_get_block(true); #ifdef FILESYS_EXT2_DEBUG printf(" New block id: 0x%x for %d/%d/%d/%d:%d\n", block_id2,l0,l1,l2,l3,i); #endif } if(block_id2 != FREEMAP_GET_ERROR) {level_data[i] = block_id2;} else {ret = -1; break;} /* If it is a leaf node */ if(item_start == item_end) continue; /* If not leaf node*/ if(level == 1) inode_expand_range(block_id2,level+1,start,end,items_per_block,l0,i,0,0); else if(level == 2) inode_expand_range(block_id2,level+1,start,end,items_per_block,l0,l1,i,0); else PANIC("Inode Fill Range Reach Unexpected Level.\n"); } else if((range_comparison & RANGE_AHEAD) > 0){ //Ahead of start continue; } else{ // Passed End break; } } ext2_write_block(d,block_id,items_per_block*sizeof(uint32_t),level_data); kfree(level_data); return ret; }
/* inode read from given position */ off_t inode_write_at(struct block *d, struct inode *inode, const void *buffer_, off_t size, off_t offset){ struct ext2_meta_data *meta; uint32_t block_size,block_id,block_idx,block_ofs; const uint8_t *buffer = buffer_; uint8_t *bounce = NULL; off_t bytes_written = 0, err; ASSERT(d != NULL && inode != NULL); // Resize inode err = inode_resize(inode,offset + size); if(err < 0) { printf("inode_write_at: resize failed.\n"); return 0; } // get device meta data meta = ext2_get_meta(d); ASSERT(meta != NULL && meta->sb != NULL); block_size = ext2_get_block_size(meta->sb); // read from disk while(size > 0){ // get data block id block_idx = offset / block_size; // the nth data block block_ofs = offset % block_size; // byte offset with data block block_id = inode_get_data_block(d,inode,block_idx); // data block id in fs ASSERT(block_id != UINT32_MAX); // Calculate bytes to write // off_t is signed. off_t inode_left = inode->i_size - offset; off_t block_left = block_size - block_ofs; off_t min_left = inode_left < block_left ? inode_left : block_left; off_t chunk_size = size < min_left ? size : min_left; // no bytes to be read if(chunk_size <= 0) break; // whole block data if(block_ofs == 0 && chunk_size == block_size) ext2_write_block(d,block_id,block_size,buffer+bytes_written); else{ if(bounce == NULL){ bounce = kmalloc(block_size); if(bounce == NULL) break; } // First read the block from disk ext2_read_block(d,block_id,block_size,bounce); // Modify data read memcpy(bounce+block_ofs,buffer+bytes_written,chunk_size); // Write to disk ext2_write_block(d,block_id,block_size,bounce); } // advance. size -= chunk_size; offset += chunk_size; bytes_written += chunk_size; } if(bounce != NULL) kfree(bounce); return bytes_written; }
SFUNC(uint32_t, ext2_alloc_inode, ext2_device_t *device) { uint32_t i_count = device->superblock.inode_count; uint32_t inode_id = 11; uint32_t bgrp_id = 0; uint32_t bgrp_icnt = device->superblock.inodes_per_group; uint32_t bgrp_count = ext2_divup(i_count,bgrp_icnt);//DIVUP uint32_t bm_block_size = 256 << device->superblock.block_size_enc; uint32_t bm_block_icnt = bm_block_size * 32; uint32_t bgrp_bmcnt = ext2_divup(bgrp_icnt,bm_block_icnt);//DIVUP uint32_t bm_id; uint32_t inode_map[bm_block_size]; uint32_t first_i = 1; uint32_t idx ,nb; aoff_t rsize; int status; ext2_block_group_desc_t *bgd; assert ( device != NULL ); bgrp_id = (inode_id - first_i) / bgrp_icnt; idx = inode_id - first_i - bgrp_id * bgrp_icnt; bm_id = idx / bm_block_icnt; idx -= bm_id * bm_block_icnt; nb = idx % 32; idx -= nb; idx /= 32; for (; bgrp_id < bgrp_count; bgrp_id++) { status = ext2_load_bgd(device, bgrp_id, &bgd); if (status) THROW(status, 0); if (bgd->free_inode_count) { for (; bm_id < bgrp_bmcnt; bm_id++) { status = ext2_read_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, &rsize); if (status) THROW(status, 0); for (; idx < bm_block_size; idx++) { if (inode_map[idx] != 0xFFFFFFFF) { for (; nb < 32; nb++) if (!EXT2_BITMAP_GET(inode_map[idx], nb)) goto found_it; } nb = 0; } idx = 0; } } bm_id = 0; ext2_free_bgd(device, bgd); } bgrp_id = 0; THROW(ENOSPC, 0); found_it: inode_id = nb + idx * 32 + bm_id * bm_block_icnt + bgrp_id * bgrp_icnt + first_i; EXT2_BITMAP_SET(inode_map[idx], nb); status = ext2_write_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, &rsize); if (status) { debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (inode bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!"); ext2_handle_error(device); THROW(status, 0); } bgd->free_inode_count--; status = ext2_store_bgd(device, bgrp_id, bgd); if (status) { debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!"); ext2_handle_error(device); THROW(status, 0); } ext2_free_bgd(device, bgd); device->superblock.free_inode_count--; RETURN(inode_id); }