/** * Shrink an indirect block. * * @param fs The file system data. * @param map The map the allocation is for. * @param buffer The buffer the indirect block is accessed by. * @param indirect The index index in the inode's block table. * @param index The index in the indirect table of the block. * @return int The error number (errno). No error if 0. */ static int rtems_rfs_block_map_indirect_shrink (rtems_rfs_file_system* fs, rtems_rfs_block_map* map, rtems_rfs_buffer_handle* buffer, rtems_rfs_block_no indirect, rtems_rfs_block_no index) { int rc = 0; /* * If this is the first block in the indirect table (index == 0), ie the last * block to be freed and the indirect block is now also free, or we have only * one indirect table and we can fit the remaining blocks into the inode, * then either move to the next indirect block or move the remaining blocks * into the inode and free the indirect table's block. */ if ((index == 0) || ((indirect == 0) && (index == RTEMS_RFS_INODE_BLOCKS))) { rtems_rfs_block_no block_to_free = map->blocks[indirect]; if ((indirect == 0) && (index == RTEMS_RFS_INODE_BLOCKS)) { /* * Move to direct inode access. */ int b; for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++) map->blocks[b] = rtems_rfs_block_get_number (buffer, b); } else { /* * One less singly indirect block in the inode. */ map->blocks[indirect] = 0; } rc = rtems_rfs_group_bitmap_free (fs, false, block_to_free); if (rc > 0) return rc; map->last_map_block = block_to_free; } return rc; }
/** * Allocate an indirect block to a map. * * @param fs The file system data. * @param map The map the allocation is for. * @param buffer The buffer the indirect block is accessed by. * @param block The block number of the indirect block allocated. * @param upping True is upping the map to the next indirect level. * @return int The error number (errno). No error if 0. */ static int rtems_rfs_block_map_indirect_alloc (rtems_rfs_file_system* fs, rtems_rfs_block_map* map, rtems_rfs_buffer_handle* buffer, rtems_rfs_block_no* block, bool upping) { rtems_rfs_bitmap_bit new_block; int rc; /* * Save the new block locally because upping can have *block pointing to the * slots which are cleared when upping. */ rc = rtems_rfs_group_bitmap_alloc (fs, map->last_map_block, false, &new_block); if (rc > 0) return rc; rc = rtems_rfs_buffer_handle_request (fs, buffer, new_block, false); if (rc > 0) { rtems_rfs_group_bitmap_free (fs, false, new_block); return rc; } memset (rtems_rfs_buffer_data (buffer), 0xff, rtems_rfs_fs_block_size (fs)); if (upping) { int b; if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_GROW)) printf ("rtems-rfs: block-map-grow: upping: block-count=%" PRId32 "\n", map->size.count); for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++) rtems_rfs_block_set_number (buffer, b, map->blocks[b]); memset (map->blocks, 0, sizeof (map->blocks)); } rtems_rfs_buffer_mark_dirty (buffer); *block = new_block; map->last_map_block = new_block; return 0; }
int rtems_rfs_block_map_shrink (rtems_rfs_file_system* fs, rtems_rfs_block_map* map, size_t blocks) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_SHRINK)) printf ("rtems-rfs: block-map-shrink: entry: blocks=%zd count=%" PRIu32 "\n", blocks, map->size.count); if (map->size.count == 0) return 0; if (blocks > map->size.count) blocks = map->size.count; while (blocks) { rtems_rfs_block_no block; rtems_rfs_block_no block_to_free; int rc; block = map->size.count - 1; if (block < RTEMS_RFS_INODE_BLOCKS) { /* * We have less than RTEMS_RFS_INODE_BLOCKS so they are held in the * inode. */ block_to_free = map->blocks[block]; map->blocks[block] = 0; } else { /* * Single indirect access is occuring. It could still be doubly indirect. * * The 'direct' variable is the offset in to the indirect table of * blocks, and 'singly' is the inode block index of the singly indirect * table of block numbers. */ rtems_rfs_block_no direct; rtems_rfs_block_no singly; direct = block % fs->blocks_per_block; singly = block / fs->blocks_per_block; if (block < fs->block_map_singly_blocks) { /* * Request the indirect block and then obtain the block number from the * indirect block. */ rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer, map->blocks[singly], true); if (rc > 0) return rc; block_to_free = rtems_rfs_block_get_number (&map->singly_buffer, direct); rc = rtems_rfs_block_map_indirect_shrink (fs, map, &map->singly_buffer, singly, direct); if (rc) return rc; } else if (block < fs->block_map_doubly_blocks) { /* * Doubly indirect tables are being used. The 'doubly' variable is the * index in to the inode's block table and points to a singly indirect * table of block numbers. The 'doubly_singly' variable is the index * into the doubly indirect table pointing to the singly indirect table * of block numbers that form the map. This is used later to determine * if the current doubly indirect table needs to be freed. The 'direct' * value is still valid for doubly indirect tables. */ rtems_rfs_block_no doubly; rtems_rfs_block_no doubly_singly; doubly = singly / fs->blocks_per_block; doubly_singly = singly % fs->blocks_per_block; rc = rtems_rfs_buffer_handle_request (fs, &map->doubly_buffer, map->blocks[doubly], true); if (rc > 0) return rc; singly = rtems_rfs_block_get_number (&map->doubly_buffer, doubly_singly); /* * Read the singly indirect table and get the block number. */ rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer, singly, true); if (rc > 0) return rc; block_to_free = rtems_rfs_block_get_number (&map->singly_buffer, direct); if (direct == 0) { rc = rtems_rfs_group_bitmap_free (fs, false, singly); if (rc > 0) return rc; map->last_map_block = singly; rc = rtems_rfs_block_map_indirect_shrink (fs, map, &map->doubly_buffer, doubly, doubly_singly); if (rc) return rc; } } else { rc = EIO; break; } } rc = rtems_rfs_group_bitmap_free (fs, false, block_to_free); if (rc > 0) return rc; map->size.count--; map->size.offset = 0; map->last_data_block = block_to_free; map->dirty = true; blocks--; } if (map->size.count == 0) { map->last_map_block = 0; map->last_data_block = 0; } /* * Keep the position inside the map. */ if (rtems_rfs_block_pos_past_end (&map->bpos, &map->size)) rtems_rfs_block_size_get_bpos (&map->size, &map->bpos); return 0; }
int rtems_rfs_block_map_grow (rtems_rfs_file_system* fs, rtems_rfs_block_map* map, size_t blocks, rtems_rfs_block_no* new_block) { int b; if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_GROW)) printf ("rtems-rfs: block-map-grow: entry: blocks=%zd count=%" PRIu32 "\n", blocks, map->size.count); if ((map->size.count + blocks) >= rtems_rfs_fs_max_block_map_blocks (fs)) return EFBIG; /* * Allocate a block at a time. The buffer handles hold the blocks so adding * this way does not thrash the cache with lots of requests. */ for (b = 0; b < blocks; b++) { rtems_rfs_bitmap_bit block; int rc; /* * Allocate the block. If an indirect block is needed and cannot be * allocated free this block. */ rc = rtems_rfs_group_bitmap_alloc (fs, map->last_data_block, false, &block); if (rc > 0) return rc; if (map->size.count < RTEMS_RFS_INODE_BLOCKS) map->blocks[map->size.count] = block; else { /* * Single indirect access is occuring. It could still be doubly indirect. */ rtems_rfs_block_no direct; rtems_rfs_block_no singly; direct = map->size.count % fs->blocks_per_block; singly = map->size.count / fs->blocks_per_block; if (map->size.count < fs->block_map_singly_blocks) { /* * Singly indirect tables are being used. Allocate a new block for a * mapping table if direct is 0 or we are moving up (upping). If upping * move the direct blocks into the table and if not this is the first * entry of a new block. */ if ((direct == 0) || ((singly == 0) && (direct == RTEMS_RFS_INODE_BLOCKS))) { /* * Upping is when we move from direct to singly indirect. */ bool upping; upping = map->size.count == RTEMS_RFS_INODE_BLOCKS; rc = rtems_rfs_block_map_indirect_alloc (fs, map, &map->singly_buffer, &map->blocks[singly], upping); } else { rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer, map->blocks[singly], true); } if (rc > 0) { rtems_rfs_group_bitmap_free (fs, false, block); return rc; } } else { /* * Doubly indirect tables are being used. */ rtems_rfs_block_no doubly; rtems_rfs_block_no singly_block; doubly = singly / fs->blocks_per_block; singly %= fs->blocks_per_block; /* * Allocate a new block for a singly indirect table if direct is 0 as * it is the first entry of a new block. We may also need to allocate a * doubly indirect block as well. Both always occur when direct is 0 * and the doubly indirect block when singly is 0. */ if (direct == 0) { rc = rtems_rfs_block_map_indirect_alloc (fs, map, &map->singly_buffer, &singly_block, false); if (rc > 0) { rtems_rfs_group_bitmap_free (fs, false, block); return rc; } /* * Allocate a new block for a doubly indirect table if singly is 0 as * it is the first entry of a new singly indirect block. */ if ((singly == 0) || ((doubly == 0) && (singly == RTEMS_RFS_INODE_BLOCKS))) { bool upping; upping = map->size.count == fs->block_map_singly_blocks; rc = rtems_rfs_block_map_indirect_alloc (fs, map, &map->doubly_buffer, &map->blocks[doubly], upping); if (rc > 0) { rtems_rfs_group_bitmap_free (fs, false, singly_block); rtems_rfs_group_bitmap_free (fs, false, block); return rc; } } else { rc = rtems_rfs_buffer_handle_request (fs, &map->doubly_buffer, map->blocks[doubly], true); if (rc > 0) { rtems_rfs_group_bitmap_free (fs, false, singly_block); rtems_rfs_group_bitmap_free (fs, false, block); return rc; } } rtems_rfs_block_set_number (&map->doubly_buffer, singly, singly_block); } else { rc = rtems_rfs_buffer_handle_request (fs, &map->doubly_buffer, map->blocks[doubly], true); if (rc > 0) { rtems_rfs_group_bitmap_free (fs, false, block); return rc; } singly_block = rtems_rfs_block_get_number (&map->doubly_buffer, singly); rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer, singly_block, true); if (rc > 0) { rtems_rfs_group_bitmap_free (fs, false, block); return rc; } } } rtems_rfs_block_set_number (&map->singly_buffer, direct, block); } map->size.count++; map->size.offset = 0; if (b == 0) *new_block = block; map->last_data_block = block; map->dirty = true; } return 0; }
static int rtems_rfs_write_root_dir (const char* name) { rtems_rfs_file_system* fs; rtems_rfs_inode_handle inode; rtems_rfs_ino ino; int rc; /* * External API so returns -1. */ rc = rtems_rfs_fs_open (name, NULL, RTEMS_RFS_FS_FORCE_OPEN, &fs); if (rc < 0) { printf ("rtems-rfs: format: file system open failed: %d: %s\n", errno, strerror (errno)); return -1; } rc = rtems_rfs_inode_alloc (fs, RTEMS_RFS_ROOT_INO, &ino); if (rc > 0) { printf ("rtems-rfs: format: inode allocation failed: %d: %s\n", rc, strerror (rc)); rtems_rfs_fs_close (fs); return rc; } if (ino != RTEMS_RFS_ROOT_INO) { printf ("rtems-rfs: format: allocated inode not root ino: %" PRId32 "\n", ino); rtems_rfs_fs_close (fs); return rc; } rc = rtems_rfs_inode_open (fs, ino, &inode, true); if (rc > 0) { printf ("rtems-rfs: format: inode open failed: %d: %s\n", rc, strerror (rc)); rtems_rfs_group_bitmap_free (fs, true, ino); rtems_rfs_fs_close (fs); return rc; } rc = rtems_rfs_inode_initialise (&inode, 0, (RTEMS_RFS_S_IFDIR | RTEMS_RFS_S_IRWXU | RTEMS_RFS_S_IXGRP | RTEMS_RFS_S_IXOTH), 0, 0); if (rc > 0) printf ("rtems-rfs: format: inode initialise failed: %d: %s\n", rc, strerror (rc)); rc = rtems_rfs_dir_add_entry (fs, &inode, ".", 1, ino); if (rc > 0) printf ("rtems-rfs: format: directory add failed: %d: %s\n", rc, strerror (rc)); rc = rtems_rfs_inode_close (fs, &inode); if (rc > 0) printf ("rtems-rfs: format: inode close failed: %d: %s\n", rc, strerror (rc)); rc = rtems_rfs_fs_close (fs); if (rc < 0) printf ("rtems-rfs: format: file system close failed: %d: %s\n", errno, strerror (errno)); return rc; }