📄 balloc.c
字号:
if (next < maxblocks && ext3_test_allocatable(next, bh)) return next; /* The bitmap search --- search forward alternately * through the actual bitmap and the last-committed copy * until we find a bit free in both. */ while (here < maxblocks) { next = ext3_find_next_zero_bit ((unsigned long *) bh->b_data, maxblocks, here); if (next >= maxblocks) return -1; if (ext3_test_allocatable(next, bh)) return next; J_ASSERT_BH(bh, bh2jh(bh)->b_committed_data); here = ext3_find_next_zero_bit ((unsigned long *) bh2jh(bh)->b_committed_data, maxblocks, next); } return -1;}/* * ext3_new_block uses a goal block to assist allocation. If the goal is * free, or there is a free block within 32 blocks of the goal, that block * is allocated. Otherwise a forward search is made for a free block; within * each block group the search first looks for an entire free byte in the block * bitmap, and then for any free bit if that fails. * This function also updates quota and i_blocks field. */int ext3_new_block (handle_t *handle, struct inode * inode, unsigned long goal, u32 * prealloc_count, u32 * prealloc_block, int * errp){ struct buffer_head * bh, *bhtmp; struct buffer_head * bh2;#if 0 char * p, * r;#endif int i, j, k, tmp, alloctmp; int bitmap_nr; int fatal = 0, err; int performed_allocation = 0; struct super_block * sb; struct ext3_group_desc * gdp; struct ext3_super_block * es;#ifdef EXT3FS_DEBUG static int goal_hits = 0, goal_attempts = 0;#endif *errp = -ENOSPC; sb = inode->i_sb; if (!sb) { printk ("ext3_new_block: nonexistent device"); return 0; } /* * Check quota for allocation of this block. */ if (DQUOT_ALLOC_BLOCK(inode, 1)) { *errp = -EDQUOT; return 0; } lock_super (sb); es = sb->u.ext3_sb.s_es; if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) && ((sb->u.ext3_sb.s_resuid != current->fsuid) && (sb->u.ext3_sb.s_resgid == 0 || !in_group_p (sb->u.ext3_sb.s_resgid)) && !capable(CAP_SYS_RESOURCE))) goto out; ext3_debug ("goal=%lu.\n", goal); /* * First, test whether the goal block is free. */ if (goal < le32_to_cpu(es->s_first_data_block) || goal >= le32_to_cpu(es->s_blocks_count)) goal = le32_to_cpu(es->s_first_data_block); i = (goal - le32_to_cpu(es->s_first_data_block)) / EXT3_BLOCKS_PER_GROUP(sb); gdp = ext3_get_group_desc (sb, i, &bh2); if (!gdp) goto io_error; if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { j = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT3_BLOCKS_PER_GROUP(sb));#ifdef EXT3FS_DEBUG if (j) goal_attempts++;#endif bitmap_nr = load_block_bitmap (sb, i); if (bitmap_nr < 0) goto io_error; bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr]; ext3_debug ("goal is at %d:%d.\n", i, j); if (ext3_test_allocatable(j, bh)) {#ifdef EXT3FS_DEBUG goal_hits++; ext3_debug ("goal bit allocated.\n");#endif goto got_block; } j = find_next_usable_block(j, bh, EXT3_BLOCKS_PER_GROUP(sb)); if (j >= 0) goto search_back; } ext3_debug ("Bit not found in block group %d.\n", i); /* * Now search the rest of the groups. We assume that * i and gdp correctly point to the last group visited. */ for (k = 0; k < sb->u.ext3_sb.s_groups_count; k++) { i++; if (i >= sb->u.ext3_sb.s_groups_count) i = 0; gdp = ext3_get_group_desc (sb, i, &bh2); if (!gdp) { *errp = -EIO; goto out; } if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { bitmap_nr = load_block_bitmap (sb, i); if (bitmap_nr < 0) goto io_error; bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr]; j = find_next_usable_block(-1, bh, EXT3_BLOCKS_PER_GROUP(sb)); if (j >= 0) goto search_back; } } /* No space left on the device */ goto out;search_back: /* * We have succeeded in finding a free byte in the block * bitmap. Now search backwards up to 7 bits to find the * start of this group of free blocks. */ for ( k = 0; k < 7 && j > 0 && ext3_test_allocatable(j - 1, bh); k++, j--) ; got_block: ext3_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count); /* Make sure we use undo access for the bitmap, because it is critical that we do the frozen_data COW on bitmap buffers in all cases even if the buffer is in BJ_Forget state in the committing transaction. */ BUFFER_TRACE(bh, "get undo access for marking new block"); fatal = ext3_journal_get_undo_access(handle, bh); if (fatal) goto out; BUFFER_TRACE(bh2, "get_write_access"); fatal = ext3_journal_get_write_access(handle, bh2); if (fatal) goto out; BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get_write_access"); fatal = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh); if (fatal) goto out; tmp = j + i * EXT3_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block); if (tmp == le32_to_cpu(gdp->bg_block_bitmap) || tmp == le32_to_cpu(gdp->bg_inode_bitmap) || in_range (tmp, le32_to_cpu(gdp->bg_inode_table), sb->u.ext3_sb.s_itb_per_group)) ext3_error (sb, "ext3_new_block", "Allocating block in system zone - " "block = %u", tmp); /* The superblock lock should guard against anybody else beating * us to this point! */ J_ASSERT_BH(bh, !ext3_test_bit(j, bh->b_data)); BUFFER_TRACE(bh, "setting bitmap bit"); ext3_set_bit(j, bh->b_data); performed_allocation = 1;#ifdef CONFIG_JBD_DEBUG { struct buffer_head *debug_bh; /* Record bitmap buffer state in the newly allocated block */ debug_bh = sb_get_hash_table(sb, tmp); if (debug_bh) { BUFFER_TRACE(debug_bh, "state when allocated"); BUFFER_TRACE2(debug_bh, bh, "bitmap state"); brelse(debug_bh); } }#endif if (buffer_jbd(bh) && bh2jh(bh)->b_committed_data) J_ASSERT_BH(bh, !ext3_test_bit(j, bh2jh(bh)->b_committed_data)); bhtmp = bh; alloctmp = j; ext3_debug ("found bit %d\n", j); /* * Do block preallocation now if required. */#ifdef EXT3_PREALLOCATE /* * akpm: this is not enabled for ext3. Need to use * ext3_test_allocatable() */ /* Writer: ->i_prealloc* */ if (prealloc_count && !*prealloc_count) { int prealloc_goal; unsigned long next_block = tmp + 1; prealloc_goal = es->s_prealloc_blocks ? es->s_prealloc_blocks : EXT3_DEFAULT_PREALLOC_BLOCKS; *prealloc_block = next_block; /* Writer: end */ for (k = 1; k < prealloc_goal && (j + k) < EXT3_BLOCKS_PER_GROUP(sb); k++, next_block++) { if (DQUOT_PREALLOC_BLOCK(inode, 1)) break; /* Writer: ->i_prealloc* */ if (*prealloc_block + *prealloc_count != next_block || ext3_set_bit (j + k, bh->b_data)) { /* Writer: end */ DQUOT_FREE_BLOCK(inode, 1); break; } (*prealloc_count)++; /* Writer: end */ } /* * As soon as we go for per-group spinlocks we'll need these * done inside the loop above. */ gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - (k - 1)); es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - (k - 1)); ext3_debug ("Preallocated a further %lu bits.\n", (k - 1)); }#endif j = tmp; BUFFER_TRACE(bh, "journal_dirty_metadata for bitmap block"); err = ext3_journal_dirty_metadata(handle, bh); if (!fatal) fatal = err; if (j >= le32_to_cpu(es->s_blocks_count)) { ext3_error (sb, "ext3_new_block", "block(%d) >= blocks count(%d) - " "block_group = %d, es == %p ",j, le32_to_cpu(es->s_blocks_count), i, es); goto out; } /* * It is up to the caller to add the new buffer to a journal * list of some description. We don't know in advance whether * the caller wants to use it as metadata or data. */ ext3_debug ("allocating block %d. " "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1); BUFFER_TRACE(bh2, "journal_dirty_metadata for group descriptor"); err = ext3_journal_dirty_metadata(handle, bh2); if (!fatal) fatal = err; BUFFER_TRACE(bh, "journal_dirty_metadata for superblock"); err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh); if (!fatal) fatal = err; sb->s_dirt = 1; if (fatal) goto out; unlock_super (sb); *errp = 0; return j; io_error: *errp = -EIO;out: if (fatal) { *errp = fatal; ext3_std_error(sb, fatal); } unlock_super (sb); /* * Undo the block allocation */ if (!performed_allocation) DQUOT_FREE_BLOCK(inode, 1); return 0; }unsigned long ext3_count_free_blocks (struct super_block * sb){#ifdef EXT3FS_DEBUG struct ext3_super_block * es; unsigned long desc_count, bitmap_count, x; int bitmap_nr; struct ext3_group_desc * gdp; int i; lock_super (sb); es = sb->u.ext3_sb.s_es; desc_count = 0; bitmap_count = 0; gdp = NULL; for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) { gdp = ext3_get_group_desc (sb, i, NULL); if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_blocks_count); bitmap_nr = load_block_bitmap (sb, i); if (bitmap_nr < 0) continue; x = ext3_count_free (sb->u.ext3_sb.s_block_bitmap[bitmap_nr], sb->s_blocksize); printk ("group %d: stored = %d, counted = %lu\n", i, le16_to_cpu(gdp->bg_free_blocks_count), x); bitmap_count += x; } printk("ext3_count_free_blocks: stored = %lu, computed = %lu, %lu\n", le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count); unlock_super (sb); return bitmap_count;#else return le32_to_cpu(sb->u.ext3_sb.s_es->s_free_blocks_count);#endif}static inline int block_in_use (unsigned long block, struct super_block * sb, unsigned char * map){ return ext3_test_bit ((block - le32_to_cpu(sb->u.ext3_sb.s_es->s_first_data_block)) % EXT3_BLOCKS_PER_GROUP(sb), map);}static inline int test_root(int a, int b){ if (a == 0) return 1; while (1) { if (a == 1) return 1; if (a % b) return 0; a = a / b; }}int ext3_group_sparse(int group){ return (test_root(group, 3) || test_root(group, 5) || test_root(group, 7));}/** * ext3_bg_has_super - number of blocks used by the superblock in group * @sb: superblock for filesystem * @group: group number to check * * Return the number of blocks used by the superblock (primary or backup) * in this group. Currently this will be only 0 or 1. */int ext3_bg_has_super(struct super_block *sb, int group){ if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&& !ext3_group_sparse(group)) return 0; return 1;}/** * ext3_bg_num_gdb - number of blocks used by the group table in group * @sb: superblock for filesystem * @group: group number to check * * Return the number of blocks used by the group descriptor table * (primary or backup) in this group. In the future there may be a * different number of descriptor blocks in each group. */unsigned long ext3_bg_num_gdb(struct super_block *sb, int group){ if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&& !ext3_group_sparse(group)) return 0; return EXT3_SB(sb)->s_gdb_count;}#ifdef CONFIG_EXT3_CHECK/* Called at mount-time, super-block is locked */void ext3_check_blocks_bitmap (struct super_block * sb){ struct buffer_head * bh; struct ext3_super_block * es; unsigned long desc_count, bitmap_count, x, j; unsigned long desc_blocks; int bitmap_nr; struct ext3_group_desc * gdp; int i; es = sb->u.ext3_sb.s_es; desc_count = 0; bitmap_count = 0; gdp = NULL; for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) { gdp = ext3_get_group_desc (sb, i, NULL); if (!gdp) continue; desc_count += le16_to_cpu(gdp->bg_free_blocks_count); bitmap_nr = load_block_bitmap (sb, i); if (bitmap_nr < 0) continue; bh = EXT3_SB(sb)->s_block_bitmap[bitmap_nr]; if (ext3_bg_has_super(sb, i) && !ext3_test_bit(0, bh->b_data)) ext3_error(sb, __FUNCTION__, "Superblock in group %d is marked free", i); desc_blocks = ext3_bg_num_gdb(sb, i); for (j = 0; j < desc_blocks; j++) if (!ext3_test_bit(j + 1, bh->b_data)) ext3_error(sb, __FUNCTION__, "Descriptor block #%ld in group " "%d is marked free", j, i); if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data)) ext3_error (sb, "ext3_check_blocks_bitmap", "Block bitmap for group %d is marked free", i); if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap), sb, bh->b_data)) ext3_error (sb, "ext3_check_blocks_bitmap", "Inode bitmap for group %d is marked free", i); for (j = 0; j < sb->u.ext3_sb.s_itb_per_group; j++) if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, sb, bh->b_data)) ext3_error (sb, "ext3_check_blocks_bitmap", "Block #%d of the inode table in " "group %d is marked free", j, i); x = ext3_count_free (bh, sb->s_blocksize); if (le16_to_cpu(gdp->bg_free_blocks_count) != x) ext3_error (sb, "ext3_check_blocks_bitmap", "Wrong free blocks count for group %d, " "stored = %d, counted = %lu", i, le16_to_cpu(gdp->bg_free_blocks_count), x); bitmap_count += x; } if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count) ext3_error (sb, "ext3_check_blocks_bitmap", "Wrong free blocks count in super block, " "stored = %lu, counted = %lu", (unsigned long)le32_to_cpu(es->s_free_blocks_count), bitmap_count);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -