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

📄 balloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  linux/fs/ext3/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 <linux/time.h>#include <linux/capability.h>#include <linux/fs.h>#include <linux/jbd.h>#include <linux/ext3_fs.h>#include <linux/ext3_jbd.h>#include <linux/quotaops.h>#include <linux/buffer_head.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 ext3_fill_super). */#define in_range(b, first, len)	((b) >= (first) && (b) <= (first) + (len) - 1)/** * ext3_get_group_desc() -- load group descriptor from disk * @sb:			super block * @block_group:	given block group * @bh:			pointer to the buffer head to store the block *			group descriptor */struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,					     unsigned int block_group,					     struct buffer_head ** bh){	unsigned long group_desc;	unsigned long offset;	struct ext3_group_desc * desc;	struct ext3_sb_info *sbi = EXT3_SB(sb);	if (block_group >= sbi->s_groups_count) {		ext3_error (sb, "ext3_get_group_desc",			    "block_group >= groups_count - "			    "block_group = %d, groups_count = %lu",			    block_group, sbi->s_groups_count);		return NULL;	}	smp_rmb();	group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb);	offset = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1);	if (!sbi->s_group_desc[group_desc]) {		ext3_error (sb, "ext3_get_group_desc",			    "Group descriptor not loaded - "			    "block_group = %d, group_desc = %lu, desc = %lu",			     block_group, group_desc, offset);		return NULL;	}	desc = (struct ext3_group_desc *) sbi->s_group_desc[group_desc]->b_data;	if (bh)		*bh = sbi->s_group_desc[group_desc];	return desc + offset;}/** * read_block_bitmap() * @sb:			super block * @block_group:	given block group * * 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 ext3_group_desc * desc;	struct buffer_head * bh = NULL;	desc = ext3_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)		ext3_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;}/* * 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 ext3_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 ext3_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 ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,			unsigned int group, struct super_block * sb){	ext3_fsblk_t group_first_block, group_last_block;	group_first_block = ext3_group_first_block_no(sb, group);	group_last_block = group_first_block + (EXT3_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 ext3_reserve_window_node *search_reserve_window(struct rb_root *root, ext3_fsblk_t goal){	struct rb_node *n = root->rb_node;	struct ext3_reserve_window_node *rsv;	if (!n)		return NULL;	do {		rsv = rb_entry(n, struct ext3_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 ext3_reserve_window_node, rsv_node);	}	return rsv;}/** * ext3_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 hold. */void ext3_rsv_window_add(struct super_block *sb,		    struct ext3_reserve_window_node *rsv){	struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root;	struct rb_node *node = &rsv->rsv_node;	ext3_fsblk_t start = rsv->rsv_start;	struct rb_node ** p = &root->rb_node;	struct rb_node * parent = NULL;	struct ext3_reserve_window_node *this;	while (*p)	{		parent = *p;		this = rb_entry(parent, struct ext3_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);}/** * ext3_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 hold. */static void rsv_window_remove(struct super_block *sb,			      struct ext3_reserve_window_node *rsv){	rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;	rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;	rsv->rsv_alloc_hit = 0;	rb_erase(&rsv->rsv_node, &EXT3_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 EXT3_RESERVE_WINDOW_NOT_ALLOCATED. */static inline int rsv_is_empty(struct ext3_reserve_window *rsv){	/* a valid reservation end block could not be 0 */	return rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED;}/** * ext3_init_block_alloc_info() * @inode:		file inode structure * * Allocate and initialize the	reservation window structure, and * link the window to the ext3 inode structure at last * * The reservation window structure is only dynamically allocated * and linked to ext3 inode the first time the open file * needs a new block. So, before every ext3_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 ext3_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 call this function. */void ext3_init_block_alloc_info(struct inode *inode){	struct ext3_inode_info *ei = EXT3_I(inode);	struct ext3_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 ext3_reserve_window_node *rsv = &block_i->rsv_window_node;		rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;		rsv->rsv_end = EXT3_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 = EXT3_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;}/** * ext3_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: *	ext3_release_file(): last writer close the file *	ext3_clear_inode(): last iput(), when nobody link to this file. *	ext3_truncate(): when the block indirect map is about to change. * */void ext3_discard_reservation(struct inode *inode){	struct ext3_inode_info *ei = EXT3_I(inode);	struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info;	struct ext3_reserve_window_node *rsv;	spinlock_t *rsv_lock = &EXT3_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);	}}/** * ext3_free_blocks_sb() -- Free given blocks and update quota * @handle:			handle to this transaction * @sb:				super block * @block:			start physcial block to free * @count:			number of blocks to free * @pdquot_freed_blocks:	pointer to quota */void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,			 ext3_fsblk_t block, unsigned long count,			 unsigned long *pdquot_freed_blocks){	struct buffer_head *bitmap_bh = NULL;	struct buffer_head *gd_bh;	unsigned long block_group;	ext3_grpblk_t bit;	unsigned long i;	unsigned long overflow;	struct ext3_group_desc * desc;	struct ext3_super_block * es;	struct ext3_sb_info *sbi;	int err = 0, ret;	ext3_grpblk_t group_freed;	*pdquot_freed_blocks = 0;	sbi = EXT3_SB(sb);	es = sbi->s_es;	if (block < le32_to_cpu(es->s_first_data_block) ||	    block + count < block ||	    block + count > le32_to_cpu(es->s_blocks_count)) {		ext3_error (sb, "ext3_free_blocks",			    "Freeing blocks not in datazone - "			    "block = "E3FSBLK", count = %lu", block, count);		goto error_return;	}	ext3_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)) /		      EXT3_BLOCKS_PER_GROUP(sb);	bit = (block - le32_to_cpu(es->s_first_data_block)) %		      EXT3_BLOCKS_PER_GROUP(sb);	/*	 * Check to see if we are freeing blocks across a group	 * boundary.	 */	if (bit + count > EXT3_BLOCKS_PER_GROUP(sb)) {

⌨️ 快捷键说明

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