📄 mkfs.c
字号:
/* * Copyright (C) International Business Machines Corp., 2000-2005 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <config.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#if HAVE_SYS_SYSMACROS_H#include <sys/sysmacros.h>#endif#include <jfs_types.h>#include <errno.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <time.h>#include <ctype.h>#include "jfs_endian.h"#include "jfs_filsys.h"#include "jfs_dinode.h"#include "jfs_superblock.h"#include "initmap.h"#include "inodes.h"#include "inode.h"#include "inodemap.h"#include "super.h"#include "logform.h"#include "jfs_dmap.h"#include "message.h"#include "debug.h"#include "jfs_version.h"#include "utilsubs.h"unsigned type_jfs;char *program_name;extern int LogOpenMode;FILE *open_by_label(uuid_t, int, int, char *, int *);static int AGsize;/* Define a parameter array for messages */#define MAXPARMS 9#define MAXSTR 128char *msg_parms[MAXPARMS];char msgstr[MAXSTR];#define L2MEGABYTE 20#define MEGABYTE (1 << L2MEGABYTE)#define MEGABYTE32 (MEGABYTE << 5)#define MAX_LOG_PERCENTAGE 10 /* Log can be at most 10% of disk */#define create_journal_only 1#define use_existing_journal 2/* * The following macro defines the initial number of aggregate inodes which * are initialized when a new aggregate is created. This does not include * any fileset inodes as those are initialized separately. */#define INIT_NUM_AGGR_INODES (BADBLOCK_I + 1)static struct dinode aggr_inodes[INIT_NUM_AGGR_INODES];void mkfs_usage(void){ printf("\nUsage: %s [-cOqV] [-j log_device] [-J options] " "[-L vol_label] [-s log_size] device [ blocks ]\n", program_name); printf("\nEmergency help:\n" " -c Check device for bad blocks before building file system.\n" " -O Provide case-insensitive support for OS/2 compatability.\n" " -q Quiet execution.\n" " -V Print version information only.\n" " -j log_device Set external journal device.\n" " -J options Set external journal options.\n" " -L vol_label Set volume label for the file system.\n" " -s log_size Set log size (in megabytes).\n\n" "NOTE: -j and -J cannot be used at the same time.\n"); return;}/*-------------------------------------------------------------------- * NAME: create_fileset * * FUNCTION: Do all work to create a fileset in an aggregate * * PARAMETERS: * dev_ptr - open port of device to write to * aggr_block_size - block size for aggregate * start_block - Number of blocks used by aggregate metadata, indicates * first block available for writing fileset metadata. * All fileset writes will be offsets from this. * inostamp - Inode stamp value to be used. * * RETURNS: * success: 0 * failure: any other value */static int create_fileset(FILE *dev_ptr, int aggr_block_size, int64_t start_block, unsigned inostamp){ int rc; int64_t inode_table_loc, inode_map_loc; int inode_table_size, inode_map_size; /* * Find space for the inode allocation map page * * Also find the fileset inode map location on disk (inode_map_loc). * We need to know this in order to initialize the fileset inodes * with the proper iag value. * * Since we only have one fileset per aggregate in the first release, * we always know where the inode map will start. Therefore, currently * we use a hard-coded value. When we add multiple filesets per * aggregate this will need to be modified to find the space for the * inode map by looking in the block allocation map for available space. */ inode_map_size = SIZE_OF_MAP_PAGE << 1;#ifdef ONE_FILESET_PER_AGGR /* * The first extent of the fileset inode allocation map follows the * first extent of the first extent of the fileset inodes at the * beginning of the fileset */ inode_map_loc = start_block + INODE_EXTENT_SIZE / aggr_block_size;#else inode_map_loc = get_space(inode_map_size);#endif /* * Allocate Aggregate Inodes for Fileset */ rc = init_fileset_inodes(aggr_block_size, dev_ptr, inode_map_loc, inode_map_size, start_block, inostamp); if (rc != 0) return (rc); /* * Create Fileset Inode Table - first extent */ rc = init_fileset_inode_table(aggr_block_size, dev_ptr, &inode_table_loc, &inode_table_size, start_block, inode_map_loc, inostamp); if (rc != 0) return (rc); /* * Create Fileset Inode Allocation Map - first extent */ rc = init_inode_map(aggr_block_size, dev_ptr, inode_table_loc, inode_table_size, inode_map_loc, inode_map_size, (ACL_I + 1), AGsize, FILESYSTEM_I); return rc;}/*-------------------------------------------------------------------- * NAME: create_aggregate * * FUNCTION: Do all work to create an aggregate * * PARAMETERS: * dev_ptr - open port of device to write to * volume_label - label for volume * number_of_blocks - number of blocks for aggregate * aggr_block_size - block size for aggregate * phys_block_size - physical block size of device * type_jfs - JFS type to create * verify_blocks - indicates if we should verify every block * log_uuid - uuid of log device * * NOTES: The superblocks are the last things written to disk. In the event * of a system crash during mkfs this device will not appear to have * a real JFS filesystem. This should prevent us from attempting to * mount a partially initialized filesystem. * * RETURNS: * success: 0 * failure: any other value */static int create_aggregate(FILE *dev_ptr, char *volume_label, int64_t number_of_blocks, int aggr_block_size, int phys_block_size, unsigned type_jfs, char *logdev, int64_t logloc, int logsize, bool verify_blocks, uuid_t log_uuid){ struct superblock aggr_superblock; void *buffer; int rc; int64_t index; int64_t first_block, last_block; int64_t reserved_size; int64_t aggr_inode_map_loc; int aggr_inode_map_sz; xad_t inode_map_dscr; int64_t secondary_ait_address, secondary_aimap_address; int64_t secondary_ait_end; int64_t fsck_wspace_address, num_bits; int fsck_wspace_length, fsck_svclog_length, npages; unsigned inostamp; struct dinode fileset_inode; /* * Find where fsck working space will live on disk and mark those * blocks. The fsck working space is always at the very end of the * aggregate so once we know how big it is we can back up from the * end to determine where it needs to start. * * Need enough 4k pages to cover: * - 1 bit per block in aggregate rounded up to BPERDMAP boundary * - 1 extra 4k page to handle control page, intermediate level pages * - 50 extra 4k pages for the chkdsk service log */ num_bits = ((number_of_blocks + BPERDMAP - 1) >> L2BPERDMAP) << L2BPERDMAP; npages = ((num_bits + (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 + 50; fsck_wspace_length = (npages << L2PSIZE) / aggr_block_size; fsck_wspace_address = number_of_blocks - fsck_wspace_length; fsck_svclog_length = (50 << L2PSIZE) / aggr_block_size; /* * Now we want the fsck working space to be ignored as actually being * part of the filesystem */ number_of_blocks -= fsck_wspace_length; /* * Initialize disk block map, so blocks can be marked as they are used * Blocks used for fsck working space will be marked here since we * don't want those blocks to be accounted for when maxag is set */ inostamp = (unsigned) time(NULL); rc = calc_map_size(number_of_blocks, aggr_inodes, aggr_block_size, &AGsize, inostamp); if (rc != 0) return rc; /* * Initialize and clear reserved disk blocks */ reserved_size = AGGR_RSVD_BYTES; buffer = calloc(reserved_size, sizeof (char)); if (buffer == NULL) { message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG); return (ENOMEM); } rc = ujfs_rw_diskblocks(dev_ptr, 0, reserved_size, buffer, PUT); if (rc != 0) return rc; for (index = 0; ((index < reserved_size / aggr_block_size) && (rc == 0)); index++) { rc = markit(index, ALLOC); } if (rc != 0) return rc; /* * In case mkfs does not complete, but we have an old superblock * already on this device, we will zero the superblock disk blocks at * the beginning and then write the real superblock to disk last. * (This keeps the device from appearing to have a complete filesystem * when initialization is not complete.) */ rc = ujfs_rw_diskblocks(dev_ptr, SUPER1_OFF, SIZE_OF_SUPER, buffer, PUT); if (rc != 0) { free(buffer); return rc; } rc = ujfs_rw_diskblocks(dev_ptr, SUPER2_OFF, SIZE_OF_SUPER, buffer, PUT); if (rc != 0) { free(buffer); return rc; } free(buffer); /* Mark blocks allocated for superblocks. */ first_block = SUPER1_OFF / aggr_block_size; last_block = first_block + (SIZE_OF_SUPER / aggr_block_size); for (index = first_block; ((index < last_block) && (rc == 0)); index++) { rc = markit(index, ALLOC); } if (rc != 0) return rc; first_block = SUPER2_OFF / aggr_block_size; last_block = first_block + (SIZE_OF_SUPER / aggr_block_size); for (index = first_block; ((index < last_block) && (rc == 0)); index++) { rc = markit(index, ALLOC); } if (rc != 0) return rc; /* * Initialize First Extent of Aggregate Inode Allocation Map */ aggr_inode_map_loc = AIMAP_OFF; aggr_inode_map_sz = SIZE_OF_MAP_PAGE << 1; rc = init_inode_map(aggr_block_size, dev_ptr, AITBL_OFF, INODE_EXTENT_SIZE, aggr_inode_map_loc / aggr_block_size, aggr_inode_map_sz, INIT_NUM_AGGR_INODES + 1, AGsize, AGGREGATE_I); if (rc != 0) return rc; /* * Initialize first inode extent of Aggregate Inode Table */ rc = init_aggr_inode_table(aggr_block_size, dev_ptr, aggr_inodes, INIT_NUM_AGGR_INODES, AITBL_OFF, aggr_inode_map_loc / aggr_block_size, aggr_inode_map_sz, inostamp); if (rc != 0) return rc; /* * Now initialize the secondary aggregate inode table and map * * We can use the same aggr_inodes we already initialized except for * the aggregate self inode. This will be updated by the call to * init_aggr_inode_table() to point to the secondary table instead of * the primary table. * * First we need to determine the location; it will follow the block * map. Since the block map might be sparse we need to use the number * of blocks instead of the length of the extents. This works since * the extents are in the inode for mkfs */ inode_map_dscr = ((xtpage_t *) & (aggr_inodes[BMAP_I].di_DASD))->xad[XTENTRYSTART]; secondary_aimap_address = addressXAD(&inode_map_dscr) + aggr_inodes[BMAP_I].di_nblocks; secondary_ait_address = (secondary_aimap_address * aggr_block_size) + (SIZE_OF_MAP_PAGE << 1); secondary_ait_end = (secondary_ait_address + INODE_EXTENT_SIZE) / aggr_block_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -