--- old/usr/src/common/zfs/zfs_prop.c	2015-11-02 01:49:37.913948048 +0100
+++ new/usr/src/common/zfs/zfs_prop.c	2015-11-02 01:49:37.925420518 +0100
@@ -429,6 +429,8 @@
 	    "STMF_SBD_LU");
 	zprop_register_hidden(ZFS_PROP_GUID, "guid", PROP_TYPE_NUMBER,
 	    PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "GUID");
+	zprop_register_hidden(ZFS_PROP_FSID_GUID, "fsid_guid", PROP_TYPE_NUMBER,
+	    PROP_DEFAULT, ZFS_TYPE_DATASET, "FSIDGUID");
 	zprop_register_hidden(ZFS_PROP_USERACCOUNTING, "useraccounting",
 	    PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET,
 	    "USERACCOUNTING");
--- old/usr/src/lib/libzfs/common/libzfs_changelist.c	2015-11-02 01:49:38.210070985 +0100
+++ new/usr/src/lib/libzfs/common/libzfs_changelist.c	2015-11-02 01:49:38.223311344 +0100
@@ -602,6 +602,8 @@
 		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
 	} else if (prop == ZFS_PROP_VOLSIZE) {
 		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+	} else if (prop == ZFS_PROP_FSID_GUID) {
+		clp->cl_prop = ZFS_PROP_MOUNTPOINT;
 	} else {
 		clp->cl_prop = prop;
 	}
--- old/usr/src/lib/libzfs/common/libzfs_dataset.c	2015-11-02 01:49:38.508675340 +0100
+++ new/usr/src/lib/libzfs/common/libzfs_dataset.c	2015-11-02 01:49:38.521004835 +0100
@@ -1484,6 +1484,12 @@
 		}
 		break;
 
+	case EEXIST:
+		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+		    "fsid_guid is invalid or already in use"));
+		(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+		break;
+
 	case EOVERFLOW:
 		/*
 		 * This platform can't address a volume this big.
@@ -2493,6 +2499,7 @@
 		break;
 
 	case ZFS_PROP_GUID:
+	case ZFS_PROP_FSID_GUID:
 		/*
 		 * GUIDs are stored as numbers, but they are identifiers.
 		 * We don't want them to be pretty printed, because pretty
@@ -3278,6 +3285,11 @@
 			    "pool must be upgraded to set this "
 			    "property or value"));
 			return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
+
+		case EEXIST:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "fsid_guid is invalid or already in use"));
+			return (zfs_error(hdl, EZFS_BADPROP, errbuf));
 #ifdef _ILP32
 		case EOVERFLOW:
 			/*
--- old/usr/src/man/man1m/zfs.1m	2015-11-02 01:49:38.883808205 +0100
+++ new/usr/src/man/man1m/zfs.1m	2015-11-02 01:49:38.896164922 +0100
@@ -1061,6 +1061,14 @@
 .Po see
 .Xr zpool-features 5
 .Pc .
+.It Sy fsid_guid Ns = Ns Sy value Ns
+Sets the dataset fsid_guid. The fsid_guid is a 64-bit unsigned integer, used to
+construct the vfs id when mounting a dataset.
+This property should only be set if you need the vfs id to be identical on two
+systems, for example in a NFS migration scenario.
+When the fsid_guid is changed for a file system, the file system and any
+children that inherit the mountpoint are unmounted, then remounted. If the
+file system was shared, existing NFS clients will require a remount.
 .It Sy mountpoint Ns = Ns Pa path Ns | Ns Sy none Ns | Ns Sy legacy
 Controls the mount point used for this file system. See the
 .Sx Mount Points
--- old/usr/src/uts/common/fs/zfs/dsl_dataset.c	2015-11-02 01:49:39.565357053 +0100
+++ new/usr/src/uts/common/fs/zfs/dsl_dataset.c	2015-11-02 01:49:39.577046516 +0100
@@ -1798,6 +1798,8 @@
 	    ds->ds_reserved);
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID,
 	    dsl_dataset_phys(ds)->ds_guid);
+	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_FSID_GUID,
+	    dsl_dataset_phys(ds)->ds_fsid_guid);
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE,
 	    dsl_dataset_phys(ds)->ds_unique_bytes);
 	dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID,
@@ -3505,3 +3507,71 @@
 	    zap_contains(ds->ds_dir->dd_pool->dp_meta_objset,
 	    ds->ds_object, DS_FIELD_RESUME_TOGUID) == 0);
 }
+
+typedef struct dsl_dataset_set_fsid_guid_arg {
+	const char *ddsfg_name;
+	uint64_t ddsfg_value;
+} dsl_dataset_set_fsid_guid_arg_t;
+
+static int
+dsl_dataset_set_fsid_guid_check(void *arg, dmu_tx_t *tx)
+{
+	int err = 0;
+	dsl_dataset_set_fsid_guid_arg_t *ddsfg = arg;
+	dsl_pool_t *dp = dmu_tx_pool(tx);
+	dsl_dataset_t *ds;
+	uint64_t newval;
+
+	newval = ddsfg->ddsfg_value;
+
+	err = dsl_dataset_hold(dp, ddsfg->ddsfg_name, FTAG, &ds);
+	if (err != 0)
+		return (err);
+
+	/* Check if the FS is mounted */
+	if (ds->ds_owner != NULL) {
+		dsl_dataset_rele(ds, FTAG);
+		return (SET_ERROR(EBUSY));
+	}
+	dsl_dataset_rele(ds, FTAG);
+
+	if (!unique_valid(newval))
+		return (SET_ERROR(EEXIST));
+
+	return (err);
+}
+
+static void
+dsl_dataset_set_fsid_guid_sync(void *arg, dmu_tx_t *tx)
+{
+	dsl_dataset_set_fsid_guid_arg_t *ddsfg = arg;
+	dsl_pool_t *dp = dmu_tx_pool(tx);
+	dsl_dataset_t *ds;
+	uint64_t newval;
+
+	VERIFY0(dsl_dataset_hold(dp, ddsfg->ddsfg_name, FTAG, &ds));
+
+	newval = ddsfg->ddsfg_value;
+
+	dmu_buf_will_dirty(ds->ds_dbuf, tx);
+	mutex_enter(&ds->ds_lock);
+	ds->ds_fsid_guid = newval;
+	dsl_dataset_phys(ds)->ds_fsid_guid = newval;
+	mutex_exit(&ds->ds_lock);
+
+	dsl_dataset_rele(ds, FTAG);
+}
+
+int
+dsl_dataset_set_fsid_guid(const char *ddname, zprop_source_t source,
+    uint64_t fsid_guid)
+{
+	dsl_dataset_set_fsid_guid_arg_t ddsfg;
+
+	ddsfg.ddsfg_name = ddname;
+	ddsfg.ddsfg_value = fsid_guid;
+
+	return (dsl_sync_task(ddname, dsl_dataset_set_fsid_guid_check,
+	    dsl_dataset_set_fsid_guid_sync, &ddsfg, 0,
+	    ZFS_SPACE_CHECK_RESERVED));
+}
--- old/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	2015-11-02 01:49:39.924403148 +0100
+++ new/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	2015-11-02 01:49:39.936051915 +0100
@@ -339,6 +339,8 @@
 boolean_t dsl_dataset_is_zapified(dsl_dataset_t *ds);
 boolean_t dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds);
 int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result);
