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

📄 alloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * * ocfs2_shift_tree_depth() uses this to determine the # clusters * value for the new topmost tree record. */static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list  *el){	int i;	i = le16_to_cpu(el->l_next_free_rec) - 1;	return le32_to_cpu(el->l_recs[i].e_cpos) +		ocfs2_rec_clusters(el, &el->l_recs[i]);}/* * Add an entire tree branch to our inode. eb_bh is the extent block * to start at, if we don't want to start the branch at the dinode * structure. * * last_eb_bh is required as we have to update it's next_leaf pointer * for the new last extent block. * * the new branch will be 'empty' in the sense that every block will * contain a single record with cluster count == 0. */static int ocfs2_add_branch(struct ocfs2_super *osb,			    handle_t *handle,			    struct inode *inode,			    struct buffer_head *fe_bh,			    struct buffer_head *eb_bh,			    struct buffer_head **last_eb_bh,			    struct ocfs2_alloc_context *meta_ac){	int status, new_blocks, i;	u64 next_blkno, new_last_eb_blk;	struct buffer_head *bh;	struct buffer_head **new_eb_bhs = NULL;	struct ocfs2_dinode *fe;	struct ocfs2_extent_block *eb;	struct ocfs2_extent_list  *eb_el;	struct ocfs2_extent_list  *el;	u32 new_cpos;	mlog_entry_void();	BUG_ON(!last_eb_bh || !*last_eb_bh);	fe = (struct ocfs2_dinode *) fe_bh->b_data;	if (eb_bh) {		eb = (struct ocfs2_extent_block *) eb_bh->b_data;		el = &eb->h_list;	} else		el = &fe->id2.i_list;	/* we never add a branch to a leaf. */	BUG_ON(!el->l_tree_depth);	new_blocks = le16_to_cpu(el->l_tree_depth);	/* allocate the number of new eb blocks we need */	new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *),			     GFP_KERNEL);	if (!new_eb_bhs) {		status = -ENOMEM;		mlog_errno(status);		goto bail;	}	status = ocfs2_create_new_meta_bhs(osb, handle, inode, new_blocks,					   meta_ac, new_eb_bhs);	if (status < 0) {		mlog_errno(status);		goto bail;	}	eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;	new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);	/* Note: new_eb_bhs[new_blocks - 1] is the guy which will be	 * linked with the rest of the tree.	 * conversly, new_eb_bhs[0] is the new bottommost leaf.	 *	 * when we leave the loop, new_last_eb_blk will point to the	 * newest leaf, and next_blkno will point to the topmost extent	 * block. */	next_blkno = new_last_eb_blk = 0;	for(i = 0; i < new_blocks; i++) {		bh = new_eb_bhs[i];		eb = (struct ocfs2_extent_block *) bh->b_data;		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);			status = -EIO;			goto bail;		}		eb_el = &eb->h_list;		status = ocfs2_journal_access(handle, inode, bh,					      OCFS2_JOURNAL_ACCESS_CREATE);		if (status < 0) {			mlog_errno(status);			goto bail;		}		eb->h_next_leaf_blk = 0;		eb_el->l_tree_depth = cpu_to_le16(i);		eb_el->l_next_free_rec = cpu_to_le16(1);		/*		 * This actually counts as an empty extent as		 * c_clusters == 0		 */		eb_el->l_recs[0].e_cpos = cpu_to_le32(new_cpos);		eb_el->l_recs[0].e_blkno = cpu_to_le64(next_blkno);		/*		 * eb_el isn't always an interior node, but even leaf		 * nodes want a zero'd flags and reserved field so		 * this gets the whole 32 bits regardless of use.		 */		eb_el->l_recs[0].e_int_clusters = cpu_to_le32(0);		if (!eb_el->l_tree_depth)			new_last_eb_blk = le64_to_cpu(eb->h_blkno);		status = ocfs2_journal_dirty(handle, bh);		if (status < 0) {			mlog_errno(status);			goto bail;		}		next_blkno = le64_to_cpu(eb->h_blkno);	}	/* This is a bit hairy. We want to update up to three blocks	 * here without leaving any of them in an inconsistent state	 * in case of error. We don't have to worry about	 * journal_dirty erroring as it won't unless we've aborted the	 * handle (in which case we would never be here) so reserving	 * the write with journal_access is all we need to do. */	status = ocfs2_journal_access(handle, inode, *last_eb_bh,				      OCFS2_JOURNAL_ACCESS_WRITE);	if (status < 0) {		mlog_errno(status);		goto bail;	}	status = ocfs2_journal_access(handle, inode, fe_bh,				      OCFS2_JOURNAL_ACCESS_WRITE);	if (status < 0) {		mlog_errno(status);		goto bail;	}	if (eb_bh) {		status = ocfs2_journal_access(handle, inode, eb_bh,					      OCFS2_JOURNAL_ACCESS_WRITE);		if (status < 0) {			mlog_errno(status);			goto bail;		}	}	/* Link the new branch into the rest of the tree (el will	 * either be on the fe, or the extent block passed in. */	i = le16_to_cpu(el->l_next_free_rec);	el->l_recs[i].e_blkno = cpu_to_le64(next_blkno);	el->l_recs[i].e_cpos = cpu_to_le32(new_cpos);	el->l_recs[i].e_int_clusters = 0;	le16_add_cpu(&el->l_next_free_rec, 1);	/* fe needs a new last extent block pointer, as does the	 * next_leaf on the previously last-extent-block. */	fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk);	eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data;	eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk);	status = ocfs2_journal_dirty(handle, *last_eb_bh);	if (status < 0)		mlog_errno(status);	status = ocfs2_journal_dirty(handle, fe_bh);	if (status < 0)		mlog_errno(status);	if (eb_bh) {		status = ocfs2_journal_dirty(handle, eb_bh);		if (status < 0)			mlog_errno(status);	}	/*	 * Some callers want to track the rightmost leaf so pass it	 * back here.	 */	brelse(*last_eb_bh);	get_bh(new_eb_bhs[0]);	*last_eb_bh = new_eb_bhs[0];	status = 0;bail:	if (new_eb_bhs) {		for (i = 0; i < new_blocks; i++)			if (new_eb_bhs[i])				brelse(new_eb_bhs[i]);		kfree(new_eb_bhs);	}	mlog_exit(status);	return status;}/* * adds another level to the allocation tree. * returns back the new extent block so you can add a branch to it * after this call. */static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,				  handle_t *handle,				  struct inode *inode,				  struct buffer_head *fe_bh,				  struct ocfs2_alloc_context *meta_ac,				  struct buffer_head **ret_new_eb_bh){	int status, i;	u32 new_clusters;	struct buffer_head *new_eb_bh = NULL;	struct ocfs2_dinode *fe;	struct ocfs2_extent_block *eb;	struct ocfs2_extent_list  *fe_el;	struct ocfs2_extent_list  *eb_el;	mlog_entry_void();	status = ocfs2_create_new_meta_bhs(osb, handle, inode, 1, meta_ac,					   &new_eb_bh);	if (status < 0) {		mlog_errno(status);		goto bail;	}	eb = (struct ocfs2_extent_block *) new_eb_bh->b_data;	if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {		OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);		status = -EIO;		goto bail;	}	eb_el = &eb->h_list;	fe = (struct ocfs2_dinode *) fe_bh->b_data;	fe_el = &fe->id2.i_list;	status = ocfs2_journal_access(handle, inode, new_eb_bh,				      OCFS2_JOURNAL_ACCESS_CREATE);	if (status < 0) {		mlog_errno(status);		goto bail;	}	/* copy the fe data into the new extent block */	eb_el->l_tree_depth = fe_el->l_tree_depth;	eb_el->l_next_free_rec = fe_el->l_next_free_rec;	for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++)		eb_el->l_recs[i] = fe_el->l_recs[i];	status = ocfs2_journal_dirty(handle, new_eb_bh);	if (status < 0) {		mlog_errno(status);		goto bail;	}	status = ocfs2_journal_access(handle, inode, fe_bh,				      OCFS2_JOURNAL_ACCESS_WRITE);	if (status < 0) {		mlog_errno(status);		goto bail;	}	new_clusters = ocfs2_sum_rightmost_rec(eb_el);	/* update fe now */	le16_add_cpu(&fe_el->l_tree_depth, 1);	fe_el->l_recs[0].e_cpos = 0;	fe_el->l_recs[0].e_blkno = eb->h_blkno;	fe_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);	for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++)		memset(&fe_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));	fe_el->l_next_free_rec = cpu_to_le16(1);	/* If this is our 1st tree depth shift, then last_eb_blk	 * becomes the allocated extent block */	if (fe_el->l_tree_depth == cpu_to_le16(1))		fe->i_last_eb_blk = eb->h_blkno;	status = ocfs2_journal_dirty(handle, fe_bh);	if (status < 0) {		mlog_errno(status);		goto bail;	}	*ret_new_eb_bh = new_eb_bh;	new_eb_bh = NULL;	status = 0;bail:	if (new_eb_bh)		brelse(new_eb_bh);	mlog_exit(status);	return status;}/* * Should only be called when there is no space left in any of the * leaf nodes. What we want to do is find the lowest tree depth * non-leaf extent block with room for new records. There are three * valid results of this search: * * 1) a lowest extent block is found, then we pass it back in *    *lowest_eb_bh and return '0' * * 2) the search fails to find anything, but the dinode has room. We *    pass NULL back in *lowest_eb_bh, but still return '0' * * 3) the search fails to find anything AND the dinode is full, in *    which case we return > 0 * * return status < 0 indicates an error. */static int ocfs2_find_branch_target(struct ocfs2_super *osb,				    struct inode *inode,				    struct buffer_head *fe_bh,				    struct buffer_head **target_bh){	int status = 0, i;	u64 blkno;	struct ocfs2_dinode *fe;	struct ocfs2_extent_block *eb;	struct ocfs2_extent_list  *el;	struct buffer_head *bh = NULL;	struct buffer_head *lowest_bh = NULL;	mlog_entry_void();	*target_bh = NULL;	fe = (struct ocfs2_dinode *) fe_bh->b_data;	el = &fe->id2.i_list;	while(le16_to_cpu(el->l_tree_depth) > 1) {		if (le16_to_cpu(el->l_next_free_rec) == 0) {			ocfs2_error(inode->i_sb, "Dinode %llu has empty "				    "extent list (next_free_rec == 0)",				    (unsigned long long)OCFS2_I(inode)->ip_blkno);			status = -EIO;			goto bail;		}		i = le16_to_cpu(el->l_next_free_rec) - 1;		blkno = le64_to_cpu(el->l_recs[i].e_blkno);		if (!blkno) {			ocfs2_error(inode->i_sb, "Dinode %llu has extent "				    "list where extent # %d has no physical "				    "block start",				    (unsigned long long)OCFS2_I(inode)->ip_blkno, i);			status = -EIO;			goto bail;		}		if (bh) {			brelse(bh);			bh = NULL;		}		status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED,					  inode);		if (status < 0) {			mlog_errno(status);			goto bail;		}		eb = (struct ocfs2_extent_block *) bh->b_data;		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);			status = -EIO;			goto bail;		}		el = &eb->h_list;		if (le16_to_cpu(el->l_next_free_rec) <		    le16_to_cpu(el->l_count)) {			if (lowest_bh)				brelse(lowest_bh);			lowest_bh = bh;			get_bh(lowest_bh);		}	}	/* If we didn't find one and the fe doesn't have any room,	 * then return '1' */	if (!lowest_bh	    && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count))		status = 1;	*target_bh = lowest_bh;bail:	if (bh)		brelse(bh);	mlog_exit(status);	return status;}/* * Grow a b-tree so that it has more records. * * We might shift the tree depth in which case existing paths should * be considered invalid. * * Tree depth after the grow is returned via *final_depth. * * *last_eb_bh will be updated by ocfs2_add_branch(). */static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,			   struct buffer_head *di_bh, int *final_depth,			   struct buffer_head **last_eb_bh,			   struct ocfs2_alloc_context *meta_ac){	int ret, shift;	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;	int depth = le16_to_cpu(di->id2.i_list.l_tree_depth);	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);	struct buffer_head *bh = NULL;	BUG_ON(meta_ac == NULL);	shift = ocfs2_find_branch_target(osb, inode, di_bh, &bh);	if (shift < 0) {		ret = shift;		mlog_errno(ret);		goto out;	}	/* We traveled all the way to the bottom of the allocation tree	 * and didn't find room for any more extents - we need to add	 * another tree level */	if (shift) {		BUG_ON(bh);		mlog(0, "need to shift tree depth (current = %d)\n", depth);		/* ocfs2_shift_tree_depth will return us a buffer with		 * the new extent block (so we can pass that to		 * ocfs2_add_branch). */		ret = ocfs2_shift_tree_depth(osb, handle, inode, di_bh,					     meta_ac, &bh);		if (ret < 0) {			mlog_errno(ret);			goto out;		}		depth++;		if (depth == 1) {			/*			 * Special case: we have room now if we shifted from			 * tree_depth 0, so no more work needs to be done.			 *			 * We won't be calling add_branch, so pass			 * back *last_eb_bh as the new leaf. At depth			 * zero, it should always be null so there's			 * no reason to brelse.			 */			BUG_ON(*last_eb_bh);			get_bh(bh);			*last_eb_bh = bh;			goto out;		}	}	/* call ocfs2_add_branch to add the final part of the tree with	 * the new data. */	mlog(0, "add branch. bh = %p\n", bh);	ret = ocfs2_add_branch(osb, handle, inode, di_bh, bh, last_eb_bh,			       meta_ac);	if (ret < 0) {		mlog_errno(ret);		goto out;	}out:	if (final_depth)		*final_depth = depth;	brelse(bh);	return ret;}/* * This is only valid for leaf nodes, which are the only ones that can * have empty extents anyway. */static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec){	return !rec->e_leaf_clusters;}/* * This function will discard the rightmost extent record. */static void ocfs2_shift_records_right(struct ocfs2_extent_list *el){	int next_free = le16_to_cpu(el->l_next_free_rec);	int count = le16_to_cpu(el->l_count);	unsigned int num_bytes;	BUG_ON(!next_free);

⌨️ 快捷键说明

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