⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 balloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/fs/ext2/balloc.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * *  Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993 *  Big-endian to little-endian byte-swapping/bitmaps by *        David S. Miller (davem@caip.rutgers.edu), 1995 */#include "ext2.h"#include <linux/quotaops.h>#include <linux/sched.h>#include <linux/buffer_head.h>#include <linux/capability.h>/* * balloc.c contains the blocks allocation and deallocation routines *//* * The free blocks are managed by bitmaps.  A file system contains several * blocks groups.  Each group contains 1 bitmap block for blocks, 1 bitmap * block for inodes, N blocks for the inode table and data blocks. * * The file system contains group descriptors which are located after the * super block.  Each descriptor contains the number of the bitmap block and * the free blocks count in the block.  The descriptors are loaded in memory * when a file system is mounted (see ext2_fill_super). */#define in_range(b, first, len)	((b) >= (first) && (b) <= (first) + (len) - 1)struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,					     unsigned int block_group,					     struct buffer_head ** bh){	unsigned long group_desc;	unsigned long offset;	struct ext2_group_desc * desc;	struct ext2_sb_info *sbi = EXT2_SB(sb);	if (block_group >= sbi->s_groups_count) {		ext2_error (sb, "ext2_get_group_desc",			    "block_group >= groups_count - "			    "block_group = %d, groups_count = %lu",			    block_group, sbi->s_groups_count);		return NULL;	}	group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(sb);	offset = block_group & (EXT2_DESC_PER_BLOCK(sb) - 1);	if (!sbi->s_group_desc[group_desc]) {		ext2_error (sb, "ext2_get_group_desc",			    "Group descriptor not loaded - "			    "block_group = %d, group_desc = %lu, desc = %lu",			     block_group, group_desc, offset);		return NULL;	}	desc = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;	if (bh)		*bh = sbi->s_group_desc[group_desc];	return desc + offset;}/* * Read the bitmap for a given block_group, reading into the specified  * slot in the superblock's bitmap cache. * * Return buffer_head on success or NULL in case of failure. */static struct buffer_head *read_block_bitmap(struct super_block *sb, unsigned int block_group){	struct ext2_group_desc * desc;	struct buffer_head * bh = NULL;		desc = ext2_get_group_desc (sb, block_group, NULL);	if (!desc)		goto error_out;	bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));	if (!bh)		ext2_error (sb, "read_block_bitmap",			    "Cannot read block bitmap - "			    "block_group = %d, block_bitmap = %u",			    block_group, le32_to_cpu(desc->bg_block_bitmap));error_out:	return bh;}static void release_blocks(struct super_block *sb, int count){	if (count) {		struct ext2_sb_info *sbi = EXT2_SB(sb);		percpu_counter_add(&sbi->s_freeblocks_counter, count);		sb->s_dirt = 1;	}}static void group_adjust_blocks(struct super_block *sb, int group_no,	struct ext2_group_desc *desc, struct buffer_head *bh, int count){	if (count) {		struct ext2_sb_info *sbi = EXT2_SB(sb);		unsigned free_blocks;		spin_lock(sb_bgl_lock(sbi, group_no));		free_blocks = le16_to_cpu(desc->bg_free_blocks_count);		desc->bg_free_blocks_count = cpu_to_le16(free_blocks + count);		spin_unlock(sb_bgl_lock(sbi, group_no));		sb->s_dirt = 1;		mark_buffer_dirty(bh);	}}/* * The reservation window structure operations * -------------------------------------------- * Operations include: * dump, find, add, remove, is_empty, find_next_reservable_window, etc. * * We use a red-black tree to represent per-filesystem reservation * windows. * *//** * __rsv_window_dump() -- Dump the filesystem block allocation reservation map * @rb_root:		root of per-filesystem reservation rb tree * @verbose:		verbose mode * @fn:			function which wishes to dump the reservation map * * If verbose is turned on, it will print the whole block reservation * windows(start, end). Otherwise, it will only print out the "bad" windows, * those windows that overlap with their immediate neighbors. */#if 1static void __rsv_window_dump(struct rb_root *root, int verbose,			      const char *fn){	struct rb_node *n;	struct ext2_reserve_window_node *rsv, *prev;	int bad;restart:	n = rb_first(root);	bad = 0;	prev = NULL;	printk("Block Allocation Reservation Windows Map (%s):\n", fn);	while (n) {		rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node);		if (verbose)			printk("reservation window 0x%p "				"start: %lu, end: %lu\n",				rsv, rsv->rsv_start, rsv->rsv_end);		if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {			printk("Bad reservation %p (start >= end)\n",			       rsv);			bad = 1;		}		if (prev && prev->rsv_end >= rsv->rsv_start) {			printk("Bad reservation %p (prev->end >= start)\n",			       rsv);			bad = 1;		}		if (bad) {			if (!verbose) {				printk("Restarting reservation walk in verbose mode\n");				verbose = 1;				goto restart;			}		}		n = rb_next(n);		prev = rsv;	}	printk("Window map complete.\n");	if (bad)		BUG();}#define rsv_window_dump(root, verbose) \	__rsv_window_dump((root), (verbose), __FUNCTION__)#else#define rsv_window_dump(root, verbose) do {} while (0)#endif/** * goal_in_my_reservation() * @rsv:		inode's reservation window * @grp_goal:		given goal block relative to the allocation block group * @group:		the current allocation block group * @sb:			filesystem super block * * Test if the given goal block (group relative) is within the file's * own block reservation window range. * * If the reservation window is outside the goal allocation group, return 0; * grp_goal (given goal block) could be -1, which means no specific * goal block. In this case, always return 1. * If the goal block is within the reservation window, return 1; * otherwise, return 0; */static intgoal_in_my_reservation(struct ext2_reserve_window *rsv, ext2_grpblk_t grp_goal,			unsigned int group, struct super_block * sb){	ext2_fsblk_t group_first_block, group_last_block;	group_first_block = ext2_group_first_block_no(sb, group);	group_last_block = group_first_block + EXT2_BLOCKS_PER_GROUP(sb) - 1;	if ((rsv->_rsv_start > group_last_block) ||	    (rsv->_rsv_end < group_first_block))		return 0;	if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)		|| (grp_goal + group_first_block > rsv->_rsv_end)))		return 0;	return 1;}/** * search_reserve_window() * @rb_root:		root of reservation tree * @goal:		target allocation block * * Find the reserved window which includes the goal, or the previous one * if the goal is not in any window. * Returns NULL if there are no windows or if all windows start after the goal. */static struct ext2_reserve_window_node *search_reserve_window(struct rb_root *root, ext2_fsblk_t goal){	struct rb_node *n = root->rb_node;	struct ext2_reserve_window_node *rsv;	if (!n)		return NULL;	do {		rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node);		if (goal < rsv->rsv_start)			n = n->rb_left;		else if (goal > rsv->rsv_end)			n = n->rb_right;		else			return rsv;	} while (n);	/*	 * We've fallen off the end of the tree: the goal wasn't inside	 * any particular node.  OK, the previous node must be to one	 * side of the interval containing the goal.  If it's the RHS,	 * we need to back up one.	 */	if (rsv->rsv_start > goal) {		n = rb_prev(&rsv->rsv_node);		rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node);	}	return rsv;}/* * ext2_rsv_window_add() -- Insert a window to the block reservation rb tree. * @sb:			super block * @rsv:		reservation window to add * * Must be called with rsv_lock held. */void ext2_rsv_window_add(struct super_block *sb,		    struct ext2_reserve_window_node *rsv){	struct rb_root *root = &EXT2_SB(sb)->s_rsv_window_root;	struct rb_node *node = &rsv->rsv_node;	ext2_fsblk_t start = rsv->rsv_start;	struct rb_node ** p = &root->rb_node;	struct rb_node * parent = NULL;	struct ext2_reserve_window_node *this;	while (*p)	{		parent = *p;		this = rb_entry(parent, struct ext2_reserve_window_node, rsv_node);		if (start < this->rsv_start)			p = &(*p)->rb_left;		else if (start > this->rsv_end)			p = &(*p)->rb_right;		else {			rsv_window_dump(root, 1);			BUG();		}	}	rb_link_node(node, parent, p);	rb_insert_color(node, root);}/** * rsv_window_remove() -- unlink a window from the reservation rb tree * @sb:			super block * @rsv:		reservation window to remove * * Mark the block reservation window as not allocated, and unlink it * from the filesystem reservation window rb tree. Must be called with * rsv_lock held. */static void rsv_window_remove(struct super_block *sb,			      struct ext2_reserve_window_node *rsv){	rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;	rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;	rsv->rsv_alloc_hit = 0;	rb_erase(&rsv->rsv_node, &EXT2_SB(sb)->s_rsv_window_root);}/* * rsv_is_empty() -- Check if the reservation window is allocated. * @rsv:		given reservation window to check * * returns 1 if the end block is EXT2_RESERVE_WINDOW_NOT_ALLOCATED. */static inline int rsv_is_empty(struct ext2_reserve_window *rsv){	/* a valid reservation end block could not be 0 */	return (rsv->_rsv_end == EXT2_RESERVE_WINDOW_NOT_ALLOCATED);}/** * ext2_init_block_alloc_info() * @inode:		file inode structure * * Allocate and initialize the  reservation window structure, and * link the window to the ext2 inode structure at last * * The reservation window structure is only dynamically allocated * and linked to ext2 inode the first time the open file * needs a new block. So, before every ext2_new_block(s) call, for * regular files, we should check whether the reservation window * structure exists or not. In the latter case, this function is called. * Fail to do so will result in block reservation being turned off for that * open file. * * This function is called from ext2_get_blocks_handle(), also called * when setting the reservation window size through ioctl before the file * is open for write (needs block allocation). * * Needs truncate_mutex protection prior to calling this function. */void ext2_init_block_alloc_info(struct inode *inode){	struct ext2_inode_info *ei = EXT2_I(inode);	struct ext2_block_alloc_info *block_i = ei->i_block_alloc_info;	struct super_block *sb = inode->i_sb;	block_i = kmalloc(sizeof(*block_i), GFP_NOFS);	if (block_i) {		struct ext2_reserve_window_node *rsv = &block_i->rsv_window_node;		rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;		rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED;	 	/*		 * if filesystem is mounted with NORESERVATION, the goal		 * reservation window size is set to zero to indicate		 * block reservation is off		 */		if (!test_opt(sb, RESERVATION))			rsv->rsv_goal_size = 0;		else			rsv->rsv_goal_size = EXT2_DEFAULT_RESERVE_BLOCKS;		rsv->rsv_alloc_hit = 0;		block_i->last_alloc_logical_block = 0;		block_i->last_alloc_physical_block = 0;	}	ei->i_block_alloc_info = block_i;}/** * ext2_discard_reservation() * @inode:		inode * * Discard(free) block reservation window on last file close, or truncate * or at last iput(). * * It is being called in three cases: * 	ext2_release_file(): last writer closes the file * 	ext2_clear_inode(): last iput(), when nobody links to this file. * 	ext2_truncate(): when the block indirect map is about to change. */void ext2_discard_reservation(struct inode *inode){	struct ext2_inode_info *ei = EXT2_I(inode);	struct ext2_block_alloc_info *block_i = ei->i_block_alloc_info;	struct ext2_reserve_window_node *rsv;	spinlock_t *rsv_lock = &EXT2_SB(inode->i_sb)->s_rsv_window_lock;	if (!block_i)		return;	rsv = &block_i->rsv_window_node;	if (!rsv_is_empty(&rsv->rsv_window)) {		spin_lock(rsv_lock);		if (!rsv_is_empty(&rsv->rsv_window))			rsv_window_remove(inode->i_sb, rsv);		spin_unlock(rsv_lock);	}}/** * ext2_free_blocks_sb() -- Free given blocks and update quota and i_blocks * @inode:		inode * @block:		start physcial block to free * @count:		number of blocks to free */void ext2_free_blocks (struct inode * inode, unsigned long block,		       unsigned long count){	struct buffer_head *bitmap_bh = NULL;	struct buffer_head * bh2;	unsigned long block_group;	unsigned long bit;	unsigned long i;	unsigned long overflow;	struct super_block * sb = inode->i_sb;	struct ext2_sb_info * sbi = EXT2_SB(sb);	struct ext2_group_desc * desc;	struct ext2_super_block * es = sbi->s_es;	unsigned freed = 0, group_freed;	if (block < le32_to_cpu(es->s_first_data_block) ||	    block + count < block ||	    block + count > le32_to_cpu(es->s_blocks_count)) {		ext2_error (sb, "ext2_free_blocks",			    "Freeing blocks not in datazone - "			    "block = %lu, count = %lu", block, count);		goto error_return;	}	ext2_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1);do_more:	overflow = 0;	block_group = (block - le32_to_cpu(es->s_first_data_block)) /		      EXT2_BLOCKS_PER_GROUP(sb);	bit = (block - le32_to_cpu(es->s_first_data_block)) %		      EXT2_BLOCKS_PER_GROUP(sb);	/*	 * Check to see if we are freeing blocks across a group	 * boundary.	 */	if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) {		overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);		count -= overflow;	}	brelse(bitmap_bh);	bitmap_bh = read_block_bitmap(sb, block_group);	if (!bitmap_bh)		goto error_return;	desc = ext2_get_group_desc (sb, block_group, &bh2);	if (!desc)		goto error_return;	if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) ||	    in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) ||	    in_range (block, le32_to_cpu(desc->bg_inode_table),		      sbi->s_itb_per_group) ||	    in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table),		      sbi->s_itb_per_group))		ext2_error (sb, "ext2_free_blocks",			    "Freeing blocks in system zones - "			    "Block = %lu, count = %lu",			    block, count);	for (i = 0, group_freed = 0; i < count; i++) {		if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group),						bit + i, bitmap_bh->b_data)) {			ext2_error(sb, __FUNCTION__,				"bit already cleared for block %lu", block + i);		} else {			group_freed++;		}	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -