[PATCH 2/9] nilfs2: add comparison function of two block mappings
This adds nilfs_bmap_compare() function and its helper routine
(nilfs_bmap_do_compare function). The nilfs_bmap_compare function
enumerates changes on the data blocks that given two bmap objects
hold. These functions are available to efficiently find out changes
on meta-data or user data between two checkpoints.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx>
---
fs/nilfs2/bmap.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/nilfs2/bmap.h | 15 +++++
2 files changed, 169 insertions(+), 0 deletions(-)
diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c
index aadbd0b..84c4866 100644
--- a/fs/nilfs2/bmap.c
+++ b/fs/nilfs2/bmap.c
@@ -422,6 +422,160 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *bmap)
return ret;
}
+static ssize_t nilfs_bmap_do_compare(struct nilfs_bmap *bmap1,
+ struct nilfs_bmap *bmap2, __u64 start,
+ struct nilfs_bmap_diff *diffs,
+ size_t maxdiffs)
+{
+ __u64 key1, key2;
+ __u64 ptr1, ptr2;
+ void *ctx1, *ctx2;
+ ssize_t n = 0;
+ int next1 = false, next2 = false;
+ int done1 = false, done2 = false;
+ int ret;
+
+ key1 = start;
+ ret = bmap1->b_ops->bop_find(bmap1, &key1, &ptr1, &ctx1);
+ if (ret < 0) {
+ if (ret != -ENOENT) {
+ n = ret;
+ goto out;
+ }
+ done1 = true;
+ ctx1 = NULL; /* ensure ->bop_find_close(bmap1, ctx1) safe */
+ }
+
+ key2 = start;
+ ret = bmap2->b_ops->bop_find(bmap2, &key2, &ptr2, &ctx2);
+ if (ret < 0) {
+ if (ret != -ENOENT) {
+ n = ret;
+ goto out;
+ }
+ done2 = true;
+ ctx2 = NULL; /* ensure ->bop_find_close(bmap2, ctx2) safe */
+ }
+
+ while (1) {
+ if (done1) {
+ if (done2)
+ break;
+
+ diffs[n].key = key2;
+ diffs[n].ptr1 = NILFS_BMAP_INVALID_PTR;
+ diffs[n].ptr2 = ptr2;
+ next2 = true;
+ } else if (done2) {
+ diffs[n].key = key1;
+ diffs[n].ptr1 = ptr1;
+ diffs[n].ptr2 = NILFS_BMAP_INVALID_PTR;
+ next1 = true;
+ } else if (key1 == key2) {
+ next1 = true;
+ next2 = true;
+
+ if (ptr1 == ptr2)
+ goto lookup_next;
+
+ diffs[n].key = key1;
+ diffs[n].ptr1 = ptr1;
+ diffs[n].ptr2 = ptr2;
+ } else if (key1 < key2) {
+ diffs[n].key = key1;
+ diffs[n].ptr1 = ptr1;
+ diffs[n].ptr2 = NILFS_BMAP_INVALID_PTR;
+ next1 = true;
+ } else /* key1 > key2 */ {
+ diffs[n].key = key2;
+ diffs[n].ptr1 = NILFS_BMAP_INVALID_PTR;
+ diffs[n].ptr2 = ptr2;
+ next2 = true;
+ }
+
+ n++;
+ if (n == maxdiffs)
+ break;
+
+ lookup_next:
+ if (next1) {
+ ret = bmap1->b_ops->bop_find_next(bmap1, &key1,
+ &ptr1, ctx1);
+ if (ret < 0) {
+ if (ret != -ENOENT) {
+ n = ret;
+ break;
+ }
+ done1 = true;
+ }
+ next1 = false;
+ }
+ if (next2) {
+ ret = bmap2->b_ops->bop_find_next(bmap2, &key2,
+ &ptr2, ctx2);
+ if (ret < 0) {
+ if (ret != -ENOENT) {
+ n = ret;
+ break;
+ }
+ done2 = true;
+ }
+ next2 = false;
+ }
+ }
+out:
+ bmap2->b_ops->bop_find_close(bmap2, ctx2);
+ bmap1->b_ops->bop_find_close(bmap1, ctx1);
+ return n;
+}
+
+/**
+ * nilfs_bmap_compare - compare two bmaps and find their differences
+ * @bmap1: source bmap
+ * @bmap2: target bmap
+ * @start: start key
+ * @diffs: pointer to an array of nilfs_bmap_diff structures
+ * @maxdiffs: number of nilfs_bmap_diff structures
+ *
+ * Description: nilfs_bmap_compare() compares two versions of bmap and
+ * stores their differences in nilfs_bmap_diff structures given by
+ * @diffs and @maxdiffs.
+ *
+ * Return Value: On success, number of items stored to @diffs are
+ * returned. On error, one of the following negative error codes are
+ * returned.
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ */
+ssize_t nilfs_bmap_compare(struct nilfs_bmap *bmap1, struct nilfs_bmap *bmap2,
+ __u64 start, struct nilfs_bmap_diff *diffs,
+ size_t maxdiffs)
+{
+ ssize_t ret;
+
+ if (maxdiffs == 0)
+ return 0;
+
+ /*
+ * hold semaphore with smaller address first to avoid possible
+ * deadlock problem.
+ */
+ if (bmap1 < bmap2) {
+ down_read(&bmap1->b_sem);
+ down_read(&bmap2->b_sem);
+ } else {
+ down_read(&bmap2->b_sem);
+ down_read(&bmap1->b_sem);
+ }
+
+ ret = nilfs_bmap_do_compare(bmap1, bmap2, start, diffs, maxdiffs);
+
+ up_read(&bmap1->b_sem);
+ up_read(&bmap2->b_sem);
+ return ret;
+}
/*
* Internal use only
diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h
index cff22c2..2e57537 100644
--- a/fs/nilfs2/bmap.h
+++ b/fs/nilfs2/bmap.h
@@ -56,6 +56,18 @@ struct nilfs_bmap_stats {
};
/**
+ * struct nilfs_bmap_diff - array item to store bmap comparison result
+ * @key: key index
+ * @ptr: bmap pointer 1
+ * @ptr: bmap pointer 2
+ */
+struct nilfs_bmap_diff {
+ __u64 key;
+ __u64 ptr1;
+ __u64 ptr2;
+};
+
+/**
* struct nilfs_bmap_operations - bmap operation table
*/
struct nilfs_bmap_operations {
@@ -162,6 +174,9 @@ int nilfs_bmap_assign(struct nilfs_bmap *, struct buffer_head **,
unsigned long, union nilfs_binfo *);
int nilfs_bmap_lookup_at_level(struct nilfs_bmap *, __u64, int, __u64 *);
int nilfs_bmap_mark(struct nilfs_bmap *, __u64, int);
+ssize_t nilfs_bmap_compare(struct nilfs_bmap *bmap1, struct nilfs_bmap *bmap2,
+ __u64 start, struct nilfs_bmap_diff *diffs,
+ size_t maxdiffs);
void nilfs_bmap_init_gc(struct nilfs_bmap *);
--
1.7.3.5
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
[Linux Filesystem; Devel]
[Linux CIFS]
[Linux USB Devel]
[Video for Linux]
[Linux Audio Users]
[Photo]
[Yosemite News]
[Yosemite Photos]
[Free Online Dating]
[Linux Kernel]
[Linux SCSI]
[XFree86]