266 lines
9.4 KiB
Diff
266 lines
9.4 KiB
Diff
From 27d60535a612beaf31c27f5d8969abffac514841 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= <f.gruenbichler@proxmox.com>
|
|
Date: Thu, 12 Oct 2017 12:29:01 +0200
|
|
Subject: [PATCH 11/11] include upstream PR #6616
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
send/recv compatibility with 0.6.5.x
|
|
|
|
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
|
---
|
|
...FREEOBJECTS-for-objects-which-can-t-exist.patch | 54 +++++++
|
|
...jects-when-receiving-full-stream-as-clone.patch | 167 +++++++++++++++++++++
|
|
debian/patches/series | 2 +
|
|
3 files changed, 223 insertions(+)
|
|
create mode 100644 debian/patches/0011-Skip-FREEOBJECTS-for-objects-which-can-t-exist.patch
|
|
create mode 100644 debian/patches/0012-Free-objects-when-receiving-full-stream-as-clone.patch
|
|
|
|
diff --git a/debian/patches/0011-Skip-FREEOBJECTS-for-objects-which-can-t-exist.patch b/debian/patches/0011-Skip-FREEOBJECTS-for-objects-which-can-t-exist.patch
|
|
new file mode 100644
|
|
index 000000000..e2f0a7cdd
|
|
--- /dev/null
|
|
+++ b/debian/patches/0011-Skip-FREEOBJECTS-for-objects-which-can-t-exist.patch
|
|
@@ -0,0 +1,54 @@
|
|
+From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= <f.gruenbichler@proxmox.com>
|
|
+Date: Tue, 26 Sep 2017 14:03:21 +0200
|
|
+Subject: Skip FREEOBJECTS for objects which can't exist
|
|
+MIME-Version: 1.0
|
|
+Content-Type: text/plain; charset="utf-8"
|
|
+Content-Transfer-Encoding: 8bit
|
|
+
|
|
+When sending an incremental stream based on a snapshot, the receiving
|
|
+side must have the same base snapshot. Thus we do not need to send
|
|
+FREEOBJECTS records for any objects past the maximum one which exists
|
|
+locally.
|
|
+
|
|
+This allows us to send incremental streams (again) to older ZFS
|
|
+implementations (e.g. ZoL < 0.7) which actually try to free all objects
|
|
+in a FREEOBJECTS record, instead of bailing out early.
|
|
+
|
|
+Reviewed by: Paul Dagnelie <pcd@delphix.com>
|
|
+Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
+Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
|
+Closes #5699
|
|
+Closes #6507
|
|
+Closes #6616
|
|
+(cherry picked from commit 829e95c4dc74d7d6d31d01af9c39e03752499b15)
|
|
+---
|
|
+ module/zfs/dmu_send.c | 16 ++++++++++++++++
|
|
+ 1 file changed, 16 insertions(+)
|
|
+
|
|
+diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c
|
|
+index 0c53ced..a81580d 100644
|
|
+--- a/module/zfs/dmu_send.c
|
|
++++ b/module/zfs/dmu_send.c
|
|
+@@ -421,6 +421,22 @@ static int
|
|
+ dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs)
|
|
+ {
|
|
+ struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects);
|
|
++ uint64_t maxobj = DNODES_PER_BLOCK *
|
|
++ (DMU_META_DNODE(dsp->dsa_os)->dn_maxblkid + 1);
|
|
++
|
|
++ /*
|
|
++ * ZoL < 0.7 does not handle large FREEOBJECTS records correctly,
|
|
++ * leading to zfs recv never completing. to avoid this issue, don't
|
|
++ * send FREEOBJECTS records for object IDs which cannot exist on the
|
|
++ * receiving side.
|
|
++ */
|
|
++ if (maxobj > 0) {
|
|
++ if (maxobj < firstobj)
|
|
++ return (0);
|
|
++
|
|
++ if (maxobj < firstobj + numobjs)
|
|
++ numobjs = maxobj - firstobj;
|
|
++ }
|
|
+
|
|
+ /*
|
|
+ * If there is a pending op, but it's not PENDING_FREEOBJECTS,
|
|
diff --git a/debian/patches/0012-Free-objects-when-receiving-full-stream-as-clone.patch b/debian/patches/0012-Free-objects-when-receiving-full-stream-as-clone.patch
|
|
new file mode 100644
|
|
index 000000000..75f4be84c
|
|
--- /dev/null
|
|
+++ b/debian/patches/0012-Free-objects-when-receiving-full-stream-as-clone.patch
|
|
@@ -0,0 +1,167 @@
|
|
+From: =?utf-8?q?Fabian_Gr=C3=BCnbichler?= <f.gruenbichler@proxmox.com>
|
|
+Date: Fri, 29 Sep 2017 12:00:29 +0200
|
|
+Subject: Free objects when receiving full stream as clone
|
|
+MIME-Version: 1.0
|
|
+Content-Type: text/plain; charset="utf-8"
|
|
+Content-Transfer-Encoding: 8bit
|
|
+
|
|
+All objects after the last written or freed object are not supposed to
|
|
+exist after receiving the stream. Free them accordingly, as if a
|
|
+freeobjects record for them had been included in the stream.
|
|
+
|
|
+Reviewed by: Paul Dagnelie <pcd@delphix.com>
|
|
+Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
|
|
+Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
|
+Closes #5699
|
|
+Closes #6507
|
|
+Closes #6616
|
|
+(backported from commit 48fbb9ddbf2281911560dfbc2821aa8b74127315)
|
|
+
|
|
+ Conflicts:
|
|
+ include/sys/dmu_send.h
|
|
+ module/zfs/dmu_send.c
|
|
+
|
|
+modified for code paths missing in 0.7
|
|
+---
|
|
+ include/sys/dmu_send.h | 1 +
|
|
+ module/zfs/dmu_send.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
+ 2 files changed, 52 insertions(+), 1 deletion(-)
|
|
+
|
|
+diff --git a/include/sys/dmu_send.h b/include/sys/dmu_send.h
|
|
+index e9bef8b..5cf67a6 100644
|
|
+--- a/include/sys/dmu_send.h
|
|
++++ b/include/sys/dmu_send.h
|
|
+@@ -61,6 +61,7 @@ typedef struct dmu_recv_cookie {
|
|
+ boolean_t drc_byteswap;
|
|
+ boolean_t drc_force;
|
|
+ boolean_t drc_resumable;
|
|
++ boolean_t drc_clone;
|
|
+ struct avl_tree *drc_guid_to_ds_map;
|
|
+ zio_cksum_t drc_cksum;
|
|
+ uint64_t drc_newsnapobj;
|
|
+diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c
|
|
+index a81580d..344e420 100644
|
|
+--- a/module/zfs/dmu_send.c
|
|
++++ b/module/zfs/dmu_send.c
|
|
+@@ -1823,6 +1823,7 @@ dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin,
|
|
+ drc->drc_force = force;
|
|
+ drc->drc_resumable = resumable;
|
|
+ drc->drc_cred = CRED();
|
|
++ drc->drc_clone = (origin != NULL);
|
|
+
|
|
+ if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
|
|
+ drc->drc_byteswap = B_TRUE;
|
|
+@@ -1883,7 +1884,9 @@ struct receive_writer_arg {
|
|
+ /* A map from guid to dataset to help handle dedup'd streams. */
|
|
+ avl_tree_t *guid_to_ds_map;
|
|
+ boolean_t resumable;
|
|
+- uint64_t last_object, last_offset;
|
|
++ uint64_t last_object;
|
|
++ uint64_t last_offset;
|
|
++ uint64_t max_object; /* highest object ID referenced in stream */
|
|
+ uint64_t bytes_read; /* bytes read when current record created */
|
|
+ };
|
|
+
|
|
+@@ -2157,6 +2160,9 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
|
|
+ return (SET_ERROR(EINVAL));
|
|
+ object = err == 0 ? drro->drr_object : DMU_NEW_OBJECT;
|
|
+
|
|
++ if (drro->drr_object > rwa->max_object)
|
|
++ rwa->max_object = drro->drr_object;
|
|
++
|
|
+ /*
|
|
+ * If we are losing blkptrs or changing the block size this must
|
|
+ * be a new file instance. We must clear out the previous file
|
|
+@@ -2257,6 +2263,9 @@ receive_freeobjects(struct receive_writer_arg *rwa,
|
|
+ err = dmu_free_long_object(rwa->os, obj);
|
|
+ if (err != 0)
|
|
+ return (err);
|
|
++
|
|
++ if (obj > rwa->max_object)
|
|
++ rwa->max_object = obj;
|
|
+ }
|
|
+ if (next_err != ESRCH)
|
|
+ return (next_err);
|
|
+@@ -2287,6 +2296,9 @@ receive_write(struct receive_writer_arg *rwa, struct drr_write *drrw,
|
|
+ rwa->last_object = drrw->drr_object;
|
|
+ rwa->last_offset = drrw->drr_offset;
|
|
+
|
|
++ if (rwa->last_object > rwa->max_object)
|
|
++ rwa->max_object = rwa->last_object;
|
|
++
|
|
+ if (dmu_object_info(rwa->os, drrw->drr_object, NULL) != 0)
|
|
+ return (SET_ERROR(EINVAL));
|
|
+
|
|
+@@ -2362,6 +2374,9 @@ receive_write_byref(struct receive_writer_arg *rwa,
|
|
+ ref_os = rwa->os;
|
|
+ }
|
|
+
|
|
++ if (drrwbr->drr_object > rwa->max_object)
|
|
++ rwa->max_object = drrwbr->drr_object;
|
|
++
|
|
+ err = dmu_buf_hold(ref_os, drrwbr->drr_refobject,
|
|
+ drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH);
|
|
+ if (err != 0)
|
|
+@@ -2404,6 +2419,9 @@ receive_write_embedded(struct receive_writer_arg *rwa,
|
|
+ if (drrwe->drr_compression >= ZIO_COMPRESS_FUNCTIONS)
|
|
+ return (EINVAL);
|
|
+
|
|
++ if (drrwe->drr_object > rwa->max_object)
|
|
++ rwa->max_object = drrwe->drr_object;
|
|
++
|
|
+ tx = dmu_tx_create(rwa->os);
|
|
+
|
|
+ dmu_tx_hold_write(tx, drrwe->drr_object,
|
|
+@@ -2440,6 +2458,9 @@ receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
|
|
+ if (dmu_object_info(rwa->os, drrs->drr_object, NULL) != 0)
|
|
+ return (SET_ERROR(EINVAL));
|
|
+
|
|
++ if (drrs->drr_object > rwa->max_object)
|
|
++ rwa->max_object = drrs->drr_object;
|
|
++
|
|
+ VERIFY0(dmu_bonus_hold(rwa->os, drrs->drr_object, FTAG, &db));
|
|
+ if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) {
|
|
+ dmu_buf_rele(db, FTAG);
|
|
+@@ -2484,6 +2505,9 @@ receive_free(struct receive_writer_arg *rwa, struct drr_free *drrf)
|
|
+ if (dmu_object_info(rwa->os, drrf->drr_object, NULL) != 0)
|
|
+ return (SET_ERROR(EINVAL));
|
|
+
|
|
++ if (drrf->drr_object > rwa->max_object)
|
|
++ rwa->max_object = drrf->drr_object;
|
|
++
|
|
+ err = dmu_free_long_range(rwa->os, drrf->drr_object,
|
|
+ drrf->drr_offset, drrf->drr_length);
|
|
+
|
|
+@@ -3207,6 +3231,32 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
|
|
+ }
|
|
+ mutex_exit(&rwa->mutex);
|
|
+
|
|
++ /*
|
|
++ * If we are receiving a full stream as a clone, all object IDs which
|
|
++ * are greater than the maximum ID referenced in the stream are
|
|
++ * by definition unused and must be freed.
|
|
++ */
|
|
++ if (drc->drc_clone && drc->drc_drrb->drr_fromguid == 0) {
|
|
++ uint64_t obj = rwa->max_object + 1;
|
|
++ int free_err = 0;
|
|
++ int next_err = 0;
|
|
++
|
|
++ while (next_err == 0) {
|
|
++ free_err = dmu_free_long_object(rwa->os, obj);
|
|
++ if (free_err != 0 && free_err != ENOENT)
|
|
++ break;
|
|
++
|
|
++ next_err = dmu_object_next(rwa->os, &obj, FALSE, 0);
|
|
++ }
|
|
++
|
|
++ if (err == 0) {
|
|
++ if (free_err != 0 && free_err != ENOENT)
|
|
++ err = free_err;
|
|
++ else if (next_err != ESRCH)
|
|
++ err = next_err;
|
|
++ }
|
|
++ }
|
|
++
|
|
+ cv_destroy(&rwa->cv);
|
|
+ mutex_destroy(&rwa->mutex);
|
|
+ bqueue_destroy(&rwa->q);
|
|
diff --git a/debian/patches/series b/debian/patches/series
|
|
index 3c8f56483..8bd73161c 100644
|
|
--- a/debian/patches/series
|
|
+++ b/debian/patches/series
|
|
@@ -8,3 +8,5 @@ enable-zed.patch
|
|
0009-add-man-page-reference-to-systemd-units.patch
|
|
0010-fix-install-path-of-zpool.d-scripts.patch
|
|
0010-receive_freeobjects-skips-freeing-some-objects.patch
|
|
+0011-Skip-FREEOBJECTS-for-objects-which-can-t-exist.patch
|
|
+0012-Free-objects-when-receiving-full-stream-as-clone.patch
|
|
--
|
|
2.14.1
|
|
|