Changeset View
Changeset View
Standalone View
Standalone View
lib/libbe/be.c
Show All 37 Lines | |||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <libgen.h> | #include <libgen.h> | ||||
#include <libzfs_core.h> | #include <libzfs_core.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <time.h> | #include <time.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <libzfsbootenv.h> | |||||
#include "be.h" | #include "be.h" | ||||
#include "be_impl.h" | #include "be_impl.h" | ||||
struct promote_entry { | struct promote_entry { | ||||
char name[BE_MAXPATHLEN]; | char name[BE_MAXPATHLEN]; | ||||
SLIST_ENTRY(promote_entry) link; | SLIST_ENTRY(promote_entry) link; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 1,160 Lines • ▼ Show 20 Lines | if (stat(child_path, &sb) != 0) { | ||||
return (be_create_child_noent(lbh, active, child_path)); | return (be_create_child_noent(lbh, active, child_path)); | ||||
} else if (cp_if_exists) | } else if (cp_if_exists) | ||||
/* Path is already a descendent of / and should be copied */ | /* Path is already a descendent of / and should be copied */ | ||||
return (be_create_child_cloned(lbh, active)); | return (be_create_child_cloned(lbh, active)); | ||||
return (set_error(lbh, BE_ERR_EXISTS)); | return (set_error(lbh, BE_ERR_EXISTS)); | ||||
} | } | ||||
#endif /* SOON */ | #endif /* SOON */ | ||||
static int | |||||
be_set_nextboot(libbe_handle_t *lbh, nvlist_t *config, uint64_t pool_guid, | |||||
const char *zfsdev) | |||||
{ | |||||
nvlist_t **child; | |||||
uint64_t vdev_guid; | |||||
int c, children; | |||||
if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, &child, | |||||
&children) == 0) { | |||||
for (c = 0; c < children; ++c) | |||||
if (be_set_nextboot(lbh, child[c], pool_guid, zfsdev) != 0) | |||||
return (1); | |||||
return (0); | |||||
} | |||||
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, | |||||
&vdev_guid) != 0) { | |||||
return (1); | |||||
} | |||||
if (zpool_nextboot(lbh->lzh, pool_guid, vdev_guid, zfsdev) != 0) { | |||||
perror("ZFS_IOC_NEXTBOOT failed"); | |||||
return (1); | |||||
} | |||||
return (0); | |||||
} | |||||
/* | /* | ||||
* Deactivate old BE dataset; currently just sets canmount=noauto | * Deactivate old BE dataset; currently just sets canmount=noauto or | ||||
* resets boot once configuration. | |||||
*/ | */ | ||||
static int | int | ||||
be_deactivate(libbe_handle_t *lbh, const char *ds) | be_deactivate(libbe_handle_t *lbh, const char *ds, bool temporary) | ||||
{ | { | ||||
zfs_handle_t *zfs; | zfs_handle_t *zfs; | ||||
if (temporary) { | |||||
return (lzbe_set_boot_device( | |||||
kevans: I somewhat wonder if we should check if bootonce was set and return a special error to indicate… | |||||
Done Inline ActionsI am not really sure if we should care about if bootonce was set or not; we might just want to ensure we do have sane state on disk -- for example when the bootenv area was not cleared on pool creation, or some unsupported state was stored. tsoome: I am not really sure if we should care about if bootonce was set or not; we might just want to… | |||||
zpool_get_name(lbh->active_phandle), NULL)); | |||||
} | |||||
if ((zfs = zfs_open(lbh->lzh, ds, ZFS_TYPE_DATASET)) == NULL) | if ((zfs = zfs_open(lbh->lzh, ds, ZFS_TYPE_DATASET)) == NULL) | ||||
return (1); | return (1); | ||||
if (zfs_prop_set(zfs, "canmount", "noauto") != 0) | if (zfs_prop_set(zfs, "canmount", "noauto") != 0) | ||||
return (1); | return (1); | ||||
zfs_close(zfs); | zfs_close(zfs); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
be_activate(libbe_handle_t *lbh, const char *bootenv, bool temporary) | be_activate(libbe_handle_t *lbh, const char *bootenv, bool temporary) | ||||
{ | { | ||||
char be_path[BE_MAXPATHLEN]; | char be_path[BE_MAXPATHLEN]; | ||||
char buf[BE_MAXPATHLEN]; | nvlist_t *dsprops; | ||||
nvlist_t *config, *dsprops, *vdevs; | |||||
char *origin; | char *origin; | ||||
uint64_t pool_guid; | |||||
zfs_handle_t *zhp; | zfs_handle_t *zhp; | ||||
int err; | int err; | ||||
be_root_concat(lbh, bootenv, be_path); | be_root_concat(lbh, bootenv, be_path); | ||||
/* Note: be_exists fails if mountpoint is not / */ | /* Note: be_exists fails if mountpoint is not / */ | ||||
if ((err = be_exists(lbh, be_path)) != 0) | if ((err = be_exists(lbh, be_path)) != 0) | ||||
return (set_error(lbh, err)); | return (set_error(lbh, err)); | ||||
if (temporary) { | if (temporary) { | ||||
config = zpool_get_config(lbh->active_phandle, NULL); | return (lzbe_set_boot_device( | ||||
if (config == NULL) | zpool_get_name(lbh->active_phandle), be_path)); | ||||
/* config should be fetchable... */ | |||||
return (set_error(lbh, BE_ERR_UNKNOWN)); | |||||
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, | |||||
&pool_guid) != 0) | |||||
/* Similarly, it shouldn't be possible */ | |||||
return (set_error(lbh, BE_ERR_UNKNOWN)); | |||||
/* Expected format according to zfsbootcfg(8) man */ | |||||
snprintf(buf, sizeof(buf), "zfs:%s:", be_path); | |||||
/* We have no config tree */ | |||||
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, | |||||
&vdevs) != 0) | |||||
return (set_error(lbh, BE_ERR_NOPOOL)); | |||||
return (be_set_nextboot(lbh, vdevs, pool_guid, buf)); | |||||
} else { | } else { | ||||
if (be_deactivate(lbh, lbh->bootfs) != 0) | if (be_deactivate(lbh, lbh->bootfs, false) != 0) | ||||
return (-1); | return (-1); | ||||
/* Obtain bootenv zpool */ | /* Obtain bootenv zpool */ | ||||
err = zpool_set_prop(lbh->active_phandle, "bootfs", be_path); | err = zpool_set_prop(lbh->active_phandle, "bootfs", be_path); | ||||
if (err) | if (err) | ||||
return (-1); | return (-1); | ||||
zhp = zfs_open(lbh->lzh, be_path, ZFS_TYPE_FILESYSTEM); | zhp = zfs_open(lbh->lzh, be_path, ZFS_TYPE_FILESYSTEM); | ||||
Show All 23 Lines |
I somewhat wonder if we should check if bootonce was set and return a special error to indicate that's the case here and let the caller decide if that's a problem or not, but I don't insist and can always revise later if we decide to care.