libbe(3): simplify import, allow replication streams

Previously, we directly used libzfs_core's lzc_receive to import to a
temporary snapshot, then cloned the snapshot and setup the properties. This
failed when attempting to import replication streams with questionable
error.

libzfs's zfs_receive is a much better fit here, so we now use it instead
with the destination dataset and let libzfs take care of the dirty details.
be_import is greatly simplified as a result.

Reported by:	Marie Helene Kvello-Aune <freebsd@mhka.no>
MFC after:	1 week
This commit is contained in:
Kyle Evans 2019-01-23 02:09:15 +00:00
parent 20694769bd
commit 16ac070581

View File

@ -649,32 +649,14 @@ int
be_import(libbe_handle_t *lbh, const char *bootenv, int fd)
{
char buf[BE_MAXPATHLEN];
time_t rawtime;
nvlist_t *props;
zfs_handle_t *zfs;
int err, len;
char nbuf[24];
recvflags_t flags = { .nomount = 1 };
int err;
/*
* We don't need this to be incredibly random, just unique enough that
* it won't conflict with an existing dataset name. Chopping time
* down to 32 bits is probably good enough for this.
*/
snprintf(nbuf, 24, "tmp%u",
(uint32_t)(time(NULL) & 0xFFFFFFFF));
if ((err = be_root_concat(lbh, nbuf, buf)) != 0)
/*
* Technically this is our problem, but we try to use short
* enough names that we won't run into problems except in
* worst-case BE root approaching MAXPATHLEN.
*/
return (set_error(lbh, BE_ERR_PATHLEN));
be_root_concat(lbh, bootenv, buf);
time(&rawtime);
len = strlen(buf);
strftime(buf + len, sizeof(buf) - len, "@%F-%T", localtime(&rawtime));
if ((err = lzc_receive(buf, NULL, NULL, false, fd)) != 0) {
if ((err = zfs_receive(lbh->lzh, buf, NULL, &flags, fd, NULL)) != 0) {
switch (err) {
case EINVAL:
return (set_error(lbh, BE_ERR_NOORIGIN));
@ -687,39 +669,22 @@ be_import(libbe_handle_t *lbh, const char *bootenv, int fd)
}
}
if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL)
if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_FILESYSTEM)) == NULL)
return (set_error(lbh, BE_ERR_ZFSOPEN));
nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
nvlist_add_string(props, "canmount", "noauto");
nvlist_add_string(props, "mountpoint", "/");
be_root_concat(lbh, bootenv, buf);
err = zfs_clone(zfs, buf, props);
zfs_close(zfs);
err = zfs_prop_set_list(zfs, props);
nvlist_free(props);
if (err != 0)
return (set_error(lbh, BE_ERR_UNKNOWN));
/*
* Finally, we open up the dataset we just cloned the snapshot so that
* we may promote it. This is necessary in order to clean up the ghost
* snapshot that doesn't need to be seen after the operation is
* complete.
*/
if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL)
return (set_error(lbh, BE_ERR_ZFSOPEN));
err = zfs_promote(zfs);
zfs_close(zfs);
if (err != 0)
return (set_error(lbh, BE_ERR_UNKNOWN));
/* Clean up the temporary snapshot */
return (be_destroy(lbh, nbuf, 0));
return (0);
}
#if SOON