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

📄 inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			 */			for (i=1; i < num; i++)				*(branch[n].p + i) = cpu_to_le32(++current_block);		}		set_buffer_uptodate(bh);		unlock_buffer(bh);		mark_buffer_dirty_inode(bh, inode);		/* We used to sync bh here if IS_SYNC(inode).		 * But we now rely upon generic_osync_inode()		 * and b_inode_buffers.  But not for directories.		 */		if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode))			sync_dirty_buffer(bh);	}	*blks = num;	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 indirect blocks we are adding * @blks:  number of direct blocks we are adding * * This function 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. */static void ext2_splice_branch(struct inode *inode,			long block, Indirect *where, int num, int blks){	int i;	struct ext2_block_alloc_info *block_i;	ext2_fsblk_t current_block;	block_i = EXT2_I(inode)->i_block_alloc_info;	/* XXX LOCKING probably should have i_meta_lock ?*/	/* That's it */	*where->p = where->key;	/*	 * Update the host buffer_head or inode to point to more just allocated	 * direct blocks blocks	 */	if (num == 0 && blks > 1) {		current_block = le32_to_cpu(where->key) + 1;		for (i = 1; i < blks; i++)			*(where->p + i ) = cpu_to_le32(current_block++);	}	/*	 * update the most recently allocated logical & physical block	 * in i_block_alloc_info, to assist find the proper goal block for next	 * allocation	 */	if (block_i) {		block_i->last_alloc_logical_block = block + blks - 1;		block_i->last_alloc_physical_block =				le32_to_cpu(where[num].key) + blks - 1;	}	/* We are done with atomic stuff, now do the rest of housekeeping */	/* had we spliced it onto indirect block? */	if (where->bh)		mark_buffer_dirty_inode(where->bh, inode);	inode->i_ctime = CURRENT_TIME_SEC;	mark_inode_dirty(inode);}/* * 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. * * `handle' can be NULL if create == 0. * * The BKL may not be held on entry here.  Be sure to take it early. * return > 0, # of blocks mapped or allocated. * return = 0, if plain lookup failed. * return < 0, error case. */static int ext2_get_blocks(struct inode *inode,			   sector_t iblock, unsigned long maxblocks,			   struct buffer_head *bh_result,			   int create){	int err = -EIO;	int offsets[4];	Indirect chain[4];	Indirect *partial;	ext2_fsblk_t goal;	int indirect_blks;	int blocks_to_boundary = 0;	int depth;	struct ext2_inode_info *ei = EXT2_I(inode);	int count = 0;	ext2_fsblk_t first_block = 0;	depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary);	if (depth == 0)		return (err);reread:	partial = ext2_get_branch(inode, depth, offsets, chain, &err);	/* Simplest case - block found, no allocation needed */	if (!partial) {		first_block = le32_to_cpu(chain[depth - 1].key);		clear_buffer_new(bh_result); /* What's this do? */		count++;		/*map more blocks*/		while (count < maxblocks && count <= blocks_to_boundary) {			ext2_fsblk_t blk;			if (!verify_chain(chain, partial)) {				/*				 * Indirect block might be removed by				 * truncate while we were reading it.				 * Handling of that case: forget what we've				 * got now, go to reread.				 */				count = 0;				goto changed;			}			blk = le32_to_cpu(*(chain[depth-1].p + count));			if (blk == first_block + count)				count++;			else				break;		}		goto got_it;	}	/* Next simple case - plain lookup or failed read of indirect block */	if (!create || err == -EIO)		goto cleanup;	mutex_lock(&ei->truncate_mutex);	/*	 * Okay, we need to do block allocation.  Lazily initialize the block	 * allocation info here if necessary	*/	if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))		ext2_init_block_alloc_info(inode);	goal = ext2_find_goal(inode, iblock, chain, partial);	/* the number of blocks need to allocate for [d,t]indirect blocks */	indirect_blks = (chain + depth) - partial - 1;	/*	 * Next look up the indirect map to count the totoal number of	 * direct blocks to allocate for this branch.	 */	count = ext2_blks_to_allocate(partial, indirect_blks,					maxblocks, blocks_to_boundary);	/*	 * XXX ???? Block out ext2_truncate while we alter the tree	 */	err = ext2_alloc_branch(inode, indirect_blks, &count, goal,				offsets + (partial - chain), partial);	if (err) {		mutex_unlock(&ei->truncate_mutex);		goto cleanup;	}	if (ext2_use_xip(inode->i_sb)) {		/*		 * we need to clear the block		 */		err = ext2_clear_xip_target (inode,			le32_to_cpu(chain[depth-1].key));		if (err) {			mutex_unlock(&ei->truncate_mutex);			goto cleanup;		}	}	ext2_splice_branch(inode, iblock, partial, indirect_blks, count);	mutex_unlock(&ei->truncate_mutex);	set_buffer_new(bh_result);got_it:	map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));	if (count > blocks_to_boundary)		set_buffer_boundary(bh_result);	err = count;	/* Clean up and exit */	partial = chain + depth - 1;	/* the whole chain */cleanup:	while (partial > chain) {		brelse(partial->bh);		partial--;	}	return err;changed:	while (partial > chain) {		brelse(partial->bh);		partial--;	}	goto reread;}int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create){	unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;	int ret = ext2_get_blocks(inode, iblock, max_blocks,			      bh_result, create);	if (ret > 0) {		bh_result->b_size = (ret << inode->i_blkbits);		ret = 0;	}	return ret;}static int ext2_writepage(struct page *page, struct writeback_control *wbc){	return block_write_full_page(page, ext2_get_block, wbc);}static int ext2_readpage(struct file *file, struct page *page){	return mpage_readpage(page, ext2_get_block);}static intext2_readpages(struct file *file, struct address_space *mapping,		struct list_head *pages, unsigned nr_pages){	return mpage_readpages(mapping, pages, nr_pages, ext2_get_block);}int __ext2_write_begin(struct file *file, struct address_space *mapping,		loff_t pos, unsigned len, unsigned flags,		struct page **pagep, void **fsdata){	return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,							ext2_get_block);}static intext2_write_begin(struct file *file, struct address_space *mapping,		loff_t pos, unsigned len, unsigned flags,		struct page **pagep, void **fsdata){	*pagep = NULL;	return __ext2_write_begin(file, mapping, pos, len, flags, pagep,fsdata);}static intext2_nobh_write_begin(struct file *file, struct address_space *mapping,		loff_t pos, unsigned len, unsigned flags,		struct page **pagep, void **fsdata){	/*	 * Dir-in-pagecache still uses ext2_write_begin. Would have to rework	 * directory handling code to pass around offsets rather than struct	 * pages in order to make this work easily.	 */	return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,							ext2_get_block);}static int ext2_nobh_writepage(struct page *page,			struct writeback_control *wbc){	return nobh_writepage(page, ext2_get_block, wbc);}static sector_t ext2_bmap(struct address_space *mapping, sector_t block){	return generic_block_bmap(mapping,block,ext2_get_block);}static ssize_text2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,			loff_t offset, unsigned long nr_segs){	struct file *file = iocb->ki_filp;	struct inode *inode = file->f_mapping->host;	return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,				offset, nr_segs, ext2_get_block, NULL);}static intext2_writepages(struct address_space *mapping, struct writeback_control *wbc){	return mpage_writepages(mapping, wbc, ext2_get_block);}const struct address_space_operations ext2_aops = {	.readpage		= ext2_readpage,	.readpages		= ext2_readpages,	.writepage		= ext2_writepage,	.sync_page		= block_sync_page,	.write_begin		= ext2_write_begin,	.write_end		= generic_write_end,	.bmap			= ext2_bmap,	.direct_IO		= ext2_direct_IO,	.writepages		= ext2_writepages,	.migratepage		= buffer_migrate_page,};const struct address_space_operations ext2_aops_xip = {	.bmap			= ext2_bmap,	.get_xip_page		= ext2_get_xip_page,};const struct address_space_operations ext2_nobh_aops = {	.readpage		= ext2_readpage,	.readpages		= ext2_readpages,	.writepage		= ext2_nobh_writepage,	.sync_page		= block_sync_page,	.write_begin		= ext2_nobh_write_begin,	.write_end		= nobh_write_end,	.bmap			= ext2_bmap,	.direct_IO		= ext2_direct_IO,	.writepages		= ext2_writepages,	.migratepage		= buffer_migrate_page,};/* * 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(__le32 *p, __le32 *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],				__le32 *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);	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.	 */	write_lock(&EXT2_I(inode)->i_meta_lock);	if (!partial->key && *partial->p) {		write_unlock(&EXT2_I(inode)->i_meta_lock);		goto no_top;	}	for (p=partial; p>chain && all_zeroes((__le32*)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;	}	write_unlock(&EXT2_I(inode)->i_meta_lock);	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, __le32 *p, __le32 *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 *

⌨️ 快捷键说明

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