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

📄 extents.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com * Written by Alex Tomas <alex@clusterfs.com> * * Architecture independence: *   Copyright (c) 2005, Bull S.A. *   Written by Pierre Peiffer <pierre.peiffer@bull.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public Licens * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111- *//* * Extents support for EXT4 * * TODO: *   - ext4*_error() should be used in some situations *   - analyze all BUG()/BUG_ON(), use -EIO where appropriate *   - smart tree reduction */#include <linux/module.h>#include <linux/fs.h>#include <linux/time.h>#include <linux/ext4_jbd2.h>#include <linux/jbd2.h>#include <linux/highuid.h>#include <linux/pagemap.h>#include <linux/quotaops.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/falloc.h>#include <linux/ext4_fs_extents.h>#include <asm/uaccess.h>/* * ext_pblock: * combine low and high parts of physical block number into ext4_fsblk_t */static ext4_fsblk_t ext_pblock(struct ext4_extent *ex){	ext4_fsblk_t block;	block = le32_to_cpu(ex->ee_start_lo);	block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1;	return block;}/* * idx_pblock: * combine low and high parts of a leaf physical block number into ext4_fsblk_t */static ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix){	ext4_fsblk_t block;	block = le32_to_cpu(ix->ei_leaf_lo);	block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1;	return block;}/* * ext4_ext_store_pblock: * stores a large physical block number into an extent struct, * breaking it into parts */static void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb){	ex->ee_start_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));	ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);}/* * ext4_idx_store_pblock: * stores a large physical block number into an index struct, * breaking it into parts */static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb){	ix->ei_leaf_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff));	ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);}static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed){	int err;	if (handle->h_buffer_credits > needed)		return handle;	if (!ext4_journal_extend(handle, needed))		return handle;	err = ext4_journal_restart(handle, needed);	return handle;}/* * could return: *  - EROFS *  - ENOMEM */static int ext4_ext_get_access(handle_t *handle, struct inode *inode,				struct ext4_ext_path *path){	if (path->p_bh) {		/* path points to block */		return ext4_journal_get_write_access(handle, path->p_bh);	}	/* path points to leaf/index in inode body */	/* we use in-core data, no need to protect them */	return 0;}/* * could return: *  - EROFS *  - ENOMEM *  - EIO */static int ext4_ext_dirty(handle_t *handle, struct inode *inode,				struct ext4_ext_path *path){	int err;	if (path->p_bh) {		/* path points to block */		err = ext4_journal_dirty_metadata(handle, path->p_bh);	} else {		/* path points to leaf/index in inode body */		err = ext4_mark_inode_dirty(handle, inode);	}	return err;}static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,			      struct ext4_ext_path *path,			      ext4_fsblk_t block){	struct ext4_inode_info *ei = EXT4_I(inode);	ext4_fsblk_t bg_start;	ext4_grpblk_t colour;	int depth;	if (path) {		struct ext4_extent *ex;		depth = path->p_depth;		/* try to predict block placement */		ex = path[depth].p_ext;		if (ex)			return ext_pblock(ex)+(block-le32_to_cpu(ex->ee_block));		/* it looks like index is empty;		 * try to find starting block from index itself */		if (path[depth].p_bh)			return path[depth].p_bh->b_blocknr;	}	/* OK. use inode's group */	bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +		le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block);	colour = (current->pid % 16) *			(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);	return bg_start + colour + block;}static ext4_fsblk_text4_ext_new_block(handle_t *handle, struct inode *inode,			struct ext4_ext_path *path,			struct ext4_extent *ex, int *err){	ext4_fsblk_t goal, newblock;	goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block));	newblock = ext4_new_block(handle, inode, goal, err);	return newblock;}static int ext4_ext_space_block(struct inode *inode){	int size;	size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))			/ sizeof(struct ext4_extent);#ifdef AGGRESSIVE_TEST	if (size > 6)		size = 6;#endif	return size;}static int ext4_ext_space_block_idx(struct inode *inode){	int size;	size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))			/ sizeof(struct ext4_extent_idx);#ifdef AGGRESSIVE_TEST	if (size > 5)		size = 5;#endif	return size;}static int ext4_ext_space_root(struct inode *inode){	int size;	size = sizeof(EXT4_I(inode)->i_data);	size -= sizeof(struct ext4_extent_header);	size /= sizeof(struct ext4_extent);#ifdef AGGRESSIVE_TEST	if (size > 3)		size = 3;#endif	return size;}static int ext4_ext_space_root_idx(struct inode *inode){	int size;	size = sizeof(EXT4_I(inode)->i_data);	size -= sizeof(struct ext4_extent_header);	size /= sizeof(struct ext4_extent_idx);#ifdef AGGRESSIVE_TEST	if (size > 4)		size = 4;#endif	return size;}static intext4_ext_max_entries(struct inode *inode, int depth){	int max;	if (depth == ext_depth(inode)) {		if (depth == 0)			max = ext4_ext_space_root(inode);		else			max = ext4_ext_space_root_idx(inode);	} else {		if (depth == 0)			max = ext4_ext_space_block(inode);		else			max = ext4_ext_space_block_idx(inode);	}	return max;}static int __ext4_ext_check_header(const char *function, struct inode *inode,					struct ext4_extent_header *eh,					int depth){	const char *error_msg;	int max = 0;	if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {		error_msg = "invalid magic";		goto corrupted;	}	if (unlikely(le16_to_cpu(eh->eh_depth) != depth)) {		error_msg = "unexpected eh_depth";		goto corrupted;	}	if (unlikely(eh->eh_max == 0)) {		error_msg = "invalid eh_max";		goto corrupted;	}	max = ext4_ext_max_entries(inode, depth);	if (unlikely(le16_to_cpu(eh->eh_max) > max)) {		error_msg = "too large eh_max";		goto corrupted;	}	if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {		error_msg = "invalid eh_entries";		goto corrupted;	}	return 0;corrupted:	ext4_error(inode->i_sb, function,			"bad header in inode #%lu: %s - magic %x, "			"entries %u, max %u(%u), depth %u(%u)",			inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),			le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),			max, le16_to_cpu(eh->eh_depth), depth);	return -EIO;}#define ext4_ext_check_header(inode, eh, depth)	\	__ext4_ext_check_header(__FUNCTION__, inode, eh, depth)#ifdef EXT_DEBUGstatic void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path){	int k, l = path->p_depth;	ext_debug("path:");	for (k = 0; k <= l; k++, path++) {		if (path->p_idx) {		  ext_debug("  %d->%llu", le32_to_cpu(path->p_idx->ei_block),			    idx_pblock(path->p_idx));		} else if (path->p_ext) {			ext_debug("  %d:%d:%llu ",				  le32_to_cpu(path->p_ext->ee_block),				  ext4_ext_get_actual_len(path->p_ext),				  ext_pblock(path->p_ext));		} else			ext_debug("  []");	}	ext_debug("\n");}static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path){	int depth = ext_depth(inode);	struct ext4_extent_header *eh;	struct ext4_extent *ex;	int i;	if (!path)		return;	eh = path[depth].p_hdr;	ex = EXT_FIRST_EXTENT(eh);	for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {		ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),			  ext4_ext_get_actual_len(ex), ext_pblock(ex));	}	ext_debug("\n");}#else#define ext4_ext_show_path(inode,path)#define ext4_ext_show_leaf(inode,path)#endifstatic void ext4_ext_drop_refs(struct ext4_ext_path *path){	int depth = path->p_depth;	int i;	for (i = 0; i <= depth; i++, path++)		if (path->p_bh) {			brelse(path->p_bh);			path->p_bh = NULL;		}}/* * ext4_ext_binsearch_idx: * binary search for the closest index of the given block * the header must be checked before calling this */static voidext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block){	struct ext4_extent_header *eh = path->p_hdr;	struct ext4_extent_idx *r, *l, *m;	ext_debug("binsearch for %d(idx):  ", block);	l = EXT_FIRST_INDEX(eh) + 1;	r = EXT_LAST_INDEX(eh);	while (l <= r) {		m = l + (r - l) / 2;		if (block < le32_to_cpu(m->ei_block))			r = m - 1;		else			l = m + 1;		ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ei_block),				m, le32_to_cpu(m->ei_block),				r, le32_to_cpu(r->ei_block));	}	path->p_idx = l - 1;	ext_debug("  -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),		  idx_pblock(path->p_idx));#ifdef CHECK_BINSEARCH	{		struct ext4_extent_idx *chix, *ix;		int k;		chix = ix = EXT_FIRST_INDEX(eh);		for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) {		  if (k != 0 &&		      le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) {				printk("k=%d, ix=0x%p, first=0x%p\n", k,					ix, EXT_FIRST_INDEX(eh));				printk("%u <= %u\n",				       le32_to_cpu(ix->ei_block),				       le32_to_cpu(ix[-1].ei_block));			}			BUG_ON(k && le32_to_cpu(ix->ei_block)					   <= le32_to_cpu(ix[-1].ei_block));			if (block < le32_to_cpu(ix->ei_block))				break;			chix = ix;		}		BUG_ON(chix != path->p_idx);	}#endif}/* * ext4_ext_binsearch: * binary search for closest extent of the given block * the header must be checked before calling this */static voidext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block){	struct ext4_extent_header *eh = path->p_hdr;	struct ext4_extent *r, *l, *m;	if (eh->eh_entries == 0) {		/*		 * this leaf is empty:		 * we get such a leaf in split/add case		 */		return;	}	ext_debug("binsearch for %d:  ", block);	l = EXT_FIRST_EXTENT(eh) + 1;	r = EXT_LAST_EXTENT(eh);	while (l <= r) {		m = l + (r - l) / 2;		if (block < le32_to_cpu(m->ee_block))			r = m - 1;		else			l = m + 1;		ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ee_block),				m, le32_to_cpu(m->ee_block),				r, le32_to_cpu(r->ee_block));	}	path->p_ext = l - 1;	ext_debug("  -> %d:%llu:%d ",			le32_to_cpu(path->p_ext->ee_block),			ext_pblock(path->p_ext),			ext4_ext_get_actual_len(path->p_ext));#ifdef CHECK_BINSEARCH	{		struct ext4_extent *chex, *ex;		int k;		chex = ex = EXT_FIRST_EXTENT(eh);		for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) {			BUG_ON(k && le32_to_cpu(ex->ee_block)					  <= le32_to_cpu(ex[-1].ee_block));			if (block < le32_to_cpu(ex->ee_block))				break;			chex = ex;		}		BUG_ON(chex != path->p_ext);	}#endif}int ext4_ext_tree_init(handle_t *handle, struct inode *inode){	struct ext4_extent_header *eh;	eh = ext_inode_hdr(inode);	eh->eh_depth = 0;	eh->eh_entries = 0;	eh->eh_magic = EXT4_EXT_MAGIC;	eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode));	ext4_mark_inode_dirty(handle, inode);	ext4_ext_invalidate_cache(inode);	return 0;}struct ext4_ext_path *ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path){	struct ext4_extent_header *eh;	struct buffer_head *bh;	short int depth, i, ppos = 0, alloc = 0;	eh = ext_inode_hdr(inode);	depth = ext_depth(inode);

⌨️ 快捷键说明

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