[Ocfs2-devel] [PATCH 17/41] ocfs2: Add CoW support.
Tao Ma
tao.ma at oracle.com
Fri Aug 21 01:24:25 PDT 2009
Hi Joel,
As our talk in irc, here is the updated one. Please review.
Regards,
Tao
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index cfaf59e..e659dc5 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -2499,7 +2499,7 @@ out:
return ret;
}
-#define MAX_COW_BYTES 1048576
+#define MAX_CONTIG_BYTES 1048576
/*
* Calculate out the start and number of virtual clusters we need to to CoW.
*
@@ -2508,9 +2508,8 @@ out:
* max_cpos is the place where we want to stop CoW intentionally.
*
* Normal we will start CoW from the beginning of extent record cotaining cpos.
- * And We will try to Cow as much clusters as we can until we reach
- * MAX_COW_BYTES. If the write_len is larger than MAX_COW_BYTES, we will
- * use that value as the maximum clusters.
+ * We try to break up extents on boundaries of MAX_CONTIG_BYTES so that we
+ * get good I/O from the resulting extent tree.
*/
static int ocfs2_refcount_cal_cow_clusters(struct inode *inode,
struct ocfs2_extent_list *el,
@@ -2525,10 +2524,11 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode,
struct buffer_head *eb_bh = NULL;
struct ocfs2_extent_block *eb = NULL;
struct ocfs2_extent_rec *rec;
- int max_clusters = ocfs2_clusters_for_bytes(inode->i_sb, MAX_COW_BYTES);
+ int want_clusters;
+ int contig_clusters =
+ ocfs2_clusters_for_bytes(inode->i_sb, MAX_CONTIG_BYTES);
int leaf_clusters, rec_end = 0;
- max_clusters = max_clusters < write_len ? write_len : max_clusters;
if (tree_height > 0) {
ret = ocfs2_find_leaf(INODE_CACHE(inode), el, cpos, &eb_bh);
if (ret) {
@@ -2588,53 +2588,95 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode,
leaf_clusters = rec_end - le32_to_cpu(rec->e_cpos);
}
- if (*cow_len + leaf_clusters >= max_clusters) {
- if (*cow_len == 0) {
- /*
- * cpos is in a very large extent record.
- * So just split max_clusters from the
- * extent record.
- */
- if ((rec_end - cpos) <= max_clusters) {
- /*
- * We can take max_clusters off
- * the end and cover all of our
- * write.
- */
- *cow_start = rec_end - max_clusters;
- } else if ((*cow_start + max_clusters) >
- (cpos + write_len)) {
- /*
- * We can take max_clusters off
- * the front and cover all of
- * our write.
- */
- /* NOOP, *cow_start is already set */
- } else {
- /*
- * We're CoWing more data than
- * write_len for contiguousness,
- * but it doesn't fit at the
- * front or end of this extent.
- * Let's try to slice the extent
- * up nicely. Optimally, our
- * CoW region starts at a
- * multiple of max_clusters. If
- * that doesn't fit, we give up
- * and just CoW at cpos.
- */
- *cow_start +=
- (cpos - *cow_start) &
- ~(max_clusters - 1);
- if ((*cow_start + max_clusters) <
- (cpos + write_len))
- *cow_start = cpos;
- }
- }
- *cow_len = max_clusters;
- break;
- } else
+ /*
+ * How many clusters do we actually need from
+ * this extent? First we see how many we actually
+ * need to complete the write. If that's smaller
+ * than contig_clusters, we try for
+ * contig_clustes.
+ */
+ if (!*cow_len)
+ want_clusters = write_len;
+ else
+ want_clusters = (cpos + write_len) -
+ (*cow_start + *cow_len);
+ if (want_clusters < contig_clusters)
+ want_clusters = contig_clusters;
+
+ /*
+ * If the write does not cover the whole extent, we
+ * need to calculate how we're going to split the extent.
+ * We try to do it on contig_clusters boundaries.
+ *
+ * Any extent smaller than contig_clusters will be
+ * CoWed in its entirety.
+ */
+ if (leaf_clusters <= contig_clusters)
*cow_len += leaf_clusters;
+ else if (*cow_len || (*cow_start == cpos)) {
+ /*
+ * This extent needs to be CoW'd from its
+ * beginning, so all we have to do is compute
+ * how many clusters to grab.
+ * We align the want_clusters to the edge of
+ * contig_clusters to get better I/O.
+ */
+ want_clusters = (want_clusters + contig_clusters - 1) /
+ contig_clusters * contig_clusters;
+
+ if (leaf_clusters < want_clusters)
+ *cow_len += leaf_clusters;
+ else
+ *cow_len += want_clusters;
+ } else if ((*cow_start + contig_clusters) >=
+ (cpos + write_len)) {
+ /*
+ * Breaking off contig_clusters at the front
+ * of the extent will cover our write. That's
+ * easy.
+ */
+ *cow_len = contig_clusters;
+ } else if ((rec_end - cpos) <= contig_clusters) {
+ /*
+ * Breaking off contig_clusters at the tail of
+ * this extent will cover cpos.
+ */
+ *cow_start = rec_end - cpos;
+ *cow_len = contig_clusters;
+ } else if ((rec_end - cpos) <= want_clusters) {
+ /*
+ * While we can't fit the entire write in this
+ * extent, we know that the write goes from cpos
+ * to the end of the extent. Break that off.
+ * We try to break it in the aligned range, if not
+ * CoW the whole extent.
+ */
+ *cow_start += (cpos - *cow_start) &
+ ~(contig_clusters - 1);
+ *cow_len = rec_end - *cow_start;
+ } else {
+ /*
+ * Ok, the entire write lives in the middle of
+ * this extent.
+ * Let's try to slice the extentup nicely.
+ * Optimally, our CoW region starts at a
+ * multiple of contig_clusters.
+ */
+ *cow_start += (cpos - *cow_start) &
+ ~(contig_clusters - 1);
+
+ want_clusters = (cpos + write_len) - *cow_start;
+ want_clusters = (want_clusters + contig_clusters - 1) /
+ contig_clusters * contig_clusters;
+ if (*cow_start + want_clusters <= rec_end)
+ *cow_len = want_clusters;
+ else
+ *cow_len = rec_end - *cow_start;
+ }
+
+ /* Have we covered our entire write yet? */
+ if ((*cow_start + *cow_len) >= (cpos + write_len))
+ break;
/*
* If we reach the end of the extent block and don't get enough
More information about the Ocfs2-devel
mailing list