Skip to content
Snippets Groups Projects
alloc.c 180 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	struct ocfs2_extent_list *right_el;
    	struct ocfs2_path *right_path = NULL;
    	int subtree_index = 0;
    	struct ocfs2_extent_list *el = path_leaf_el(left_path);
    	struct buffer_head *bh = path_leaf_bh(left_path);
    	struct buffer_head *root_bh = NULL;
    
    
    	BUG_ON(index >= le16_to_cpu(el->l_next_free_rec));
    	left_rec = &el->l_recs[index];
    
    Al Viro's avatar
    Al Viro committed
    	if (index == le16_to_cpu(el->l_next_free_rec) - 1 &&
    
    	    le16_to_cpu(el->l_next_free_rec) == le16_to_cpu(el->l_count)) {
    		/* we meet with a cross extent block merge. */
    		ret = ocfs2_get_right_path(inode, left_path, &right_path);
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    		right_el = path_leaf_el(right_path);
    		next_free = le16_to_cpu(right_el->l_next_free_rec);
    		BUG_ON(next_free <= 0);
    		right_rec = &right_el->l_recs[0];
    		if (ocfs2_is_empty_extent(right_rec)) {
    
    Al Viro's avatar
    Al Viro committed
    			BUG_ON(next_free <= 1);
    
    			right_rec = &right_el->l_recs[1];
    		}
    
    		BUG_ON(le32_to_cpu(left_rec->e_cpos) +
    		       le16_to_cpu(left_rec->e_leaf_clusters) !=
    		       le32_to_cpu(right_rec->e_cpos));
    
    		subtree_index = ocfs2_find_subtree_root(inode,
    							left_path, right_path);
    
    		ret = ocfs2_extend_rotate_transaction(handle, subtree_index,
    						      handle->h_buffer_credits,
    						      right_path);
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    		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;
    			}
    		}
    
    	} else {
    		BUG_ON(index == le16_to_cpu(el->l_next_free_rec) - 1);
    		right_rec = &el->l_recs[index + 1];
    	}
    
    
    	ret = ocfs2_journal_access(handle, inode, bh,
    				   OCFS2_JOURNAL_ACCESS_WRITE);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    	le16_add_cpu(&left_rec->e_leaf_clusters, -split_clusters);
    
    	le32_add_cpu(&right_rec->e_cpos, -split_clusters);
    	le64_add_cpu(&right_rec->e_blkno,
    		     -ocfs2_clusters_to_blocks(inode->i_sb, split_clusters));
    	le16_add_cpu(&right_rec->e_leaf_clusters, split_clusters);
    
    	ocfs2_cleanup_merge(el, index);
    
    	ret = ocfs2_journal_dirty(handle, bh);
    	if (ret)
    		mlog_errno(ret);
    
    
    	if (right_path) {
    		ret = ocfs2_journal_dirty(handle, path_leaf_bh(right_path));
    		if (ret)
    			mlog_errno(ret);
    
    		ocfs2_complete_edge_insert(inode, handle, left_path,
    					   right_path, subtree_index);
    	}
    out:
    	if (right_path)
    		ocfs2_free_path(right_path);
    	return ret;
    }
    
    static int ocfs2_get_left_path(struct inode *inode,
    			       struct ocfs2_path *right_path,
    			       struct ocfs2_path **ret_left_path)
    {
    	int ret;
    	u32 left_cpos;
    	struct ocfs2_path *left_path = NULL;
    
    	*ret_left_path = NULL;
    
    	/* This function shouldn't be called for non-trees. */
    	BUG_ON(right_path->p_tree_depth == 0);
    
    	ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb,
    					    right_path, &left_cpos);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    	/* This function shouldn't be called for the leftmost leaf. */
    	BUG_ON(left_cpos == 0);
    
    	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_path(inode, left_path, left_cpos);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    	*ret_left_path = left_path;
    
    	if (ret)
    		ocfs2_free_path(left_path);
    
    	return ret;
    }
    
    /*
     * Remove split_rec clusters from the record at index and merge them
    
     * onto the tail of the record "before" it.
     * For index > 0, the "before" means the extent rec at index - 1.
     *
     * For index == 0, the "before" means the last record of the previous
     * extent block. And there is also a situation that we may need to
     * remove the rightmost leaf extent block in the right_path and change
     * the right path to indicate the new rightmost path.
    
    static int ocfs2_merge_rec_left(struct inode *inode,
    				struct ocfs2_path *right_path,
    
    				handle_t *handle,
    				struct ocfs2_extent_rec *split_rec,
    
    				struct ocfs2_cached_dealloc_ctxt *dealloc,
    
    				struct ocfs2_extent_tree *et,
    
    				int index)
    
    	int ret, i, subtree_index = 0, has_empty_extent = 0;
    
    	unsigned int split_clusters = le16_to_cpu(split_rec->e_leaf_clusters);
    	struct ocfs2_extent_rec *left_rec;
    	struct ocfs2_extent_rec *right_rec;
    
    	struct ocfs2_extent_list *el = path_leaf_el(right_path);
    	struct buffer_head *bh = path_leaf_bh(right_path);
    	struct buffer_head *root_bh = NULL;
    	struct ocfs2_path *left_path = NULL;
    	struct ocfs2_extent_list *left_el;
    
    	BUG_ON(index < 0);
    
    
    	right_rec = &el->l_recs[index];
    
    	if (index == 0) {
    		/* we meet with a cross extent block merge. */
    		ret = ocfs2_get_left_path(inode, right_path, &left_path);
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    		left_el = path_leaf_el(left_path);
    		BUG_ON(le16_to_cpu(left_el->l_next_free_rec) !=
    		       le16_to_cpu(left_el->l_count));
    
    		left_rec = &left_el->l_recs[
    				le16_to_cpu(left_el->l_next_free_rec) - 1];
    		BUG_ON(le32_to_cpu(left_rec->e_cpos) +
    		       le16_to_cpu(left_rec->e_leaf_clusters) !=
    		       le32_to_cpu(split_rec->e_cpos));
    
    		subtree_index = ocfs2_find_subtree_root(inode,
    							left_path, right_path);
    
    		ret = ocfs2_extend_rotate_transaction(handle, subtree_index,
    						      handle->h_buffer_credits,
    						      left_path);
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    		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;
    			}
    		}
    	} else {
    		left_rec = &el->l_recs[index - 1];
    		if (ocfs2_is_empty_extent(&el->l_recs[0]))
    			has_empty_extent = 1;
    	}
    
    
    	ret = ocfs2_journal_access(handle, inode, bh,
    				   OCFS2_JOURNAL_ACCESS_WRITE);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    	if (has_empty_extent && index == 1) {
    		/*
    		 * The easy case - we can just plop the record right in.
    		 */
    		*left_rec = *split_rec;
    
    		has_empty_extent = 0;
    
    		le16_add_cpu(&left_rec->e_leaf_clusters, split_clusters);
    
    	le32_add_cpu(&right_rec->e_cpos, split_clusters);
    	le64_add_cpu(&right_rec->e_blkno,
    		     ocfs2_clusters_to_blocks(inode->i_sb, split_clusters));
    	le16_add_cpu(&right_rec->e_leaf_clusters, -split_clusters);
    
    	ocfs2_cleanup_merge(el, index);
    
    	ret = ocfs2_journal_dirty(handle, bh);
    	if (ret)
    		mlog_errno(ret);
    
    
    	if (left_path) {
    		ret = ocfs2_journal_dirty(handle, path_leaf_bh(left_path));
    		if (ret)
    			mlog_errno(ret);
    
    		/*
    		 * In the situation that the right_rec is empty and the extent
    		 * block is empty also,  ocfs2_complete_edge_insert can't handle
    		 * it and we need to delete the right extent block.
    		 */
    		if (le16_to_cpu(right_rec->e_leaf_clusters) == 0 &&
    		    le16_to_cpu(el->l_next_free_rec) == 1) {
    
    			ret = ocfs2_remove_rightmost_path(inode, handle,
    
    							  right_path,
    							  dealloc, et);
    
    			if (ret) {
    				mlog_errno(ret);
    				goto out;
    			}
    
    			/* Now the rightmost extent block has been deleted.
    			 * So we use the new rightmost path.
    			 */
    			ocfs2_mv_path(right_path, left_path);
    			left_path = NULL;
    		} else
    			ocfs2_complete_edge_insert(inode, handle, left_path,
    						   right_path, subtree_index);
    	}
    
    	if (left_path)
    		ocfs2_free_path(left_path);
    
    	return ret;
    }
    
    static int ocfs2_try_to_merge_extent(struct inode *inode,
    				     handle_t *handle,
    
    				     struct ocfs2_path *path,
    
    				     int split_index,
    				     struct ocfs2_extent_rec *split_rec,
    				     struct ocfs2_cached_dealloc_ctxt *dealloc,
    
    				     struct ocfs2_merge_ctxt *ctxt,
    				     struct ocfs2_extent_tree *et)
    
    Tao Mao's avatar
    Tao Mao committed
    	int ret = 0;
    
    	struct ocfs2_extent_list *el = path_leaf_el(path);
    
    	struct ocfs2_extent_rec *rec = &el->l_recs[split_index];
    
    	BUG_ON(ctxt->c_contig_type == CONTIG_NONE);
    
    
    Tao Mao's avatar
    Tao Mao committed
    	if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) {
    		/*
    		 * The merge code will need to create an empty
    		 * extent to take the place of the newly
    		 * emptied slot. Remove any pre-existing empty
    		 * extents - having more than one in a leaf is
    		 * illegal.
    		 */
    
    		ret = ocfs2_rotate_tree_left(inode, handle, path,
    
    Tao Mao's avatar
    Tao Mao committed
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    
    Tao Mao's avatar
    Tao Mao committed
    		split_index--;
    		rec = &el->l_recs[split_index];
    
    	}
    
    	if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) {
    		/*
    		 * Left-right contig implies this.
    		 */
    		BUG_ON(!ctxt->c_split_covers_rec);
    
    		/*
    		 * Since the leftright insert always covers the entire
    		 * extent, this call will delete the insert record
    		 * entirely, resulting in an empty extent record added to
    		 * the extent block.
    		 *
    		 * Since the adding of an empty extent shifts
    		 * everything back to the right, there's no need to
    		 * update split_index here.
    
    		 *
    		 * When the split_index is zero, we need to merge it to the
    		 * prevoius extent block. It is more efficient and easier
    		 * if we do merge_right first and merge_left later.
    
    		ret = ocfs2_merge_rec_right(inode, path,
    					    handle, split_rec,
    					    split_index);
    
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    		/*
    		 * We can only get this from logic error above.
    		 */
    		BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
    
    
    		/* The merge left us with an empty extent, remove it. */
    
    		ret = ocfs2_rotate_tree_left(inode, handle, path,
    					     dealloc, et);
    
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    		rec = &el->l_recs[split_index];
    
    		/*
    		 * Note that we don't pass split_rec here on purpose -
    
    		 * we've merged it into the rec already.
    
    		ret = ocfs2_merge_rec_left(inode, path,
    					   handle, rec,
    
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    
    		ret = ocfs2_rotate_tree_left(inode, handle, path,
    
    		/*
    		 * Error from this last rotate is not critical, so
    		 * print but don't bubble it up.
    		 */
    		if (ret)
    			mlog_errno(ret);
    		ret = 0;
    	} else {
    		/*
    		 * Merge a record to the left or right.
    		 *
    		 * 'contig_type' is relative to the existing record,
    		 * so for example, if we're "right contig", it's to
    		 * the record on the left (hence the left merge).
    		 */
    		if (ctxt->c_contig_type == CONTIG_RIGHT) {
    			ret = ocfs2_merge_rec_left(inode,
    
    						   path,
    						   handle, split_rec,
    
    						   split_index);
    			if (ret) {
    				mlog_errno(ret);
    				goto out;
    			}
    		} else {
    			ret = ocfs2_merge_rec_right(inode,
    
    						    path,
    						    handle, split_rec,
    
    						    split_index);
    			if (ret) {
    				mlog_errno(ret);
    				goto out;
    			}
    		}
    
    		if (ctxt->c_split_covers_rec) {
    			/*
    			 * The merge may have left an empty extent in
    			 * our leaf. Try to rotate it away.
    			 */
    
    			ret = ocfs2_rotate_tree_left(inode, handle, path,
    
    			if (ret)
    				mlog_errno(ret);
    			ret = 0;
    		}
    	}
    
    out:
    	return ret;
    }
    
    static void ocfs2_subtract_from_rec(struct super_block *sb,
    				    enum ocfs2_split_type split,
    				    struct ocfs2_extent_rec *rec,
    				    struct ocfs2_extent_rec *split_rec)
    {
    	u64 len_blocks;
    
    	len_blocks = ocfs2_clusters_to_blocks(sb,
    				le16_to_cpu(split_rec->e_leaf_clusters));
    
    	if (split == SPLIT_LEFT) {
    		/*
    		 * Region is on the left edge of the existing
    		 * record.
    		 */
    		le32_add_cpu(&rec->e_cpos,
    			     le16_to_cpu(split_rec->e_leaf_clusters));
    		le64_add_cpu(&rec->e_blkno, len_blocks);
    		le16_add_cpu(&rec->e_leaf_clusters,
    			     -le16_to_cpu(split_rec->e_leaf_clusters));
    	} else {
    		/*
    		 * Region is on the right edge of the existing
    		 * record.
    		 */
    		le16_add_cpu(&rec->e_leaf_clusters,
    			     -le16_to_cpu(split_rec->e_leaf_clusters));
    	}
    }
    
    /*
     * Do the final bits of extent record insertion at the target leaf
     * list. If this leaf is part of an allocation tree, it is assumed
     * that the tree above has been prepared.
     */
    static void ocfs2_insert_at_leaf(struct ocfs2_extent_rec *insert_rec,
    				 struct ocfs2_extent_list *el,
    				 struct ocfs2_insert_type *insert,
    				 struct inode *inode)
    {
    	int i = insert->ins_contig_index;
    	unsigned int range;
    	struct ocfs2_extent_rec *rec;
    
    	BUG_ON(le16_to_cpu(el->l_tree_depth) != 0);
    
    	if (insert->ins_split != SPLIT_NONE) {
    		i = ocfs2_search_extent_list(el, le32_to_cpu(insert_rec->e_cpos));
    		BUG_ON(i == -1);
    		rec = &el->l_recs[i];
    		ocfs2_subtract_from_rec(inode->i_sb, insert->ins_split, rec,
    					insert_rec);
    		goto rotate;
    	}
    
    	/*
    	 * Contiguous insert - either left or right.
    	 */
    	if (insert->ins_contig != CONTIG_NONE) {
    		rec = &el->l_recs[i];
    		if (insert->ins_contig == CONTIG_LEFT) {
    			rec->e_blkno = insert_rec->e_blkno;
    			rec->e_cpos = insert_rec->e_cpos;
    		}
    		le16_add_cpu(&rec->e_leaf_clusters,
    			     le16_to_cpu(insert_rec->e_leaf_clusters));
    		return;
    	}
    
    	/*
    	 * Handle insert into an empty leaf.
    	 */
    	if (le16_to_cpu(el->l_next_free_rec) == 0 ||
    	    ((le16_to_cpu(el->l_next_free_rec) == 1) &&
    	     ocfs2_is_empty_extent(&el->l_recs[0]))) {
    		el->l_recs[0] = *insert_rec;
    		el->l_next_free_rec = cpu_to_le16(1);
    		return;
    	}
    
    	/*
    	 * Appending insert.
    	 */
    	if (insert->ins_appending == APPEND_TAIL) {
    		i = le16_to_cpu(el->l_next_free_rec) - 1;
    		rec = &el->l_recs[i];
    		range = le32_to_cpu(rec->e_cpos)
    			+ le16_to_cpu(rec->e_leaf_clusters);
    		BUG_ON(le32_to_cpu(insert_rec->e_cpos) < range);
    
    		mlog_bug_on_msg(le16_to_cpu(el->l_next_free_rec) >=
    				le16_to_cpu(el->l_count),
    				"inode %lu, depth %u, count %u, next free %u, "
    				"rec.cpos %u, rec.clusters %u, "
    				"insert.cpos %u, insert.clusters %u\n",
    				inode->i_ino,
    				le16_to_cpu(el->l_tree_depth),
    				le16_to_cpu(el->l_count),
    				le16_to_cpu(el->l_next_free_rec),
    				le32_to_cpu(el->l_recs[i].e_cpos),
    				le16_to_cpu(el->l_recs[i].e_leaf_clusters),
    				le32_to_cpu(insert_rec->e_cpos),
    				le16_to_cpu(insert_rec->e_leaf_clusters));
    		i++;
    		el->l_recs[i] = *insert_rec;
    		le16_add_cpu(&el->l_next_free_rec, 1);
    		return;
    	}
    
    rotate:
    	/*
    	 * Ok, we have to rotate.
    	 *
    	 * At this point, it is safe to assume that inserting into an
    	 * empty leaf and appending to a leaf have both been handled
    	 * above.
    	 *
    	 * This leaf needs to have space, either by the empty 1st
    	 * extent record, or by virtue of an l_next_rec < l_count.
    	 */
    	ocfs2_rotate_leaf(el, insert_rec);
    }
    
    static void ocfs2_adjust_rightmost_records(struct inode *inode,
    					   handle_t *handle,
    					   struct ocfs2_path *path,
    					   struct ocfs2_extent_rec *insert_rec)
    {
    	int ret, i, next_free;
    	struct buffer_head *bh;
    	struct ocfs2_extent_list *el;
    	struct ocfs2_extent_rec *rec;
    
    	/*
    	 * Update everything except the leaf block.
    	 */
    	for (i = 0; i < path->p_tree_depth; i++) {
    		bh = path->p_node[i].bh;
    		el = path->p_node[i].el;
    
    
    		next_free = le16_to_cpu(el->l_next_free_rec);
    		if (next_free == 0) {
    			ocfs2_error(inode->i_sb,
    				    "Dinode %llu has a bad extent list",
    				    (unsigned long long)OCFS2_I(inode)->ip_blkno);
    			ret = -EIO;
    
    			return;
    		}
    
    		rec = &el->l_recs[next_free - 1];
    
    		rec->e_int_clusters = insert_rec->e_cpos;
    		le32_add_cpu(&rec->e_int_clusters,
    			     le16_to_cpu(insert_rec->e_leaf_clusters));
    		le32_add_cpu(&rec->e_int_clusters,
    			     -le32_to_cpu(rec->e_cpos));
    
    		ret = ocfs2_journal_dirty(handle, bh);
    		if (ret)
    			mlog_errno(ret);
    
    	}
    }
    
    static int ocfs2_append_rec_to_path(struct inode *inode, handle_t *handle,
    				    struct ocfs2_extent_rec *insert_rec,
    				    struct ocfs2_path *right_path,
    				    struct ocfs2_path **ret_left_path)
    {
    	int ret, next_free;
    	struct ocfs2_extent_list *el;
    	struct ocfs2_path *left_path = NULL;
    
    	*ret_left_path = NULL;
    
    	/*
    	 * This shouldn't happen for non-trees. The extent rec cluster
    	 * count manipulation below only works for interior nodes.
    	 */
    	BUG_ON(right_path->p_tree_depth == 0);
    
    	/*
    	 * If our appending insert is at the leftmost edge of a leaf,
    	 * then we might need to update the rightmost records of the
    	 * neighboring path.
    	 */
    	el = path_leaf_el(right_path);
    	next_free = le16_to_cpu(el->l_next_free_rec);
    	if (next_free == 0 ||
    	    (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) {
    		u32 left_cpos;
    
    		ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path,
    						    &left_cpos);
    		if (ret) {
    			mlog_errno(ret);
    
    		mlog(0, "Append may need a left path update. cpos: %u, "
    		     "left_cpos: %u\n", le32_to_cpu(insert_rec->e_cpos),
    		     left_cpos);
    
    		/*
    		 * No need to worry if the append is already in the
    		 * leftmost leaf.
    		 */
    		if (left_cpos) {
    			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_path(inode, left_path, left_cpos);
    			if (ret) {
    				mlog_errno(ret);
    				goto out;
    			}
    
    			/*
    			 * ocfs2_insert_path() will pass the left_path to the
    			 * journal for us.
    			 */
    		}
    	}
    
    	ret = ocfs2_journal_access_path(inode, handle, right_path);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    
    	ocfs2_adjust_rightmost_records(inode, handle, right_path, insert_rec);
    
    
    	*ret_left_path = left_path;
    	ret = 0;
    out:
    	if (ret != 0)
    		ocfs2_free_path(left_path);
    
    	return ret;
    }
    
    
    static void ocfs2_split_record(struct inode *inode,
    			       struct ocfs2_path *left_path,
    			       struct ocfs2_path *right_path,
    			       struct ocfs2_extent_rec *split_rec,
    			       enum ocfs2_split_type split)
    {
    	int index;
    	u32 cpos = le32_to_cpu(split_rec->e_cpos);
    	struct ocfs2_extent_list *left_el = NULL, *right_el, *insert_el, *el;
    	struct ocfs2_extent_rec *rec, *tmprec;
    
    	right_el = path_leaf_el(right_path);;
    	if (left_path)
    		left_el = path_leaf_el(left_path);
    
    	el = right_el;
    	insert_el = right_el;
    	index = ocfs2_search_extent_list(el, cpos);
    	if (index != -1) {
    		if (index == 0 && left_path) {
    			BUG_ON(ocfs2_is_empty_extent(&el->l_recs[0]));
    
    			/*
    			 * This typically means that the record
    			 * started in the left path but moved to the
    			 * right as a result of rotation. We either
    			 * move the existing record to the left, or we
    			 * do the later insert there.
    			 *
    			 * In this case, the left path should always
    			 * exist as the rotate code will have passed
    			 * it back for a post-insert update.
    			 */
    
    			if (split == SPLIT_LEFT) {
    				/*
    				 * It's a left split. Since we know
    				 * that the rotate code gave us an
    				 * empty extent in the left path, we
    				 * can just do the insert there.
    				 */
    				insert_el = left_el;
    			} else {
    				/*
    				 * Right split - we have to move the
    				 * existing record over to the left
    				 * leaf. The insert will be into the
    				 * newly created empty extent in the
    				 * right leaf.
    				 */
    				tmprec = &right_el->l_recs[index];
    				ocfs2_rotate_leaf(left_el, tmprec);
    				el = left_el;
    
    				memset(tmprec, 0, sizeof(*tmprec));
    				index = ocfs2_search_extent_list(left_el, cpos);
    				BUG_ON(index == -1);
    			}
    		}
    	} else {
    		BUG_ON(!left_path);
    		BUG_ON(!ocfs2_is_empty_extent(&left_el->l_recs[0]));
    		/*
    		 * Left path is easy - we can just allow the insert to
    		 * happen.
    		 */
    		el = left_el;
    		insert_el = left_el;
    		index = ocfs2_search_extent_list(el, cpos);
    		BUG_ON(index == -1);
    	}
    
    	rec = &el->l_recs[index];
    	ocfs2_subtract_from_rec(inode->i_sb, split, rec, split_rec);
    	ocfs2_rotate_leaf(insert_el, split_rec);
    }
    
    
     * This function only does inserts on an allocation b-tree. For tree
     * depth = 0, ocfs2_insert_at_leaf() is called directly.
    
     *
     * right_path is the path we want to do the actual insert
     * in. left_path should only be passed in if we need to update that
     * portion of the tree after an edge insert.
     */
    static int ocfs2_insert_path(struct inode *inode,
    			     handle_t *handle,
    			     struct ocfs2_path *left_path,
    			     struct ocfs2_path *right_path,
    			     struct ocfs2_extent_rec *insert_rec,
    			     struct ocfs2_insert_type *insert)
    {
    	int ret, subtree_index;
    	struct buffer_head *leaf_bh = path_leaf_bh(right_path);
    
    	if (left_path) {
    		int credits = handle->h_buffer_credits;
    
    		/*
    		 * There's a chance that left_path got passed back to
    		 * us without being accounted for in the
    		 * journal. Extend our transaction here to be sure we
    		 * can change those blocks.
    		 */
    		credits += left_path->p_tree_depth;
    
    		ret = ocfs2_extend_trans(handle, credits);
    		if (ret < 0) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    		ret = ocfs2_journal_access_path(inode, handle, left_path);
    		if (ret < 0) {
    			mlog_errno(ret);
    			goto out;
    		}
    	}
    
    
    	/*
    	 * Pass both paths to the journal. The majority of inserts
    	 * will be touching all components anyway.
    	 */
    	ret = ocfs2_journal_access_path(inode, handle, right_path);
    	if (ret < 0) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    
    	if (insert->ins_split != SPLIT_NONE) {
    		/*
    		 * We could call ocfs2_insert_at_leaf() for some types
    
    Joe Perches's avatar
    Joe Perches committed
    		 * of splits, but it's easier to just let one separate
    
    		 * function sort it all out.
    		 */
    		ocfs2_split_record(inode, left_path, right_path,
    				   insert_rec, insert->ins_split);
    
    
    		/*
    		 * Split might have modified either leaf and we don't
    		 * have a guarantee that the later edge insert will
    		 * dirty this for us.
    		 */
    		if (left_path)
    			ret = ocfs2_journal_dirty(handle,
    						  path_leaf_bh(left_path));
    			if (ret)
    				mlog_errno(ret);
    
    	} else
    		ocfs2_insert_at_leaf(insert_rec, path_leaf_el(right_path),
    				     insert, inode);
    
    
    	ret = ocfs2_journal_dirty(handle, leaf_bh);
    	if (ret)
    		mlog_errno(ret);
    
    	if (left_path) {
    		/*
    		 * The rotate code has indicated that we need to fix
    		 * up portions of the tree after the insert.
    		 *
    		 * XXX: Should we extend the transaction here?
    		 */
    		subtree_index = ocfs2_find_subtree_root(inode, left_path,
    							right_path);
    		ocfs2_complete_edge_insert(inode, handle, left_path,
    					   right_path, subtree_index);
    	}
    
    	ret = 0;
    out:
    	return ret;
    }
    
    static int ocfs2_do_insert_extent(struct inode *inode,
    				  handle_t *handle,
    
    				  struct ocfs2_extent_tree *et,
    
    				  struct ocfs2_extent_rec *insert_rec,
    				  struct ocfs2_insert_type *type)
    {
    	int ret, rotate = 0;
    	u32 cpos;
    	struct ocfs2_path *right_path = NULL;
    	struct ocfs2_path *left_path = NULL;
    	struct ocfs2_extent_list *el;
    
    
    	el = et->et_root_el;
    
    	ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
    
    				   OCFS2_JOURNAL_ACCESS_WRITE);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    	if (le16_to_cpu(el->l_tree_depth) == 0) {
    		ocfs2_insert_at_leaf(insert_rec, el, type, inode);
    		goto out_update_clusters;
    	}
    
    
    	right_path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
    
    	if (!right_path) {
    		ret = -ENOMEM;
    		mlog_errno(ret);
    		goto out;
    	}
    
    	/*
    	 * Determine the path to start with. Rotations need the
    	 * rightmost path, everything else can go directly to the
    	 * target leaf.
    	 */
    	cpos = le32_to_cpu(insert_rec->e_cpos);
    	if (type->ins_appending == APPEND_NONE &&
    	    type->ins_contig == CONTIG_NONE) {
    		rotate = 1;
    		cpos = UINT_MAX;
    	}
    
    	ret = ocfs2_find_path(inode, right_path, cpos);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    	/*
    	 * Rotations and appends need special treatment - they modify
    	 * parts of the tree's above them.
    	 *
    	 * Both might pass back a path immediate to the left of the
    	 * one being inserted to. This will be cause
    	 * ocfs2_insert_path() to modify the rightmost records of
    	 * left_path to account for an edge insert.
    	 *
    	 * XXX: When modifying this code, keep in mind that an insert
    	 * can wind up skipping both of these two special cases...
    	 */
    	if (rotate) {
    
    		ret = ocfs2_rotate_tree_right(inode, handle, type->ins_split,
    
    					      le32_to_cpu(insert_rec->e_cpos),
    					      right_path, &left_path);
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    
    		/*
    		 * ocfs2_rotate_tree_right() might have extended the
    		 * transaction without re-journaling our tree root.
    		 */
    
    		ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
    
    					   OCFS2_JOURNAL_ACCESS_WRITE);
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    
    	} else if (type->ins_appending == APPEND_TAIL
    		   && type->ins_contig != CONTIG_LEFT) {
    		ret = ocfs2_append_rec_to_path(inode, handle, insert_rec,
    					       right_path, &left_path);
    		if (ret) {
    			mlog_errno(ret);
    			goto out;
    		}
    	}
    
    	ret = ocfs2_insert_path(inode, handle, left_path, right_path,
    				insert_rec, type);
    	if (ret) {
    		mlog_errno(ret);
    		goto out;
    	}
    
    out_update_clusters:
    
    	if (type->ins_split == SPLIT_NONE)
    
    		ocfs2_et_update_clusters(inode, et,
    					 le16_to_cpu(insert_rec->e_leaf_clusters));
    
    	ret = ocfs2_journal_dirty(handle, et->et_root_bh);
    
    	if (ret)
    		mlog_errno(ret);
    
    out:
    	ocfs2_free_path(left_path);
    	ocfs2_free_path(right_path);
    
    	return ret;
    }
    
    
    static enum ocfs2_contig_type
    
    ocfs2_figure_merge_contig_type(struct inode *inode, struct ocfs2_path *path,
    
    			       struct ocfs2_extent_list *el, int index,
    			       struct ocfs2_extent_rec *split_rec)
    {
    
    	int status;