📄 diskmap.c
字号:
/* * Copyright (c) International Business Machines Corp., 2000-2002 * * 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 "jfs_types.h"#include "jfs_dmap.h"#include "diskmap.h"/* * budtab[] * * used to determine the maximum free string in a character * of a wmap word. the actual bit values of the character * serve as the index into this array and the value of the * array at that index is the max free string. * */static int8_t budtab[256] = { 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1};/* * NAME: ujfs_maxbuddy * * FUNCTION: Determines the maximum string of free blocks within a word of the * wmap or pmap consistent with binary buddy. * * PRE CONDITIONS: * * POST CONDITIONS: * * PARAMETERS: * cp - Pointer to wmap or pmap word. * * NOTES: * * DATA STRUCTURES: * * RETURNS: Maximum string of free blocks within word. */int8_t ujfs_maxbuddy(unsigned char *cp){ /* * Check if the wmap or pmap word is all free. If so, the free buddy size is * BUDMIN. */ if (*((uint32_t *) cp) == 0) { return (BUDMIN); } /* * Check if the wmap or pmap word is half free. If so, the free buddy size * is BUDMIN-1. */ if (*((uint16_t *) cp) == 0 || *((uint16_t *) cp + 1) == 0) { return (BUDMIN - 1); } /* * Not all free or half free. Determine the free buddy size through table * lookup using quarters of the wmap or pmap word. */ return (MAX(MAX(budtab[*cp], budtab[*(cp + 1)]), MAX(budtab[*(cp + 2)], budtab[*(cp + 3)])));}/* * NAME: ujfs_adjtree * * FUNCTION: Calculate the tree of a dmap or dmapctl. * * PRE CONDITIONS: * * POST CONDITIONS: * * PARAMETERS: * cp - Pointer to the top of the tree * l2leaves- Number of leaf nodes as a power of 2 * l2min - Number of disk blocks actually covered by a leaf of the tree; * specified as a power of 2 * * NOTES: This routine first works against the leaves of the tree to calculate * the maximum free string for leaf buddys. Once this is accomplished the * values of the leaf nodes are bubbled up the tree. * * DATA STRUCTURES: * * RETURNS: */int8_t ujfs_adjtree(int8_t * treep, int32_t l2leaves, int32_t l2min){ int32_t nleaves, leaf_index, l2max, nextb, bsize, index; int32_t l2free, leaf, num_this_level, nextp; int8_t *cp0, *cp1, *cp = treep; /* * Determine the number of leaves of the tree and the * index of the first leaf. * Note: I don't know why the leaf_index calculation works, but it does. */ nleaves = (1 << l2leaves); leaf_index = (nleaves - 1) / 3; /* * Determine the maximum free string possible for the leaves. */ l2max = l2min + l2leaves; /* * Try to combine buddies starting with a buddy size of 1 (i.e. two leaves). * At a buddy size of 1 two buddy leaves can be combined if both buddies * have a maximum free of l2min; the combination will result in the * left-most buddy leaf having a maximum free of l2min+1. After processing * all buddies for a certain size, process buddies at the next higher buddy * size (i.e. current size * 2) and the next maximum free * (current free + 1). This continues until the maximum possible buddy * combination yields maximum free. */ for (l2free = l2min, bsize = 1; l2free < l2max; l2free++, bsize = nextb) { nextb = bsize << 1; for (cp0 = cp + leaf_index, index = 0; index < nleaves; index += nextb, cp0 += nextb) { if (*cp0 == l2free && *(cp0 + bsize) == l2free) { *cp0 = l2free + 1; *(cp0 + bsize) = -1; } } } /* * With the leaves reflecting maximum free values bubble this information up * the tree. Starting at the leaf node level, the four nodes described by * the higher level parent node are compared for a maximum free and this * maximum becomes the value of the parent node. All lower level nodes are * processed in this fashion then we move up to the next level (parent * becomes a lower level node) and continue the process for that level. */ for (leaf = leaf_index, num_this_level = nleaves >> 2; num_this_level > 0; num_this_level >>= 2, leaf = nextp) { nextp = (leaf - 1) >> 2; /* * Process all lower level nodes at this level setting the value of the * parent node as the maximum of the four lower level nodes. */ for (cp0 = cp + leaf, cp1 = cp + nextp, index = 0; index < num_this_level; index++, cp0 += 4, cp1++) { *cp1 = TREEMAX(cp0); } } return (*cp);}/* * NAME: ujfs_complete_dmap * * FUNCTION: Fill in rest of dmap fields from wmap/pmap already initialized. * * PARAMETERS: * dmap_page - dmap to complete * blkno - starting block number for this dmap * treemax - will be filled in with max free for this dmap * * RETURNS: NONE */void ujfs_complete_dmap(struct dmap *dmap_page, int64_t blkno, int8_t *treemax){ struct dmaptree *tp; int8_t *cp; int32_t index; dmap_page->start = blkno; tp = &dmap_page->tree; tp->height = 4; tp->leafidx = LEAFIND; tp->nleafs = LPERDMAP; tp->l2nleafs = L2LPERDMAP; tp->budmin = BUDMIN; /* * Pick up the pointer to the first leaf of the dmap tree. */ cp = tp->stree + tp->leafidx; /* * Set the initial state for the leaves of the dmap tree. They will reflect * the current allocation state of the wmap words. */ for (index = 0; index < LPERDMAP; index++) { *(cp + index) = ujfs_maxbuddy((unsigned char *) &dmap_page->wmap[index]); } /* * With the leaves of the dmap initialized adjust (initialize) the dmap's * tree. */ *treemax = ujfs_adjtree(tp->stree, L2LPERDMAP, BUDMIN);}/* * NAME: ujfs_idmap_page * * FUNCTION: Initialize one dmap page * * POST CONDITIONS: Blocks which don't actually exist in the aggregate will be * marked as allocated in the dmap page. The total number of blocks will * only account for the actually existing blocks. * * PARAMETERS: * map_page - pointer to page of map * nblocks - number of blocks this page * * RETURNS: NONE */void ujfs_idmap_page(struct dmap *map_page, uint32_t nblocks){ uint32_t index, nwords, bit; map_page->nblocks = map_page->nfree = nblocks; /* * Partial dmap page? * If there are not enough blocks to cover an entire dmap page the ones * which represent blocks which don't exist will be marked as allocated. * * nwords will indicate the first word beyond the end of existing blocks * bit will indicate if this block does not fall on a 32-bit boundary */ nwords = nblocks / DBWORD; bit = nblocks % DBWORD; if (bit) { /* * Need to mark a partial word allocated */ map_page->wmap[nwords] = map_page->pmap[nwords] = ONES >> bit; nwords++; } /* * Set the rest of the words in the page to ONES. */ for (index = nwords; index < LPERDMAP; index++) { map_page->pmap[index] = map_page->wmap[index] = ONES; }}/* * NAME: ujfs_getagl2size * * FUNCTION: Determine log2(allocation group size) based on size of aggregate * * PARAMETERS: * size - Number of blocks in aggregate * aggr_block_size - Aggregate block size * * RETURNS: log2(allocation group size) in aggregate blocks */int32_t ujfs_getagl2size(int64_t size, int32_t aggr_block_size){ int64_t sz; int64_t m; int32_t l2sz; if (size < BPERDMAP * MAXAG) { return (L2BPERDMAP); } m = ((uint64_t) 1 << (64 - 1)); for (l2sz = 64; l2sz >= 0; l2sz--, m >>= 1) { if (m & size) { break; } } sz = (int64_t) 1 << l2sz; if (sz < size) { l2sz += 1; } return (l2sz - L2MAXAG);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -