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

📄 alloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	el = left_path->p_node[subtree_index].el;	left_el = left_path->p_node[subtree_index + 1].el;	right_el = right_path->p_node[subtree_index + 1].el;	ocfs2_adjust_root_records(el, left_el, right_el,				  left_path->p_node[subtree_index + 1].bh->b_blocknr);	root_bh = left_path->p_node[subtree_index].bh;	ret = ocfs2_journal_dirty(handle, root_bh);	if (ret)		mlog_errno(ret);}static int ocfs2_rotate_subtree_right(struct inode *inode,				      handle_t *handle,				      struct ocfs2_path *left_path,				      struct ocfs2_path *right_path,				      int subtree_index){	int ret, i;	struct buffer_head *right_leaf_bh;	struct buffer_head *left_leaf_bh = NULL;	struct buffer_head *root_bh;	struct ocfs2_extent_list *right_el, *left_el;	struct ocfs2_extent_rec move_rec;	left_leaf_bh = path_leaf_bh(left_path);	left_el = path_leaf_el(left_path);	if (left_el->l_next_free_rec != left_el->l_count) {		ocfs2_error(inode->i_sb,			    "Inode %llu has non-full interior leaf node %llu"			    "(next free = %u)",			    (unsigned long long)OCFS2_I(inode)->ip_blkno,			    (unsigned long long)left_leaf_bh->b_blocknr,			    le16_to_cpu(left_el->l_next_free_rec));		return -EROFS;	}	/*	 * This extent block may already have an empty record, so we	 * return early if so.	 */	if (ocfs2_is_empty_extent(&left_el->l_recs[0]))		return 0;	root_bh = left_path->p_node[subtree_index].bh;	BUG_ON(root_bh != right_path->p_node[subtree_index].bh);	ret = ocfs2_journal_access(handle, inode, root_bh,				   OCFS2_JOURNAL_ACCESS_WRITE);	if (ret) {		mlog_errno(ret);		goto out;	}	for(i = subtree_index + 1; i < path_num_items(right_path); i++) {		ret = ocfs2_journal_access(handle, inode,					   right_path->p_node[i].bh,					   OCFS2_JOURNAL_ACCESS_WRITE);		if (ret) {			mlog_errno(ret);			goto out;		}		ret = ocfs2_journal_access(handle, inode,					   left_path->p_node[i].bh,					   OCFS2_JOURNAL_ACCESS_WRITE);		if (ret) {			mlog_errno(ret);			goto out;		}	}	right_leaf_bh = path_leaf_bh(right_path);	right_el = path_leaf_el(right_path);	/* This is a code error, not a disk corruption. */	mlog_bug_on_msg(!right_el->l_next_free_rec, "Inode %llu: Rotate fails "			"because rightmost leaf block %llu is empty\n",			(unsigned long long)OCFS2_I(inode)->ip_blkno,			(unsigned long long)right_leaf_bh->b_blocknr);	ocfs2_create_empty_extent(right_el);	ret = ocfs2_journal_dirty(handle, right_leaf_bh);	if (ret) {		mlog_errno(ret);		goto out;	}	/* Do the copy now. */	i = le16_to_cpu(left_el->l_next_free_rec) - 1;	move_rec = left_el->l_recs[i];	right_el->l_recs[0] = move_rec;	/*	 * Clear out the record we just copied and shift everything	 * over, leaving an empty extent in the left leaf.	 *	 * We temporarily subtract from next_free_rec so that the	 * shift will lose the tail record (which is now defunct).	 */	le16_add_cpu(&left_el->l_next_free_rec, -1);	ocfs2_shift_records_right(left_el);	memset(&left_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));	le16_add_cpu(&left_el->l_next_free_rec, 1);	ret = ocfs2_journal_dirty(handle, left_leaf_bh);	if (ret) {		mlog_errno(ret);		goto out;	}	ocfs2_complete_edge_insert(inode, handle, left_path, right_path,				subtree_index);out:	return ret;}/* * Given a full path, determine what cpos value would return us a path * containing the leaf immediately to the left of the current one. * * Will return zero if the path passed in is already the leftmost path. */static int ocfs2_find_cpos_for_left_leaf(struct super_block *sb,					 struct ocfs2_path *path, u32 *cpos){	int i, j, ret = 0;	u64 blkno;	struct ocfs2_extent_list *el;	BUG_ON(path->p_tree_depth == 0);	*cpos = 0;	blkno = path_leaf_bh(path)->b_blocknr;	/* Start at the tree node just above the leaf and work our way up. */	i = path->p_tree_depth - 1;	while (i >= 0) {		el = path->p_node[i].el;		/*		 * Find the extent record just before the one in our		 * path.		 */		for(j = 0; j < le16_to_cpu(el->l_next_free_rec); j++) {			if (le64_to_cpu(el->l_recs[j].e_blkno) == blkno) {				if (j == 0) {					if (i == 0) {						/*						 * We've determined that the						 * path specified is already						 * the leftmost one - return a						 * cpos of zero.						 */						goto out;					}					/*					 * The leftmost record points to our					 * leaf - we need to travel up the					 * tree one level.					 */					goto next_node;				}				*cpos = le32_to_cpu(el->l_recs[j - 1].e_cpos);				*cpos = *cpos + ocfs2_rec_clusters(el,							   &el->l_recs[j - 1]);				*cpos = *cpos - 1;				goto out;			}		}		/*		 * If we got here, we never found a valid node where		 * the tree indicated one should be.		 */		ocfs2_error(sb,			    "Invalid extent tree at extent block %llu\n",			    (unsigned long long)blkno);		ret = -EROFS;		goto out;next_node:		blkno = path->p_node[i].bh->b_blocknr;		i--;	}out:	return ret;}/* * Extend the transaction by enough credits to complete the rotation, * and still leave at least the original number of credits allocated * to this transaction. */static int ocfs2_extend_rotate_transaction(handle_t *handle, int subtree_depth,					   int op_credits,					   struct ocfs2_path *path){	int credits = (path->p_tree_depth - subtree_depth) * 2 + 1 + op_credits;	if (handle->h_buffer_credits < credits)		return ocfs2_extend_trans(handle, credits);	return 0;}/* * Trap the case where we're inserting into the theoretical range past * the _actual_ left leaf range. Otherwise, we'll rotate a record * whose cpos is less than ours into the right leaf. * * It's only necessary to look at the rightmost record of the left * leaf because the logic that calls us should ensure that the * theoretical ranges in the path components above the leaves are * correct. */static int ocfs2_rotate_requires_path_adjustment(struct ocfs2_path *left_path,						 u32 insert_cpos){	struct ocfs2_extent_list *left_el;	struct ocfs2_extent_rec *rec;	int next_free;	left_el = path_leaf_el(left_path);	next_free = le16_to_cpu(left_el->l_next_free_rec);	rec = &left_el->l_recs[next_free - 1];	if (insert_cpos > le32_to_cpu(rec->e_cpos))		return 1;	return 0;}static int ocfs2_leftmost_rec_contains(struct ocfs2_extent_list *el, u32 cpos){	int next_free = le16_to_cpu(el->l_next_free_rec);	unsigned int range;	struct ocfs2_extent_rec *rec;	if (next_free == 0)		return 0;	rec = &el->l_recs[0];	if (ocfs2_is_empty_extent(rec)) {		/* Empty list. */		if (next_free == 1)			return 0;		rec = &el->l_recs[1];	}	range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);	if (cpos >= le32_to_cpu(rec->e_cpos) && cpos < range)		return 1;	return 0;}/* * Rotate all the records in a btree right one record, starting at insert_cpos. * * The path to the rightmost leaf should be passed in. * * The array is assumed to be large enough to hold an entire path (tree depth). * * Upon succesful return from this function: * * - The 'right_path' array will contain a path to the leaf block *   whose range contains e_cpos. * - That leaf block will have a single empty extent in list index 0. * - In the case that the rotation requires a post-insert update, *   *ret_left_path will contain a valid path which can be passed to *   ocfs2_insert_path(). */static int ocfs2_rotate_tree_right(struct inode *inode,				   handle_t *handle,				   enum ocfs2_split_type split,				   u32 insert_cpos,				   struct ocfs2_path *right_path,				   struct ocfs2_path **ret_left_path){	int ret, start, orig_credits = handle->h_buffer_credits;	u32 cpos;	struct ocfs2_path *left_path = NULL;	*ret_left_path = NULL;	left_path = ocfs2_new_path(path_root_bh(right_path),				   path_root_el(right_path));	if (!left_path) {		ret = -ENOMEM;		mlog_errno(ret);		goto out;	}	ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path, &cpos);	if (ret) {		mlog_errno(ret);		goto out;	}	mlog(0, "Insert: %u, first left path cpos: %u\n", insert_cpos, cpos);	/*	 * What we want to do here is:	 *	 * 1) Start with the rightmost path.	 *	 * 2) Determine a path to the leaf block directly to the left	 *    of that leaf.	 *	 * 3) Determine the 'subtree root' - the lowest level tree node	 *    which contains a path to both leaves.	 *	 * 4) Rotate the subtree.	 *	 * 5) Find the next subtree by considering the left path to be	 *    the new right path.	 *	 * The check at the top of this while loop also accepts	 * insert_cpos == cpos because cpos is only a _theoretical_	 * value to get us the left path - insert_cpos might very well	 * be filling that hole.	 *	 * Stop at a cpos of '0' because we either started at the	 * leftmost branch (i.e., a tree with one branch and a	 * rotation inside of it), or we've gone as far as we can in	 * rotating subtrees.	 */	while (cpos && insert_cpos <= cpos) {		mlog(0, "Rotating a tree: ins. cpos: %u, left path cpos: %u\n",		     insert_cpos, cpos);		ret = ocfs2_find_path(inode, left_path, cpos);		if (ret) {			mlog_errno(ret);			goto out;		}		mlog_bug_on_msg(path_leaf_bh(left_path) ==				path_leaf_bh(right_path),				"Inode %lu: error during insert of %u "				"(left path cpos %u) results in two identical "				"paths ending at %llu\n",				inode->i_ino, insert_cpos, cpos,				(unsigned long long)				path_leaf_bh(left_path)->b_blocknr);		if (split == SPLIT_NONE &&		    ocfs2_rotate_requires_path_adjustment(left_path,							  insert_cpos)) {			/*			 * We've rotated the tree as much as we			 * should. The rest is up to			 * ocfs2_insert_path() to complete, after the			 * record insertion. We indicate this			 * situation by returning the left path.			 *			 * The reason we don't adjust the records here			 * before the record insert is that an error			 * later might break the rule where a parent			 * record e_cpos will reflect the actual			 * e_cpos of the 1st nonempty record of the			 * child list.			 */			*ret_left_path = left_path;			goto out_ret_path;		}		start = ocfs2_find_subtree_root(inode, left_path, right_path);		mlog(0, "Subtree root at index %d (blk %llu, depth %d)\n",		     start,		     (unsigned long long) right_path->p_node[start].bh->b_blocknr,		     right_path->p_tree_depth);		ret = ocfs2_extend_rotate_transaction(handle, start,						      orig_credits, right_path);		if (ret) {			mlog_errno(ret);			goto out;		}		ret = ocfs2_rotate_subtree_right(inode, handle, left_path,						 right_path, start);		if (ret) {			mlog_errno(ret);			goto out;		}		if (split != SPLIT_NONE &&		    ocfs2_leftmost_rec_contains(path_leaf_el(right_path),						insert_cpos)) {			/*			 * A rotate moves the rightmost left leaf			 * record over to the leftmost right leaf			 * slot. If we're doing an extent split			 * instead of a real insert, then we have to			 * check that the extent to be split wasn't			 * just moved over. If it was, then we can			 * exit here, passing left_path back -			 * ocfs2_split_extent() is smart enough to			 * search both leaves.			 */			*ret_left_path = left_path;			goto out_ret_path;		}		/*		 * There is no need to re-read the next right path		 * as we know that it'll be our current left		 * path. Optimize by copying values instead.		 */		ocfs2_mv_path(right_path, left_path);		ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path,						    &cpos);		if (ret) {			mlog_errno(ret);			goto out;		}	}out:	ocfs2_free_path(left_path);out_ret_path:	return ret;}static void ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle,				      struct ocfs2_path *path){	int i, idx;	struct ocfs2_extent_rec *rec;	struct ocfs2_extent_list *el;	struct ocfs2_extent_block *eb;	u32 range;	/* Path should always be rightmost. */	eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data;	BUG_ON(eb->h_next_leaf_blk != 0ULL);	el = &eb->h_list;	BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0);	idx = le16_to_cpu(el->l_next_free_rec) - 1;	rec = &el->l_recs[idx];	range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);	for (i = 0; i < path->p_tree_depth; i++) {		el = path->p_node[i].el;		idx = le16_to_cpu(el->l_next_free_rec) - 1;		rec = &el->l_recs[idx];		rec->e_int_clusters = cpu_to_le32(range);		le32_add_cpu(&rec->e_int_clusters, -le32_to_cpu(rec->e_cpos));		ocfs2_journal_dirty(handle, path->p_node[i].bh);	}}static void ocfs2_unlink_path(struct inode *inode, handle_t *handle,			      struct ocfs2_cached_dealloc_ctxt *dealloc,			      struct ocfs2_path *path, int unlink_start){	int ret, i;	struct ocfs2_extent_block *eb;	struct ocfs2_extent_list *el;	struct buffer_head *bh;	for(i = unlink_start; i < path_num_items(path); i++) {		bh = path->p_node[i].bh;		eb = (struct ocfs2_extent_block *)bh->b_data;		/*		 * Not all nodes might have had their final count		 * decremented by the caller - handle this here.		 */		el = &eb->h_list;		if (le16_to_cpu(el->l_next_free_rec) > 1) {			mlog(ML_ERROR,			     "Inode %llu, attempted to remove extent block "			     "%llu with %u records\n",			     (unsigned long long)OCFS2_I(inode)->ip_blkno,			     (unsigned long long)le64_to_cpu(eb->h_blkno),			     le16_to_cpu(el->l_next_free_rec));			ocfs2_journal_dirty(handle, bh);			ocfs2_remove_from_cache(inode, bh);			continue;		}		el->l_next_free_rec = 0;		memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));		ocfs2_journal_dirty(handle, bh);

⌨️ 快捷键说明

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