📄 initmap.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 */#define _GNU_SOURCE /* FOR O_DIRECT */#include <config.h>#include "jfs_types.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include "jfs_endian.h"#include "jfs_filsys.h"#include "jfs_dinode.h"#include "devices.h"#include "inodes.h"#include "jfs_dmap.h"#include "diskmap.h"#include "inode.h"#include "initmap.h"#include "message.h"#include "utilsubs.h"extern unsigned type_jfs;#define UZWORD (0x80000000u)#define DBBYTE 8 /* number of bits per byte */#define L2DBBYTE 3 /* log2 of number of bits per byte */#define CHAR_ONES (0xffu)static struct dmap **block_map_array;static unsigned sz_block_map_array;static unsigned cur_dmap_index;static struct dbmap *control_page;static unsigned last_allocated;static struct dmap *empty_page;struct xtree_buf { struct xtree_buf *down; /* next rightmost child */ struct xtree_buf *up; /* parent */ xtpage_t *page;};static struct xtree_buf *badblock_pages;static int xtAppend(FILE *, struct dinode *, int64_t, int64_t, int, struct xtree_buf *, int);/*-------------------------------------------------------------------- * NAME: initdmap() * * FUNCTION: Initialize a dmap for the specified block range * (blkno thru blkno+nblocks-1). * * PARAMETERS: * dev_ptr - device to write map page to * blkno - Starting disk block number to be covered by this dmap. * nblocks - Number of blocks covered by this dmap. * treemax - Return value set as maximum free string found in this dmap * start - Logical block address of where this dmap should live on disk. * * NOTES: The wmap and pmap words along the leaves of the dmap tree are * initialized, with the leaves initialized to the maximum free string of * the wmap word they describe. With this complete ujfs_adjtree() is * called to combine all appropriate buddies and update the higher level of * the tree to reflect the result of the buddy combination. The maximum * free string of the dmap (i.e. the root value of the tree) is returned * in treemax. * * RETURNS: NONE */static int initdmap(FILE *dev_ptr, int64_t blkno, int64_t nblocks, int8_t * treemax, int64_t start){ int rc = 0; /* * Determine if the dmap already exists */ if (block_map_array[cur_dmap_index] == NULL) { if (nblocks == BPERDMAP) { /* * alloc/init a template empty full page buffer */ if (empty_page == NULL) { empty_page = malloc(sizeof (struct dmap)); if (empty_page == NULL) { message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG); return (ENOMEM); } memset(empty_page, 0, sizeof (struct dmap)); ujfs_idmap_page(empty_page, nblocks); ujfs_complete_dmap(empty_page, blkno, treemax); } else { /* * customize/reuse the template empty page */ empty_page->start = blkno; *treemax = empty_page->tree.stree[0]; } block_map_array[cur_dmap_index] = empty_page; } else { /* * alloc/init a special dmap page with the correct size */ block_map_array[cur_dmap_index] = malloc(sizeof (struct dmap)); if (block_map_array[cur_dmap_index] == NULL) { message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG); return (ENOMEM); } memset(block_map_array[cur_dmap_index], 0, sizeof (struct dmap)); ujfs_idmap_page(block_map_array[cur_dmap_index], nblocks); ujfs_complete_dmap(block_map_array[cur_dmap_index], blkno, treemax); } } else { /* * Fill in rest of fields of special existing dmap page */ ujfs_complete_dmap(block_map_array[cur_dmap_index], blkno, treemax); } /* * Write the dmap page and free if special buffer */ /* swap if on big endian machine */ ujfs_swap_dmap(block_map_array[cur_dmap_index]); rc = ujfs_rw_diskblocks(dev_ptr, start, PSIZE, block_map_array[cur_dmap_index], PUT); ujfs_swap_dmap(block_map_array[cur_dmap_index]); if (rc != 0) return rc; if (block_map_array[cur_dmap_index] != empty_page) { free(block_map_array[cur_dmap_index]); } cur_dmap_index++; return (rc);}/*-------------------------------------------------------------------- * NAME: initctl() * * FUNCTION: Initialize a dmapctl for the specified block range * (blkno thru blkno+nblocks-1) and * level and initialize all dmapctls and dmaps under this dmapctl. * * PARAMETERS: * dev_ptr - device to write page to * blkno - Starting disk block number to be covered by this dmapctl. * nblocks - Number of blocks covered by this dmapctl. * level - The level of this dmapctl. * treemax - Return value set as the maximum free string found in this * dmapctl. * start - Logical block address of where this page should live on disk. * * NOTES: This routine is called recursively. On first invocation it is called * for the top level dmapctl of the tree. For each leaf of the dmapctl, * the lower level dmap (level == 0) or dmapctl (level > 0) is created for * the block range covered by the leaf and the leaf is set to the maximum * free string found in the lower level object. If the lower level object * is a dmap, initdmap() is called to handle it's initialization. * Otherwise, initctl() is called recursively to initialize the lower level * dmapctl with the level specified as the current level - 1; once all * leaves have been initialized ujfs_adjtree() is called to combine all * appropriate buddies and update the higher level of the tree to reflect * the result of the buddy combination. The maximum free string of the * dmapctl (i.e. the root value of the tree) is returned in treemax. * * RETURNS: None. */static int initctl(FILE *dev_ptr, int64_t blkno, int64_t nblocks, int level, int8_t * treemax, int64_t * start){ int index, rc = 0, l2cblks, nchild; int8_t *cp, max; struct dmapctl *dcp; int64_t nb, cblks; int64_t next_page; /* * alloc/init current level dmapctl page buffer */ dcp = malloc(sizeof (struct dmapctl)); if (dcp == NULL) { message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG); return (ENOMEM); } memset(dcp, 0, sizeof (struct dmapctl)); dcp->height = 5; dcp->leafidx = CTLLEAFIND; dcp->nleafs = LPERCTL; dcp->l2nleafs = L2LPERCTL; dcp->budmin = L2BPERDMAP + level * L2LPERCTL; /* Pick up the pointer to the first leaf of the dmapctl tree */ cp = dcp->stree + dcp->leafidx; /* * Determine how many lower level dmapctls or dmaps will be described by * this dmapctl based upon the number of blocks covered by this dmapctl. */ l2cblks = L2BPERDMAP + level * L2LPERCTL; cblks = (1 << l2cblks); nchild = nblocks >> l2cblks; nchild = (nblocks & (cblks - 1)) ? nchild + 1 : nchild; next_page = *start + PSIZE; for (index = 0; index < nchild; index++, nblocks -= nb, blkno += nb) { /* * Determine how many blocks the lower level dmapctl or dmap will cover. */ nb = MIN(cblks, nblocks); /* * If this is a level 0 dmapctl, initialize the dmap for the * block range (i.e. blkno thru blkno+nb-1). Otherwise, * initialize the lower level dmapctl for this block range. * In either case, the pointer to the leaf covering this block * range is passed down and will be set to the length of the * maximum free string of blocks found at the lower level. */ if (level == 0) { rc += initdmap(dev_ptr, blkno, nb, cp + index, next_page); next_page += PSIZE; } else { rc += initctl(dev_ptr, blkno, nb, level - 1, cp + index, &next_page); } } /* * Initialize the leaves for this dmapctl that were not covered by the * specified input block range (i.e. the leaves have no low level * dmapctl or dmap. */ for (; index < LPERCTL; index++) { *(cp + index) = NOFREE; } /* * With the leaves initialized, adjust the tree for this dmapctl. */ max = ujfs_adjtree(dcp->stree, L2LPERCTL, l2cblks); /* * Write and release the dmapctl page */ /* swap if on big endian machine */ ujfs_swap_dmapctl(dcp); rc += ujfs_rw_diskblocks(dev_ptr, *start, PSIZE, dcp, PUT); free(dcp); /* * Set the treemax return value with the maximum free described by * this dmapctl. */ *treemax = max; *start = next_page; return (rc);}/*-------------------------------------------------------------------- * NAME: initbmap() * * FUNCTION: Initialize the disk block allocation map for an aggregate. * * PARAMETERS: * dev_ptr - device to write page to * nblocks - Number of blocks within the aggregate. * * NOTES: The bmap control page is created. Next, the number dmapctl level * required to described the aggregate size (number of blocks within the * aggregate) is determined. initctl() is then called to initialize the * appropriate dmapctl levels and corresponding dmaps. * * RETURNS: */static int initbmap(FILE *dev_ptr, int64_t nblocks){ int level, rc = 0; int64_t next_page; /* * get the level for the actual top dmapctl for the aggregate and * its physical address (N.B. map file has been allocated * to cover full control level hierarchy); */ level = BMAPSZTOLEV(nblocks); next_page = BMAP_OFF + PSIZE + PSIZE * (2 - level); /* * initialize only the dmapctls and the dmaps they describe * that covers the actual aggregate size. */ rc = initctl(dev_ptr, 0, nblocks, level, &control_page->dn_maxfreebud, &next_page); if (rc != 0) return (rc); /* * Write the control page to disk. */ /* swap if on big endian machine */ ujfs_swap_dbmap(control_page); rc = ujfs_rw_diskblocks(dev_ptr, BMAP_OFF, PSIZE, control_page, PUT); ujfs_swap_dbmap(control_page); return (rc);}/*-------------------------------------------------------------------- * NAME: alloc_map() * * FUNCTION: Allocate and initialize to zero the memory for dmap pages * and the control page of block map. * * PARAMETERS: * num_dmaps - Indicates number of dmaps to allocate * * DATA STRUCTURES: Initializes file static variable block_map * * RETURNS: 0 for success */static int alloc_map(int num_dmaps){ if (num_dmaps <= 0) return EINVAL; /* alloc/init dmap page pointer array */ block_map_array = malloc(num_dmaps * sizeof (struct dmap *)); if (block_map_array == NULL) { message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG); return ENOMEM; } sz_block_map_array = num_dmaps; memset(block_map_array, 0, num_dmaps * sizeof (struct dmap *)); /* alloc/init control page */ control_page = malloc(sizeof (struct dbmap)); if (control_page == NULL) { message_user(MSG_OSO_INSUFF_MEMORY, NULL, 0, OSO_MSG); return ENOMEM; } memset(control_page, 0, sizeof (struct dbmap)); return 0;}/*-------------------------------------------------------------------- * NAME: initmap() * * FUNCTION: Initialize control page * * PARAMETERS: * nblocks - Number of blocks covered by this map * ag_size - Will be filled in with AG size in blocks * aggr_block_size - Aggregate block size * * RETURNS: NONE */static void initmap(int64_t nblocks, int *ag_size, int aggr_block_size){ int index, nb, l2nl, n; /* * Initialize base information */ control_page->dn_l2nbperpage = log2shift(PSIZE / aggr_block_size); control_page->dn_mapsize = control_page->dn_nfree = nblocks; control_page->dn_maxlevel = BMAPSZTOLEV(nblocks); /* control_page->dn_maxfreebud is computed at finalization */ /* * Initialize allocation group information. */ control_page->dn_agl2size = ujfs_getagl2size(nblocks, aggr_block_size); *ag_size = control_page->dn_agsize = (int64_t) 1 << control_page->dn_agl2size; control_page->dn_numag = nblocks / control_page->dn_agsize; control_page->dn_numag += (nblocks % control_page->dn_agsize) ? 1 : 0; for (index = 0, nb = nblocks; index < control_page->dn_numag; index++, nb -= *ag_size) { control_page->dn_agfree[index] = MIN(nb, *ag_size); } control_page->dn_aglevel = BMAPSZTOLEV(control_page->dn_agsize); l2nl = control_page->dn_agl2size - (L2BPERDMAP +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -