From a9fa9b765df38cc5319ae734b5148fd47ebbfd8d Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 18 Feb 2010 00:24:25 +0000 Subject: 2010-02-18 Chris Johns * libfs/src/rfs/rtems-rfs-bitmaps.c, libfs/src/rfs/rtems-rfs-bitmaps.h, libfs/src/rfs/rtems-rfs-bitmaps-ut.c, libfs/src/rfs/rtems-rfs-block.c, libfs/src/rfs/rtems-rfs-block.h, libfs/src/rfs/rtems-rfs-block-pos.h, libfs/src/rfs/rtems-rfs-buffer-bdbuf.c, libfs/src/rfs/rtems-rfs-buffer.c, libfs/src/rfs/rtems-rfs-buffer-devio.c, libfs/src/rfs/rtems-rfs-buffer.h, libfs/src/rfs/rtems-rfs-data.h, libfs/src/rfs/rtems-rfs-dir.c, libfs/src/rfs/rtems-rfs-dir.h, libfs/src/rfs/rtems-rfs-dir-hash.c, libfs/src/rfs/rtems-rfs-dir-hash.h, libfs/src/rfs/rtems-rfs-file.c, libfs/src/rfs/rtems-rfs-file.h, libfs/src/rfs/rtems-rfs-file-system.c, libfs/src/rfs/rtems-rfs-file-system-fwd.h, libfs/src/rfs/rtems-rfs-file-system.h, libfs/src/rfs/rtems-rfs-format.c, libfs/src/rfs/rtems-rfs-format.h, libfs/src/rfs/rtems-rfs-group.c, libfs/src/rfs/rtems-rfs-group.h, libfs/src/rfs/rtems-rfs.h, libfs/src/rfs/rtems-rfs-inode.c, libfs/src/rfs/rtems-rfs-inode.h, libfs/src/rfs/rtems-rfs-link.c, libfs/src/rfs/rtems-rfs-link.h, libfs/src/rfs/rtems-rfs-mutex.c, libfs/src/rfs/rtems-rfs-mutex.h, libfs/src/rfs/rtems-rfs-rtems.c, libfs/src/rfs/rtems-rfs-rtems-dev.c, libfs/src/rfs/rtems-rfs-rtems-dir.c, libfs/src/rfs/rtems-rfs-rtems-file.c, libfs/src/rfs/rtems-rfs-rtems.h, libfs/src/rfs/rtems-rfs-rtems-utils.c, libfs/src/rfs/rtems-rfs-shell.c, libfs/src/rfs/rtems-rfs-shell.h, libfs/src/rfs/rtems-rfs-trace.c, libfs/src/rfs/rtems-rfs-trace.h: New. * Makefile.am, preinstall.am, libfs/Makefile.am, wrapup/Makefile.am: Updated with the RFS support. * libfs/README: Updated after 10 years. * libblock/src/flashdisk.c, libblock/src/nvdisk.c, libblock/src/ramdisk-driver.c: Updated to the new error reporting in libblock. * libmisc/shell/main_ls.c, libmisc/shell/print-ls.c: Fix printing the size in long mode. * libnetworking/nfs/bootp_subr.c, libnetworking/rtems/rtems_bootp.c, libnetworking/rtems/rtems_bsdnet_internal.h: Return the BOOTP/DHCP to the forever behaviour of 4.9 with the ability to call BOOTP and control the process if required. --- cpukit/libfs/src/rfs/rtems-rfs-format.c | 627 ++++++++++++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 cpukit/libfs/src/rfs/rtems-rfs-format.c (limited to 'cpukit/libfs/src/rfs/rtems-rfs-format.c') diff --git a/cpukit/libfs/src/rfs/rtems-rfs-format.c b/cpukit/libfs/src/rfs/rtems-rfs-format.c new file mode 100644 index 0000000000..e15905b2f0 --- /dev/null +++ b/cpukit/libfs/src/rfs/rtems-rfs-format.c @@ -0,0 +1,627 @@ +/* + * COPYRIGHT (c) 2010 Chris Johns + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ +/** + * @file + * + * @ingroup rtems-rfs + * + * RTEMS File Systems Format + * + * Format the file system ready for use. + */ + +#include +#include + +#include +#include +#include +#include +#include + +/** + * Return the number of gigabytes. + */ +#define GIGS(_g) ((_g) * 1024 * 1024) + +/** + * Return the number of bits that fit in the block size. + */ +static int +rtems_rfs_bits_per_block (rtems_rfs_file_system* fs) +{ + return rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs)); +} + +/** + * Return a rounded up integer quotient given a dividend and divisor. That is: + * "quotient = dividend / divisor" + */ +int +rtems_rfs_rup_quotient (uint32_t dividend, uint32_t divisor) +{ + if (dividend == 0) + return 1; + return ((dividend - 1) / divisor) + 1; +} + +/** + * Return the number of inodes as a percentage of the total number that can fit + * in a blocl. + */ +static int +rtems_rfs_inodes_from_percent (rtems_rfs_file_system* fs, + int percentage) +{ + int blocks; + blocks = (rtems_rfs_bits_per_block (fs) * percentage) / 100; + return blocks * (rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode)); +} + +/** + * Return the inode overhead given a number of inodes. + */ +static int +rtems_rfs_inode_overhead (rtems_rfs_file_system* fs) +{ + int blocks; + blocks = + (fs->group_inodes * sizeof (rtems_rfs_inode)) / rtems_rfs_fs_block_size (fs); + return ((blocks + 1) * 100 * 10) / rtems_rfs_bits_per_block (fs); +} + +static bool +rtems_rfs_check_config (rtems_rfs_file_system* fs, + const rtems_rfs_format_config* config) +{ + fs->block_size = config->block_size; + if (!fs->block_size) + { + uint64_t total_size = rtems_rfs_fs_media_size (fs); + + if (total_size > GIGS (2)) + { + uint32_t gigs = (total_size + GIGS (1)) / GIGS (1); + int b; + for (b = 31; b > 0; b--) + if ((gigs & (1 << b)) != 0) + break; + fs->block_size = 1 << b; + } + + if (fs->block_size < 1024) + fs->block_size = 1024; + + if (fs->block_size > (4 * 1024)) + fs->block_size = (4 * 1024); + } + + if ((fs->block_size % rtems_rfs_fs_media_block_size (fs)) != 0) + { + printf ("block size (%ld) is not a multiple of media block size (%ld)\n", + fs->block_size, rtems_rfs_fs_media_block_size (fs)); + return false; + } + + fs->group_blocks = config->group_blocks; + if (!fs->group_blocks) + { + /* + * The number of blocks per group is defined by the number of bits in a + * block. + */ + fs->group_blocks = rtems_rfs_bitmap_numof_bits (fs->block_size); + } + + if (fs->group_blocks > rtems_rfs_bitmap_numof_bits (fs->block_size)) + { + printf ("group block count is higher than bits in block\n"); + return false; + } + + fs->group_inodes = config->group_inodes; + if (!fs->group_inodes) + { + int inode_overhead = RTEMS_RFS_INODE_OVERHEAD_PERCENTAGE; + + /* + * The number of inodes per group is set as a percentage. + */ + if (config->inode_overhead) + inode_overhead = config->inode_overhead; + + fs->group_inodes = rtems_rfs_inodes_from_percent (fs, inode_overhead); + } + + /* + * Round up to fill a block because the minimum allocation unit is a block. + */ + fs->inodes_per_block = rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode); + fs->group_inodes = + rtems_rfs_rup_quotient (fs->group_inodes, + fs->inodes_per_block) * fs->inodes_per_block; + + if (fs->group_inodes > rtems_rfs_bitmap_numof_bits (fs->block_size)) + fs->group_inodes = rtems_rfs_bitmap_numof_bits (fs->block_size); + + fs->max_name_length = config->max_name_length; + if (!fs->max_name_length) + { + fs->max_name_length = 512; + } + + return true; +} + +static bool +rtems_rfs_write_group (rtems_rfs_file_system* fs, + int group, + bool initialise_inodes, + bool verbose) +{ + rtems_rfs_buffer_handle handle; + rtems_rfs_bitmap_control bitmap; + rtems_rfs_buffer_block group_base; + size_t group_size; + int blocks; + int b; + int rc; + + group_base = rtems_rfs_fs_block (fs, group, 0); + + if (group_base > rtems_rfs_fs_blocks (fs)) + { + printf ("rtems-rfs: write-group: group %d base beyond disk limit\n", + group); + return false; + } + + group_size = fs->group_blocks; + + /* + * Be nice to strange sizes of disks. These are embedded systems after all + * and nice numbers do not always work out. Let the last block pick up the + * remainder of the blocks. + */ + if ((group_base + group_size) > rtems_rfs_fs_blocks (fs)) + group_size = rtems_rfs_fs_blocks (fs) - group_base; + + if (verbose) + printf ("\rrtems-rfs: format: group %3d: base = %ld, size = %ld", + group, group_base, group_size); + + /* + * Open a handle and request an empty buffer. + */ + rc = rtems_rfs_buffer_handle_open (fs, &handle); + if (rc > 0) + { + printf ("\nrtems-rfs: write-group: handle open failed: %d: %s\n", + rc, strerror (rc)); + return false; + } + + if (verbose) + printf (", blocks"); + + /* + * Open the block bitmap using the new buffer. + */ + rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size, + group_base + RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("\nrtems-rfs: write-group: group %3d: open block bitmap failed: %d: %s\n", + group, rc, strerror (rc)); + return false; + } + + /* + * Force the whole buffer to a known state. The bit map may not occupy the + * whole block. + */ + memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs)); + + /* + * Clear the bitmap. + */ + rc = rtems_rfs_bitmap_map_clear_all (&bitmap); + if (rc > 0) + { + rtems_rfs_bitmap_close (&bitmap); + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("\nrtems-rfs: write-group: group %3d: block bitmap clear all failed: %d: %s\n", + group, rc, strerror (rc)); + return false; + } + + /* + * Forced allocation of the block bitmap. + */ + rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK); + + /* + * Forced allocation of the inode bitmap. + */ + rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK); + + /* + * Determine the number of inodes blocks in the group. + */ + blocks = rtems_rfs_rup_quotient (fs->group_inodes, fs->inodes_per_block); + + /* + * Forced allocation of the inode blocks which follow the block bitmap. + */ + for (b = 0; b < blocks; b++) + rtems_rfs_bitmap_map_set (&bitmap, b + RTEMS_RFS_GROUP_INODE_BLOCK); + + /* + * Close the block bitmap. + */ + rc = rtems_rfs_bitmap_close (&bitmap); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("\nrtems-rfs: write-group: group %3d: close block bitmap failed: %d: %s\n", + group, rc, strerror (rc)); + return false; + } + + rtems_rfs_buffer_mark_dirty (&handle); + + if (verbose) + printf (", inodes"); + + /* + * Open the inode bitmap using the old buffer. Should release any changes. + */ + rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size, + group_base + RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("\nrtems-rfs: write-group: group %3d: open inode bitmap failed: %d: %s\n", + group, rc, strerror (rc)); + return false; + } + + /* + * Force the whole buffer to a known state. The bit map may not occupy the + * whole block. + */ + memset (rtems_rfs_buffer_data (&handle), 0x00, rtems_rfs_fs_block_size (fs)); + + /* + * Clear the inode bitmap. + */ + rc = rtems_rfs_bitmap_map_clear_all (&bitmap); + if (rc > 0) + { + rtems_rfs_bitmap_close (&bitmap); + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("\nrtems-rfs: write-group: group %3d: inode bitmap" \ + " clear all failed: %d: %s\n", group, rc, strerror (rc)); + return false; + } + + /* + * Close the inode bitmap. + */ + rc = rtems_rfs_bitmap_close (&bitmap); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("\nrtems-rfs: write-group: group %3d: close inode" \ + " bitmap failed: %d: %s\n", group, rc, strerror (rc)); + return false; + } + + rtems_rfs_buffer_mark_dirty (&handle); + + /* + * Initialise the inode tables if rerquired to do so. + */ + if (initialise_inodes) + { + for (b = 0; b < blocks; b++) + { + rc = rtems_rfs_buffer_handle_request (fs, &handle, + group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK, + false); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("\nrtems-rfs: write-group: group %3d: block %ld request failed: %d: %s\n", + group, group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK, + rc, strerror (rc)); + return false; + } + + /* + * Force the whole buffer to a known state. The bit map may not occupy the + * whole block. + */ + memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs)); + + rtems_rfs_buffer_mark_dirty (&handle); + } + } + + rc = rtems_rfs_buffer_handle_close (fs, &handle); + if (rc > 0) + { + printf ("\nrtems-rfs: write-group: buffer handle close failed: %d: %s\n", + rc, strerror (rc)); + return false; + } + + return true; +} + +static bool +rtems_rfs_write_superblock (rtems_rfs_file_system* fs) +{ + rtems_rfs_buffer_handle handle; + uint8_t* sb; + int rc; + + rc = rtems_rfs_buffer_handle_open (fs, &handle); + if (rc > 0) + { + printf ("rtems-rfs: write-superblock: handle open failed: %d: %s\n", + rc, strerror (rc)); + return false; + } + + rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, false); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("rtems-rfs: write-superblock: request failed: %d: %s\n", + rc, strerror (rc)); + return false; + } + + sb = rtems_rfs_buffer_data (&handle); + +#define write_sb(_o, _d) rtems_rfs_write_u32(sb + (_o), _d) + + memset (sb, 0xff, rtems_rfs_fs_block_size (fs)); + + write_sb (RTEMS_RFS_SB_OFFSET_MAGIC, RTEMS_RFS_SB_MAGIC); + write_sb (RTEMS_RFS_SB_OFFSET_BLOCKS, rtems_rfs_fs_blocks (fs)); + write_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE, rtems_rfs_fs_block_size (fs)); + write_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS, fs->bad_blocks); + write_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH, fs->max_name_length); + write_sb (RTEMS_RFS_SB_OFFSET_GROUPS, fs->group_count); + write_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS, fs->group_blocks); + write_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES, fs->group_inodes); + + rtems_rfs_buffer_mark_dirty (&handle); + + rc = rtems_rfs_buffer_handle_release (fs, &handle); + if (rc > 0) + { + rtems_rfs_buffer_handle_close (fs, &handle); + printf ("rtems-rfs: write-superblock: buffer release failed: %d: %s\n", + rc, strerror (rc)); + return false; + } + + rc = rtems_rfs_buffer_handle_close (fs, &handle); + if (rc > 0) + { + printf ("rtems-rfs: write-superblock: buffer handle close failed: %d: %s\n", + rc, strerror (rc)); + return false; + } + + return true; +} + +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: %ld\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; +} + +int +rtems_rfs_format (const char* name, const rtems_rfs_format_config* config) +{ + rtems_rfs_file_system fs; + int group; + int rc; + + if (config->verbose) + printf ("rtems-rfs: format: %s\n", name); + + memset (&fs, 0, sizeof (rtems_rfs_file_system)); + + rtems_chain_initialize_empty (&fs.release); + rtems_chain_initialize_empty (&fs.release_modified); + rtems_chain_initialize_empty (&fs.file_shares); + + fs.max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS; + + fs.release_count = 0; + fs.release_modified_count = 0; + + fs.flags = RTEMS_RFS_FS_NO_LOCAL_CACHE; + + /* + * Open the buffer interface. + */ + rc = rtems_rfs_buffer_open (name, &fs); + if (rc > 0) + { + printf ("rtems-rfs: format: buffer open failed: %d: %s\n", + rc, strerror (rc)); + return -1; + } + + /* + * Check the media. + */ + if (rtems_rfs_fs_media_block_size (&fs) == 0) + { + printf ("rtems-rfs: media block is invalid: %lu\n", + rtems_rfs_fs_media_block_size (&fs)); + return -1; + } + + /* + * Check the configuration data. + */ + if (!rtems_rfs_check_config (&fs, config)) + return -1; + + fs.blocks = rtems_rfs_fs_media_size (&fs) / fs.block_size; + + /* + * The bits per block sets the upper limit for the number of blocks in a + * group. The disk will be divided into groups which are the number of bits + * per block. + */ + fs.group_count = + ((rtems_rfs_fs_blocks (&fs) - 1) / rtems_rfs_bits_per_block (&fs)) + 1; + + if (config->verbose) + { + printf ("rtems-rfs: format: media size = %llu\n", + rtems_rfs_fs_media_size (&fs)); + printf ("rtems-rfs: format: media blocks = %ld\n", + rtems_rfs_fs_media_blocks (&fs)); + printf ("rtems-rfs: format: media block size = %lu\n", + rtems_rfs_fs_media_block_size (&fs)); + printf ("rtems-rfs: format: size = %llu\n", + rtems_rfs_fs_size (&fs)); + printf ("rtems-rfs: format: blocks = %lu\n", + rtems_rfs_fs_blocks (&fs)); + printf ("rtems-rfs: format: block size = %lu\n", + rtems_rfs_fs_block_size (&fs)); + printf ("rtems-rfs: format: bits per block = %u\n", + rtems_rfs_bits_per_block (&fs)); + printf ("rtems-rfs: format: inode size = %lu\n", sizeof (rtems_rfs_inode)); + printf ("rtems-rfs: format: inodes = %lu (%d.%d%%)\n", + fs.group_inodes * fs.group_count, + rtems_rfs_inode_overhead (&fs) / 10, + rtems_rfs_inode_overhead (&fs) % 10); + printf ("rtems-rfs: format: groups = %u\n", fs.group_count); + printf ("rtems-rfs: format: group blocks = %lu\n", fs.group_blocks); + printf ("rtems-rfs: format: group inodes = %lu\n", fs.group_inodes); + } + + rc = rtems_rfs_buffer_setblksize (&fs, rtems_rfs_fs_block_size (&fs)); + if (rc > 0) + { + printf ("rtems-rfs: format: setting block size failed: %d: %s\n", + rc, strerror (rc)); + return -1; + } + + if (!rtems_rfs_write_superblock (&fs)) + { + printf ("rtems-rfs: format: superblock write failed\n"); + return -1; + } + + for (group = 0; group < fs.group_count; group++) + if (!rtems_rfs_write_group (&fs, group, + config->initialise_inodes, config->verbose)) + return -1; + + if (config->verbose) + printf ("\n"); + + rc = rtems_rfs_buffer_close (&fs); + if (rc > 0) + { + printf ("rtems-rfs: format: buffer close failed: %d: %s\n", + rc, strerror (rc)); + return -1; + } + + rc = rtems_rfs_write_root_dir (name); + if (rc > 0) + { + printf ("rtems-rfs: format: writing root dir failed: %d: %s\n", + rc, strerror (rc)); + return -1; + } + + return 0; +} -- cgit v1.2.3