From: Sage Weil Date: Thu, 28 Mar 2013 16:26:11 +0000 (-0700) Subject: librbd: handle diff from clone X-Git-Tag: v0.62~118^2~37 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4d02e17f36e27c8aeefb383a56d4ae7110b5dd5b;p=ceph.git librbd: handle diff from clone If we have a parent image, and the reference is from snap 0 (beginning of time) we need to look at the diff on the parent from the beginning of time and report that when we get an ENOENT. Signed-off-by: Sage Weil --- diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index b1d30452f5ed..1340ba26f942 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -2256,6 +2256,14 @@ reprotect_and_return_err: return total_read; } + int simple_diff_cb(uint64_t off, size_t len, bool exists, void *arg) + { + interval_set *diff = static_cast *>(arg); + diff->insert(off, len); + return 0; + } + + int64_t diff_iterate(ImageCtx *ictx, const char *fromsnapname, uint64_t off, size_t len, int (*cb)(uint64_t, size_t, bool, void *), @@ -2307,6 +2315,22 @@ reprotect_and_return_err: // FIXME: if end_size > from_size, we could read_iterate for the // final part, and skip the listsnaps op. + // check parent overlap only if we are comparing to the beginning of time + interval_set parent_diff; + if (from_snap_id == 0) { + ictx->parent_lock.get_read(); + uint64_t overlap = end_size; + ictx->get_parent_overlap(from_snap_id, &overlap); + r = 0; + if (ictx->parent && overlap > 0) { + ldout(ictx->cct, 10) << " first getting parent diff" << dendl; + r = diff_iterate(ictx->parent, NULL, 0, overlap, simple_diff_cb, &parent_diff); + } + ictx->parent_lock.put_read(); + if (r < 0) + return r; + } + int64_t total_read = 0; uint64_t period = ictx->get_stripe_period(); uint64_t left = mylen; @@ -2334,8 +2358,25 @@ reprotect_and_return_err: op.stat(&size, NULL, NULL); op.list_snaps(&snap_set, NULL); int r = head_ctx.operate(p->first.name, &op, NULL); - if (r == -ENOENT) + if (r == -ENOENT) { + if (from_snap_id == 0 && !parent_diff.empty()) { + // report parent diff instead + for (vector::iterator q = p->second.begin(); q != p->second.end(); ++q) { + for (vector >::iterator r = q->buffer_extents.begin(); + r != q->buffer_extents.end(); + ++r) { + interval_set o; + o.insert(off + r->first, r->second); + o.intersection_of(parent_diff); + ldout(ictx->cct, 20) << " reporting parent overlap " << o << dendl; + for (interval_set::iterator s = o.begin(); s != o.end(); ++s) { + cb(s.get_start(), s.get_len(), false, arg); + } + } + } + } continue; + } if (r < 0) return r;