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

📄 inode.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 3 页
字号:
	branch[0].key = cpu_to_le32(parent);	if (parent) for (n = 1; n < num; n++) {		struct buffer_head *bh;		/* Allocate the next block */		int nr = ext2_alloc_block(inode, parent, &err);		if (!nr)			break;		branch[n].key = cpu_to_le32(nr);		/*		 * Get buffer_head for parent block, zero it out and set 		 * the pointer to new one, then send parent to disk.		 */		bh = sb_getblk(inode->i_sb, parent);		lock_buffer(bh);		memset(bh->b_data, 0, blocksize);		branch[n].bh = bh;		branch[n].p = (u32*) bh->b_data + offsets[n];		*branch[n].p = branch[n].key;		mark_buffer_uptodate(bh, 1);		unlock_buffer(bh);		mark_buffer_dirty_inode(bh, inode);		if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {			ll_rw_block (WRITE, 1, &bh);			wait_on_buffer (bh);		}		parent = nr;	}	if (n == num)		return 0;	/* Allocation failed, free what we already allocated */	for (i = 1; i < n; i++)		bforget(branch[i].bh);	for (i = 0; i < n; i++)		ext2_free_blocks(inode, le32_to_cpu(branch[i].key), 1);	return err;}/** *	ext2_splice_branch - splice the allocated branch onto inode. *	@inode: owner *	@block: (logical) number of block we are adding *	@chain: chain of indirect blocks (with a missing link - see *		ext2_alloc_branch) *	@where: location of missing link *	@num:   number of blocks we are adding * *	This function verifies that chain (up to the missing link) had not *	changed, fills the missing link and does all housekeeping needed in *	inode (->i_blocks, etc.). In case of success we end up with the full *	chain to new block and return 0. Otherwise (== chain had been changed) *	we free the new blocks (forgetting their buffer_heads, indeed) and *	return -EAGAIN. */static inline int ext2_splice_branch(struct inode *inode,				     long block,				     Indirect chain[4],				     Indirect *where,				     int num){	int i;	/* Verify that place we are splicing to is still there and vacant */	/* Writer: pointers, ->i_next_alloc* */	if (!verify_chain(chain, where-1) || *where->p)		/* Writer: end */		goto changed;	/* That's it */	*where->p = where->key;	inode->u.ext2_i.i_next_alloc_block = block;	inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);	/* Writer: end */	/* We are done with atomic stuff, now do the rest of housekeeping */	inode->i_ctime = CURRENT_TIME;	/* had we spliced it onto indirect block? */	if (where->bh) {		mark_buffer_dirty_inode(where->bh, inode);		if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {			ll_rw_block (WRITE, 1, &where->bh);			wait_on_buffer(where->bh);		}	}	if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)		ext2_sync_inode (inode);	else		mark_inode_dirty(inode);	return 0;changed:	for (i = 1; i < num; i++)		bforget(where[i].bh);	for (i = 0; i < num; i++)		ext2_free_blocks(inode, le32_to_cpu(where[i].key), 1);	return -EAGAIN;}/* * Allocation strategy is simple: if we have to allocate something, we will * have to go the whole way to leaf. So let's do it before attaching anything * to tree, set linkage between the newborn blocks, write them if sync is * required, recheck the path, free and repeat if check fails, otherwise * set the last missing link (that will protect us from any truncate-generated * removals - all blocks on the path are immune now) and possibly force the * write on the parent block. * That has a nice additional property: no special recovery from the failed * allocations is needed - we simply release blocks and do not touch anything * reachable from inode. */static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create){	int err = -EIO;	int offsets[4];	Indirect chain[4];	Indirect *partial;	unsigned long goal;	int left;	int depth = ext2_block_to_path(inode, iblock, offsets);	if (depth == 0)		goto out;	lock_kernel();reread:	partial = ext2_get_branch(inode, depth, offsets, chain, &err);	/* Simplest case - block found, no allocation needed */	if (!partial) {got_it:		bh_result->b_dev = inode->i_dev;		bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key);		bh_result->b_state |= (1UL << BH_Mapped);		/* Clean up and exit */		partial = chain+depth-1; /* the whole chain */		goto cleanup;	}	/* Next simple case - plain lookup or failed read of indirect block */	if (!create || err == -EIO) {cleanup:		while (partial > chain) {			brelse(partial->bh);			partial--;		}		unlock_kernel();out:		return err;	}	/*	 * Indirect block might be removed by truncate while we were	 * reading it. Handling of that case (forget what we've got and	 * reread) is taken out of the main path.	 */	if (err == -EAGAIN)		goto changed;	if (ext2_find_goal(inode, iblock, chain, partial, &goal) < 0)		goto changed;	left = (chain + depth) - partial;	err = ext2_alloc_branch(inode, left, goal,					offsets+(partial-chain), partial);	if (err)		goto cleanup;	if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)		goto changed;	bh_result->b_state |= (1UL << BH_New);	goto got_it;changed:	while (partial > chain) {		brelse(partial->bh);		partial--;	}	goto reread;}static int ext2_writepage(struct page *page){	return block_write_full_page(page,ext2_get_block);}static int ext2_readpage(struct file *file, struct page *page){	return block_read_full_page(page,ext2_get_block);}static int ext2_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to){	return block_prepare_write(page,from,to,ext2_get_block);}static int ext2_bmap(struct address_space *mapping, long block){	return generic_block_bmap(mapping,block,ext2_get_block);}static int ext2_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize){	return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, ext2_get_block);}struct address_space_operations ext2_aops = {	readpage: ext2_readpage,	writepage: ext2_writepage,	sync_page: block_sync_page,	prepare_write: ext2_prepare_write,	commit_write: generic_commit_write,	bmap: ext2_bmap,	direct_IO: ext2_direct_IO,};/* * Probably it should be a library function... search for first non-zero word * or memcmp with zero_page, whatever is better for particular architecture. * Linus? */static inline int all_zeroes(u32 *p, u32 *q){	while (p < q)		if (*p++)			return 0;	return 1;}/** *	ext2_find_shared - find the indirect blocks for partial truncation. *	@inode:	  inode in question *	@depth:	  depth of the affected branch *	@offsets: offsets of pointers in that branch (see ext2_block_to_path) *	@chain:	  place to store the pointers to partial indirect blocks *	@top:	  place to the (detached) top of branch * *	This is a helper function used by ext2_truncate(). * *	When we do truncate() we may have to clean the ends of several indirect *	blocks but leave the blocks themselves alive. Block is partially *	truncated if some data below the new i_size is refered from it (and *	it is on the path to the first completely truncated data block, indeed). *	We have to free the top of that path along with everything to the right *	of the path. Since no allocation past the truncation point is possible *	until ext2_truncate() finishes, we may safely do the latter, but top *	of branch may require special attention - pageout below the truncation *	point might try to populate it. * *	We atomically detach the top of branch from the tree, store the block *	number of its root in *@top, pointers to buffer_heads of partially *	truncated blocks - in @chain[].bh and pointers to their last elements *	that should not be removed - in @chain[].p. Return value is the pointer *	to last filled element of @chain. * *	The work left to caller to do the actual freeing of subtrees: *		a) free the subtree starting from *@top *		b) free the subtrees whose roots are stored in *			(@chain[i].p+1 .. end of @chain[i].bh->b_data) *		c) free the subtrees growing from the inode past the @chain[0].p *			(no partially truncated stuff there). */static Indirect *ext2_find_shared(struct inode *inode,				int depth,				int offsets[4],				Indirect chain[4],				u32 *top){	Indirect *partial, *p;	int k, err;	*top = 0;	for (k = depth; k > 1 && !offsets[k-1]; k--)		;	partial = ext2_get_branch(inode, k, offsets, chain, &err);	/* Writer: pointers */	if (!partial)		partial = chain + k-1;	/*	 * If the branch acquired continuation since we've looked at it -	 * fine, it should all survive and (new) top doesn't belong to us.	 */	if (!partial->key && *partial->p)		/* Writer: end */		goto no_top;	for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--)		;	/*	 * OK, we've found the last block that must survive. The rest of our	 * branch should be detached before unlocking. However, if that rest	 * of branch is all ours and does not grow immediately from the inode	 * it's easier to cheat and just decrement partial->p.	 */	if (p == chain + k - 1 && p > chain) {		p->p--;	} else {		*top = *p->p;		*p->p = 0;	}	/* Writer: end */	while(partial > p)	{		brelse(partial->bh);		partial--;	}no_top:	return partial;}/** *	ext2_free_data - free a list of data blocks *	@inode:	inode we are dealing with *	@p:	array of block numbers *	@q:	points immediately past the end of array * *	We are freeing all blocks refered from that array (numbers are *	stored as little-endian 32-bit) and updating @inode->i_blocks *	appropriately. */static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q){	unsigned long block_to_free = 0, count = 0;	unsigned long nr;	for ( ; p < q ; p++) {		nr = le32_to_cpu(*p);		if (nr) {			*p = 0;			/* accumulate blocks to free if they're contiguous */			if (count == 0)				goto free_this;			else if (block_to_free == nr - count)				count++;			else {				mark_inode_dirty(inode);				ext2_free_blocks (inode, block_to_free, count);			free_this:				block_to_free = nr;				count = 1;			}		}	}	if (count > 0) {		mark_inode_dirty(inode);		ext2_free_blocks (inode, block_to_free, count);	}}/** *	ext2_free_branches - free an array of branches *	@inode:	inode we are dealing with *	@p:	array of block numbers *	@q:	pointer immediately past the end of array *	@depth:	depth of the branches to free * *	We are freeing all blocks refered from these branches (numbers are *	stored as little-endian 32-bit) and updating @inode->i_blocks *	appropriately. */static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth){	struct buffer_head * bh;	unsigned long nr;	if (depth--) {		int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);		for ( ; p < q ; p++) {			nr = le32_to_cpu(*p);			if (!nr)				continue;			*p = 0;			bh = sb_bread(inode->i_sb, nr);			/*			 * A read failure? Report error and clear slot			 * (should be rare).			 */ 			if (!bh) {				ext2_error(inode->i_sb, "ext2_free_branches",					"Read failure, inode=%ld, block=%ld",					inode->i_ino, nr);				continue;

⌨️ 快捷键说明

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