+int dsl_dataset_set_fsid_guid(const char *ddname, zprop_source_t source,
+    uint64_t fsid_guid);
 
 void dsl_dataset_deactivate_feature(uint64_t dsobj,
     spa_feature_t f, dmu_tx_t *tx);
--- old/usr/src/uts/common/fs/zfs/sys/unique.h	2015-11-02 01:49:40.207842795 +0100
+++ new/usr/src/uts/common/fs/zfs/sys/unique.h	2015-11-02 01:49:40.219649561 +0100
@@ -47,6 +47,12 @@
 /* Return a unique value, which equals the one passed in if possible. */
 uint64_t unique_insert(uint64_t value);
 
+/*
+ * Return B_TRUE if the passed value does not exist and is valid,
+ * B_FALSE otherwise
+ */
+boolean_t unique_valid(uint64_t value);
+
 /* Indicate that this value no longer needs to be uniquified against. */
 void unique_remove(uint64_t value);
 
--- old/usr/src/uts/common/fs/zfs/unique.c	2015-11-02 01:49:40.490314472 +0100
+++ new/usr/src/uts/common/fs/zfs/unique.c	2015-11-02 01:49:40.501836115 +0100
@@ -99,6 +99,21 @@
 	return (un->un_value);
 }
 
+boolean_t
+unique_valid(uint64_t value)
+{
+	unique_t un_tofind;
+
+	un_tofind.un_value = value;
+
+	mutex_enter(&unique_mtx);
+	boolean_t rv = ((value & ~UNIQUE_MASK) == 0 &&
+	    avl_find(&unique_avl, &un_tofind, NULL) == NULL);
+	mutex_exit(&unique_mtx);
+
+	return (rv);
+}
+
 void
 unique_remove(uint64_t value)
 {
--- old/usr/src/uts/common/fs/zfs/zfs_ioctl.c	2015-11-02 01:49:40.774695690 +0100
+++ new/usr/src/uts/common/fs/zfs/zfs_ioctl.c	2015-11-02 01:49:40.786693537 +0100
@@ -2404,6 +2404,9 @@
 	VERIFY(0 == nvpair_value_uint64(pair, &intval));
 
 	switch (prop) {
+	case ZFS_PROP_FSID_GUID:
+		err = dsl_dataset_set_fsid_guid(dsname, source, intval);
+		break;
 	case ZFS_PROP_QUOTA:
 		err = dsl_dir_set_quota(dsname, source, intval);
 		break;
--- old/usr/src/uts/common/sys/fs/zfs.h	2015-11-02 01:49:41.175612774 +0100
+++ new/usr/src/uts/common/sys/fs/zfs.h	2015-11-02 01:49:41.187593322 +0100
@@ -149,6 +149,7 @@
 	ZFS_PROP_REDUNDANT_METADATA,
 	ZFS_PROP_PREV_SNAP,
 	ZFS_PROP_RECEIVE_RESUME_TOKEN,
+	ZFS_PROP_FSID_GUID,
 	ZFS_NUM_PROPS
 } zfs_prop_t;
 
