[Ocfs2-tools-devel] [RFC] fsck.ocfs2 refcount.v3

Tao Ma tao.ma at oracle.com
Mon Nov 23 00:12:34 PST 2009


Hi list,

I am now adding refcount support for fsck.ocfs2.

Here is the draft and I'd like to see your comments before I fully implement it.
1. check the inode field in o2fsck_verify_inode_fields.
   1) check dyn_feature. If the volume has no refcount support, clear
      OCFS2_HAS_REFCOUNT_FL.
   2) check i_refcount_loc. If the volume has no refcount support, or
      the file has no OCFS2_HAS_REFCOUNT_FL, reset i_refcount_loc to 0.
2. check the refcount_tree. Details below.
3. in o2fsck_check_blocks and o2fsck_check_xattr, if the ocfs2_extent_rec
   is refcounted, add it to the refcount_extent rb-tree(discribed below),
   and the file which share the same refcount tree will be in a list.
   Please note that we don't call o2fsck_mark_cluster_allocated against
   refcounted clusters. It will be handled in step 4.
4. check the refcounted extent rec, and if we finds any wrong clusters,
   add them to ost_dup_clusters. Details below.
5. call ocfs2_pass1_dup to handle duplicate clusters.

Details for checking refcount tree(step 2).
1) if read_refcount_block fails, remove the whole block. If it is
   the root block, remove the dyn_features and i_refcount_loc.
2) Basic check of the pyhsical clusters. If it is above the volume size,
   remove it. Other test will be postoned to step 4.
2) if there is any overlap among refcount_rec,
   say (ec1.r_cpos + rec1.r_clusters > rec2.r_cpos), remove rec2.

So below is the details for step 4.
The main structure is:

/* every REFCOUNTED ocfs2_extent_rec will become one. */
struct refcount_extent {
        struct rb_node ext_node;
        uint32_t clusters;
        uint64_t p_cpos;
};

/* every refcounted file corresponds one. */
struct recount_file {
        uint64_t blkno;
        struct list_head next;
        struct rb_root ref_extents; /* store every refcounted extent rec
				     * in this file. */
};

/* every refcount tree corresponds one. */
struct refcount_block {
        uint64_t rf_blkno;
        struct list_head files_list; /* list all the files which have the
				      * same refcount tree. */
};

So given a refcount_block, the main check function is:
check_refcount(refcount_block)
{
	/*
	 * old_p_cpos is to record the end of the previous checked clusters.
	 * ref_rec is to record the refcount rec we are checking.
	 * r_offset is the offset in ref_rec we have checked.
	 */
	old_p_cpos = 0;
	ref_rec = NULL;
	r_offset = 0;

	while (any refcount file have refcount_extent) {
		/* Find the lowest p_cpos. */
		for (the 1st refcount_extent for every file)
			find the smallest 3-tuple(p_cpos, clusters, refcount);
	
		orig_p_cpos = p_cpos;
		orig_clusters = clusters;

		o2fsck_mark_cluster_allocated(p_cpos, clusters, &has_setted);
		if (has_setted) {
			/*
			 * There is other system file which has already set
			 * the used clusters bitmap. So we have to add them
			 * to duplicate clusters and let ocfs2_pass1_dup
			 * handle them.
			 */
			add_to_dup_clusters(p_cpos, clusters);
			ocfs2_refcount_punch_hole(p_cpos, p_cpos + clusters);
			ref_rec = NULL;
			r_offset = 0;
			if (old_p_cpos < p_cpos + clusters)
				old_p_pos = p_cpos + clusters;
			goto next;
		}

	/* This will be moved to a new function in the implementation. */
again:
		if (!ref_rec)
			ocfs2_get_refcount_rec(p_cpos, &ref_rec);

		if (ref_rec.r_cpos + r_offset < p_cpos) {
        	        /* there is a hole in the refount tree. remove it. */
			ocfs2_refcount_punch_hole(ref_rec.r_cpos +
						  r_offset, p_cpos);
			ref_rec = NULL;
			r_offset = 0;
			goto again;
		} else if (ref_rec.r_cpos + r_offset > p_cpos) {
			/*
			 * Some clusters are marked as refcounted, but don't
			 * have corresponding refcount_rec in the refcount tree.
			 */
			if (user want to add it to refcount tree) {
				ocfs2_add_refcount(p_cpos,
					ref_rec.r_cpos + r_offset - p_cpos,
					refcount);
			} else {
				/* Add to duplicate clusters and let
				 * ocfs2_pass1_dup handle them.
				 */
				add_to_dup_clusters(p_cpos,
					ref_rec.r_cpos + r_offset - p_cpos);
			}
			change = ref_rec.r_cpos + r_offset - p_cpos;
			p_cpos = ref_rec.r_cpos + r_offset;
			clusters -= change;
			goto again;
		}

		/* now ref_rec.r_cpos + r_offset == p_cpos */
		if (ref_rec.r_count != refcount) {
			if (user want to update ref_rec.r_count)
				update_r_count(ref_rec);
			else if (user want to dup) {
				add_to_dup_clusters(p_cpos,
					min(p_cpos + clusters,
				  ref_rec.r_cpos + ref_rec.r_clusters));
				ocfs2_refcount_punch_hole(p_cpos,
					min(p_cpos + clusters,
				  ref_rec.r_cpos + ref_rec.r_clusters));
			} else {
				/*
				 * User has told us to leave it alone.
				 * Skip to the next hunk.
				 */
				goto next;
			}
		}

		if (p_cpos + clusters <=
		    ref_rec.r_cpos + ref_rec.r_clusters) {
			/* we have finished checking (p_cpos, clusters). */
			if (p_cpos + clusters <
			    ref_rec.r_cpos + ref_rec.r_clusters) {
				/*
				 * this refcount_rec still have more clusters.
				 * record the end of the r_clusters.
				 * the next (p_cpos, clusters) will still use
				 * this refcount_rec.
				 */
				r_offset = p_cpos + clusters - ref_rec.r_cpos;
			}
			old_p_cpos = p_cpos + clusters;
			goto next;
		}

		/*
		 * now we have finished checking current refcount_rec,
		 * p_cpos + clusters > ref_rec.r_cpos + ref_rec.r_clusters,
		 * need to read next refcount_rec.
		 */
		clusters += p_cpos;
		p_cpos = refcount_rec.r_cpos + ref_rec.r_clusters;
		clusters -= p_cpos;
		ref_rec = NULL;
		r_offset = 0;
		goto again;
next:
		for (the 1st refcount_extent for every file)
        	     remove (orig_p_cpos, orig_clusters) if exists;
	}

	/*
	 * Remove all the refcount rec passed "p_cpos" from the tree since
	 * there is no corresponding refcounted clusters.
	 */
	ocfs2_refcount_punch_hole(p_cpos, UINT_MAX);
}

Regards,
Tao



More information about the Ocfs2-tools-devel mailing list