[Ocfs2-tools-commits] taoma commits r1326 - branches/sparse-files/libocfs2

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Sun Mar 25 23:01:18 PDT 2007


Author: taoma
Date: 2007-03-25 23:01:15 -0700 (Sun, 25 Mar 2007)
New Revision: 1326

Modified:
   branches/sparse-files/libocfs2/extend_file.c
Log:
Update the extent insert mechanism with Mark's new kernel code for sparse file.

This new mechanism's corresponding ocfs2 kernel code is sparse file branch with
the last commit hash 8d7c92bebcd01b2a95c4c3b331cd2c9c86755e82.
The date is Mar 22 2007.

Modified: branches/sparse-files/libocfs2/extend_file.c
===================================================================
--- branches/sparse-files/libocfs2/extend_file.c	2007-03-24 01:37:19 UTC (rev 1325)
+++ branches/sparse-files/libocfs2/extend_file.c	2007-03-26 06:01:15 UTC (rev 1326)
@@ -141,14 +141,15 @@
 /*
  * Insert an extent block at given index.
  *
- * This will not take an additional reference on eb_bh.
+ * Note:
+ * This buf will be inserted into the path, so the caller shouldn't free it.
  */
 static inline void ocfs2_path_insert_eb(struct ocfs2_path *path, int index,
 					char *buf)
 {
 	struct ocfs2_extent_block *eb = (struct ocfs2_extent_block *) buf;
 	/*
-	 * Right now, no root bh is an extent block, so this helps
+	 * Right now, no root buf is an extent block, so this helps
 	 * catch code errors with dinode trees. The assertion can be
 	 * safely removed if we ever need to insert extent block
 	 * structures at the root.
@@ -262,6 +263,10 @@
 	CONTIG_RIGHT
 };
 
+/*
+ * NOTE: ocfs2_block_extent_contig(), ocfs2_extents_adjacent() and
+ * ocfs2_extent_contig only work properly against leaf nodes!
+ */
 static inline int ocfs2_block_extent_contig(ocfs2_filesys *fs,
 					    struct ocfs2_extent_rec *ext,
 					    uint64_t blkno)
@@ -348,7 +353,7 @@
  * 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
+ * last_eb_buf 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
@@ -438,7 +443,13 @@
 		 */
 		eb_el->l_recs[0].e_cpos = new_cpos;
 		eb_el->l_recs[0].e_blkno = 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 = 0;
+
 		if (!eb_el->l_tree_depth)
 			new_last_eb_blk = eb->h_blkno;
 
@@ -510,10 +521,10 @@
  * valid results of this search:
  *
  * 1) a lowest extent block is found, then we pass it back in
- *    *lowest_eb_bh and return '0'
+ *    *target_buf 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'
+ *    pass NULL back in *target_buf, but still return '0'
  *
  * 3) the search fails to find anything AND the dinode is full, in
  *    which case we return > 0
@@ -689,6 +700,8 @@
 {
 	int next_free = el->l_next_free_rec;
 
+	assert(el->l_tree_depth == 0);
+
 	if (next_free == 0)
 		goto set_and_inc;
 
@@ -726,7 +739,17 @@
 		i++;
 
 		/* The caller didn't pass two adjacent paths. */
-		assert(i <= left->p_tree_depth);
+ 		if (i > left->p_tree_depth) {
+ 			fprintf(stderr,
+ 				"Inode %"PRIu64", "
+ 				"left depth %u, right depth %u\n"
+ 				"left leaf blk %"PRIu64", "
+ 				"right leaf blk %"PRIu64"\n",
+ 				path_root_blkno(right),
+ 				left->p_tree_depth, right->p_tree_depth,
+ 				path_leaf_blkno(left), path_leaf_blkno(right));
+			assert(0);
+		}
 	} while (left->p_node[i].blkno == right->p_node[i].blkno);
 
 	return i - 1;
