Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Aug 2018 20:33:14 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r337177 - in head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs: . sys
Message-ID:  <201808022033.w72KXEiP023396@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Thu Aug  2 20:33:13 2018
New Revision: 337177
URL: https://svnweb.freebsd.org/changeset/base/337177

Log:
  MFV r337175: 9487 Free objects when receiving full stream as clone
  
  All objects after the last written or freed object are not supposed to
  exist after receiving the stream. We should free them accordingly, as if
  a freeobjects record for them had been included in the stream.
  
  zfsonlinux/zfs@48fbb9ddbf2281911560dfbc2821aa8b74127315
  illumos/illumos-gate@7864b8192b8d30471fa2240466d516292e5765b8
  
  Reviewed by: Matthew Ahrens <mahrens@delphix.com>
  Approved by: Dan McDonald <danmcd@joyent.com>
  Author:     Paul Dagnelie <pcd@delphix.com>

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_send.h
Directory Properties:
  head/sys/cddl/contrib/opensolaris/   (props changed)

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c	Thu Aug  2 20:31:54 2018	(r337176)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c	Thu Aug  2 20:33:13 2018	(r337177)
@@ -1795,6 +1795,7 @@ dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_re
 	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;
@@ -1855,7 +1856,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 */
 };
 
@@ -2152,6 +2155,9 @@ receive_object(struct receive_writer_arg *rwa, struct 
 		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
@@ -2247,6 +2253,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);
@@ -2276,6 +2285,9 @@ receive_write(struct receive_writer_arg *rwa, struct d
 	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));
 
@@ -2352,6 +2364,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)
@@ -2394,6 +2409,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,
@@ -2430,6 +2448,9 @@ receive_spill(struct receive_writer_arg *rwa, struct d
 	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);
@@ -2474,6 +2495,9 @@ receive_free(struct receive_writer_arg *rwa, struct dr
 	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);
 
@@ -3092,6 +3116,41 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *f
 		cv_wait(&rwa.cv, &rwa.mutex);
 	}
 	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. Note that it's possible that
+	 * we've resumed this send and the first record we received was the END
+	 * record. In that case, max_object would be 0, but we shouldn't start
+	 * freeing all objects from there; instead we should start from the
+	 * resumeobj.
+	 */
+	if (drc->drc_clone && drc->drc_drrb->drr_fromguid == 0) {
+		uint64_t obj;
+		if (nvlist_lookup_uint64(begin_nvl, "resume_object", &obj) != 0)
+			obj = 0;
+		if (rwa.max_object > obj)
+			obj = rwa.max_object;
+		obj++;
+		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);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_send.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_send.h	Thu Aug  2 20:31:54 2018	(r337176)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_send.h	Thu Aug  2 20:33:13 2018	(r337177)
@@ -70,6 +70,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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808022033.w72KXEiP023396>