@@ -756,6 +779,16 @@
 
 	el = root_el;
 	while (el->l_tree_depth) {
+		if (el->l_next_free_rec == 0) {
+			fprintf(stderr,
+				"Inode has empty extent list at depth %u\n",
+				el->l_tree_depth);
+			ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK;
+			goto out;
+
+		}
+
+
 		for(i = 0; i < el->l_next_free_rec - 1; i++) {
 			rec = &el->l_recs[i];
 
@@ -764,13 +797,21 @@
 			 * tree, this should just wind up returning the
 			 * rightmost record.
 			 */
-			range = rec->e_cpos + rec->e_int_clusters;
+			range = rec->e_cpos +
+				ocfs2_rec_clusters(el->l_tree_depth, rec);
 			if (cpos >= rec->e_cpos && cpos < range)
 			    break;
 		}
 
 		blkno = el->l_recs[i].e_blkno;
-		assert(blkno);
+		if (blkno == 0) {
+			fprintf(stderr,
+				"Inode has bad blkno in extent list "
+				"at depth %u (index %d)\n",
+				el->l_tree_depth, i);
+			ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK;
+			goto out;
+		}
 
 		ret = ocfs2_malloc_block(fs->fs_io, &buf);
 		if (ret)
@@ -783,6 +824,15 @@
 		eb = (struct ocfs2_extent_block *) buf;
 		el = &eb->h_list;
 
+		if (el->l_next_free_rec > el->l_count) {
+			fprintf(stderr,
+				"Inode has bad count in extent list at "
+				"block %"PRIu64" (next free=%u, count=%u)\n",
+				blkno, el->l_next_free_rec, el->l_count);
+			ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK;
+			goto out;
+		}
+
 		if (func)
 			func(data, buf);
 		buf = NULL;
@@ -948,15 +998,17 @@
  * We've changed a leaf block (in right_path) and need to reflect that
  * change back up the subtree.
  *
- * This happens in two places:
+ * This happens in multiple places:
  *   - When we've moved an extent record from the left path leaf to the right
  *     path leaf to make room for an empty extent in the left path leaf.
- *   - When we've inserted a new record into the right path leaf.
+ *   - When our insert into the right path leaf is at the leftmost edge
+ *     and requires an update of the path immediately to it's left. This
+ *     can occur at the end of some types of rotation and appending inserts.
  */
-static void ocfs2_complete_rotation(ocfs2_filesys *fs,
-				    struct ocfs2_path *left_path,
-				    struct ocfs2_path *right_path,
-				    int subtree_index)
+static void ocfs2_complete_edge_insert(ocfs2_filesys *fs,
+				       struct ocfs2_path *left_path,
+				       struct ocfs2_path *right_path,
+				       int subtree_index)
 {
 	int i, idx;
 	uint64_t blkno;
@@ -1085,7 +1137,7 @@
 	memset(&left_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
 	left_el->l_next_free_rec += 1;
 
-	ocfs2_complete_rotation(fs, left_path, right_path, subtree_index);
+	ocfs2_complete_edge_insert(fs, left_path, right_path, subtree_index);
 
 	ret = ocfs2_sync_path_to_disk(fs, left_path, right_path, subtree_index);
 
@@ -1105,6 +1157,8 @@
 	uint64_t blkno;
 	struct ocfs2_extent_list *el;
 
+	assert(path->p_tree_depth > 0);
+
 	*cpos = 0;
 
 	blkno = path_leaf_blkno(path);
@@ -1205,8 +1259,8 @@
  */
 static int ocfs2_rotate_tree_right(ocfs2_filesys *fs,
 				   uint32_t insert_cpos,
-				   struct ocfs2_path **ret_left_path,
-				   struct ocfs2_path *right_path)
+				   struct ocfs2_path *right_path,
+				   struct ocfs2_path **ret_left_path)
 {
 	int ret, start;
 	uint32_t cpos;
@@ -1214,10 +1268,6 @@
 
 	*ret_left_path = NULL;
 
-	ret = ocfs2_find_cpos_for_left_leaf(right_path, &cpos);
-	if (ret)
-		goto out;
-
 	left_path = ocfs2_new_path(fs, path_root_buf(right_path),
 				   path_root_el(right_path));
 	if (!left_path) {
@@ -1225,6 +1275,10 @@
 		goto out;
 	}
 
+	ret = ocfs2_find_cpos_for_left_leaf(right_path, &cpos);
+	if (ret)
+		goto out;
+
 	/*
 	 * What we want to do here is:
 	 *
@@ -1240,15 +1294,33 @@
 	 *
 	 * 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 (insert_cpos <= cpos) {
-		start = 0;
+	while (cpos && insert_cpos <= cpos) {
 
 		ret = ocfs2_find_path(fs, left_path, cpos);
 		if (ret)
 			goto out;
 
-		start = ocfs2_find_subtree_root(left_path, right_path);
+		if (path_leaf_blkno(left_path) == path_leaf_blkno(right_path)) {
+			fprintf(stderr, "Inode %"PRIu64": "
+				"error during insert of %u "
+				"(left path cpos %u) results in two identical "
+				"paths ending at %"PRIu64"\n",
+				path_root_blkno(left_path),
+				insert_cpos, cpos,
+				path_leaf_blkno(left_path));
+			assert(0);
+		}
 
 		if (ocfs2_rotate_requires_path_adjustment(left_path,
 							  insert_cpos)) {
@@ -1270,6 +1342,8 @@
 			goto out_ret_path;
 		}
 
+		start = ocfs2_find_subtree_root(left_path, right_path);
+
 		ret = ocfs2_rotate_subtree_right(fs, left_path, right_path,
 						 start);
 		if (ret)
@@ -1299,7 +1373,7 @@
  * copying all extent records from the dinode into the extent block,
  * and then pointing the dinode to the new extent_block.
  */
-static errcode_t shift_tree_depth(struct insert_ctxt *ctxt, char **last_eb)
+static errcode_t shift_tree_depth(struct insert_ctxt *ctxt, char **new_eb)
 {
 	errcode_t ret;
 	char *buf = NULL;
@@ -1345,9 +1419,9 @@
 
 	ret = ocfs2_write_extent_block(ctxt->fs, blkno, buf);
 	if (!ret)
-		*last_eb = buf;
+		*new_eb = buf;
 out:
-	if (buf && !*last_eb)
+	if (buf && !*new_eb)
 		ocfs2_free(&buf);
 
 	return ret;
@@ -1361,6 +1435,8 @@
 	int i;
 	enum ocfs2_contig_type contig_type = CONTIG_NONE;
 
+	assert(el->l_tree_depth == 0);
+
 	for(i = 0; i < el->l_next_free_rec; i++) {
 		contig_type = ocfs2_extent_contig(fs, &el->l_recs[i],
 						  insert_rec);
@@ -1392,7 +1468,7 @@
 
 	insert->ins_appending = APPEND_NONE;
 
-	assert(!el->l_tree_depth);
+	assert(el->l_tree_depth == 0);
 
 	if (!el->l_next_free_rec)
 		goto set_tail_append;
@@ -1507,6 +1583,19 @@
 	ocfs2_figure_contig_type(fs, insert, el, insert_rec);
 
 	/*
+	 * The insert code isn't quite ready to deal with all cases of
+	 * left contiguousness. Specifically, if it's an insert into
+	 * the 1st record in a leaf, it will require the adjustment of
+	 * e_clusters on the last record of the path directly to it's
+	 * left. For now, just catch that case and fool the layers
+	 * above us. This works just fine for tree_depth == 0, which
+	 * is why we allow that above.
+	 */
+	if (insert->ins_contig == CONTIG_LEFT &&
+	    insert->ins_contig_index == 0)
+		insert->ins_contig = CONTIG_NONE;
+
+	/*
 	 * Ok, so we can simply compare against last_eb to figure out
 	 * whether the path doesn't exist. This will only happen in
 	 * the case that we're doing a tail append, so maybe we can
@@ -1547,7 +1636,7 @@
 	unsigned int range;
 	struct ocfs2_extent_rec *rec;
 
-	assert(!el->l_tree_depth);
+	assert(el->l_tree_depth == 0);
 
 	/*
 	 * Contiguous insert - either left or right.
@@ -1601,16 +1690,62 @@
 	ocfs2_rotate_leaf(el, insert_rec);
 }
 
-static int ocfs2_append_rec_to_path(struct ocfs2_path *path,
-				    struct ocfs2_extent_rec *insert_rec)
+static int ocfs2_append_rec_to_path(ocfs2_filesys *fs,
+				    struct ocfs2_extent_rec *insert_rec,
+				    struct ocfs2_path *right_path,
+				    struct ocfs2_path **ret_left_path)
 {
 	int ret, i, next_free;
 	struct ocfs2_extent_list *el;
-	struct ocfs2_extent_rec *rec;
+	struct ocfs2_path *left_path = NULL;
 
-	el = path_root_el(path);
+	*ret_left_path = NULL;
+
+	/*
+	 * This shouldn't happen for non-trees. The extent rec cluster
+	 * count manipulation below only works for interior nodes.
+	 */
+	assert(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 = el->l_next_free_rec;
+	if (next_free == 0 ||
+	    (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) {
+		uint32_t left_cpos;
+
+		ret = ocfs2_find_cpos_for_left_leaf(right_path, &left_cpos);
+		if (ret)
+			goto out;
+		/*
+		 * No need to worry if the append is already in the
+		 * leftmost leaf.
+		 */
+		if (left_cpos) {
+			left_path = ocfs2_new_path(fs,
+						   path_root_buf(right_path),
+						   path_root_el(right_path));
+			if (!left_path) {
+				ret = OCFS2_ET_NO_MEMORY;
+				goto out;
+			}
+
+			ret = ocfs2_find_path(fs, left_path, left_cpos);
+			if (ret)
+				goto out;
+		}
+	}
+
+	el = path_root_el(right_path);
 	i = 0;
 	while (1) {
+		struct ocfs2_extent_rec *rec;
+
 		next_free = el->l_next_free_rec;
 		if (next_free == 0) {
 			ret = OCFS2_ET_CORRUPT_EXTENT_BLOCK;
@@ -1622,14 +1757,18 @@
 		rec->e_int_clusters += insert_rec->e_leaf_clusters;
 		rec->e_int_clusters -= rec->e_cpos;
 
-		if (++i >= path->p_tree_depth)
+		/* Don't touch the leaf node */
+		if (++i >= right_path->p_tree_depth)
 			break;
 
-		el = path->p_node[i].el;
+		el = right_path->p_node[i].el;
 	}
 
+	*ret_left_path = left_path;
 	ret = 0;
 out:
+	if (ret)
+		ocfs2_free_path(left_path);
 	return ret;
 }
 
@@ -1639,7 +1778,7 @@
  *
  * 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 a rotation.
+ * portion of the tree after an edge insert.
  */
 static int ocfs2_insert_path(struct insert_ctxt* ctxt,
 			     struct ocfs2_path *left_path,
@@ -1650,24 +1789,6 @@
 	int ret, subtree_index;
 	struct ocfs2_extent_list *el;
 
-	/*
-	 * At this point, only appends that are not left contig
-	 * require an update of the full tree path.
-	 */
-	if (insert->ins_appending == APPEND_NONE
-	    || insert->ins_contig == CONTIG_LEFT)
-		goto out_update_leaf;
-
-	/*
-	 * We should only get a left path for some types of rotations.
-	 */
-	assert(!left_path);
-
-	ret = ocfs2_append_rec_to_path(right_path, insert_rec);
-	if (ret)
-		goto out;
-
-out_update_leaf:
 	el = path_leaf_el(right_path);
 
 	ocfs2_insert_at_leaf(insert_rec, el, insert);
@@ -1678,7 +1799,7 @@
 		 * up portions of the tree after the insert.
 		 */
 		subtree_index = ocfs2_find_subtree_root(left_path, right_path);
-		ocfs2_complete_rotation(ctxt->fs, left_path,
+		ocfs2_complete_edge_insert(ctxt->fs, left_path,
 				        right_path, subtree_index);
 	} else
 		subtree_index = 0;
@@ -1732,15 +1853,32 @@
 	if (ret)
 		goto out;
 
-	if (!rotate)
-		goto out_insert;
+	/*
+	 * 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...
+	 */
 
-	ret = ocfs2_rotate_tree_right(fs, insert_rec->e_cpos,
-				      &left_path, right_path);
-	if (ret)
-		goto out;
+	if (rotate) {
+		ret = ocfs2_rotate_tree_right(fs, insert_rec->e_cpos,
+					      right_path, &left_path);
+		if (ret)
+			goto out;
+	} else if (type->ins_appending == APPEND_TAIL
+		   && type->ins_contig != CONTIG_LEFT) {
+		ret = ocfs2_append_rec_to_path(fs, insert_rec,
+					       right_path, &left_path);
+		if (ret)
+			goto out;
+ 	}
 
-out_insert:
 	ret = ocfs2_insert_path(ctxt, left_path, right_path, insert_rec, type);
 	if (ret)
 		goto out;




More information about the Ocfs2-tools-commits mailing list