Skip to content

Commit

Permalink
7446 zpool create should support efi system partition
Browse files Browse the repository at this point in the history
Reviewed by: Andrew Stormont <[email protected]>
Reviewed by: Yuri Pankov <[email protected]>
Approved by: Dan McDonald <[email protected]>
  • Loading branch information
tsoome authored and Dan McDonald committed May 17, 2017
1 parent 859ddda commit 7855d95
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 62 deletions.
11 changes: 10 additions & 1 deletion usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t isdisk)
uint64_t offline = 0ULL;
char *physpath = NULL;
char rawpath[PATH_MAX], fullpath[PATH_MAX];
zpool_boot_label_t boot_type;
uint64_t boot_size;
size_t len;

if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
Expand Down Expand Up @@ -220,7 +222,14 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t isdisk)
len = strlen(rawpath);
rawpath[len - 2] = '\0';

if (zpool_label_disk(g_zfshdl, zhp, rawpath) != 0) {
if (zpool_is_bootable(zhp))
boot_type = ZPOOL_COPY_BOOT_LABEL;
else
boot_type = ZPOOL_NO_BOOT_LABEL;

boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
if (zpool_label_disk(g_zfshdl, zhp, rawpath,
boot_type, boot_size, NULL) != 0) {
(void) zpool_vdev_online(zhp, fullpath,
ZFS_ONLINE_FORCEFAULT, &newstate);
return;
Expand Down
91 changes: 85 additions & 6 deletions usr/src/cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ get_usage(zpool_help_t idx)
case HELP_CLEAR:
return (gettext("\tclear [-nF] <pool> [device]\n"));
case HELP_CREATE:
return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
return (gettext("\tcreate [-fnd] [-B] "
"[-o property=value] ... \n"
"\t [-O file-system-property=value] ... \n"
"\t [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
case HELP_DESTROY:
Expand Down Expand Up @@ -496,6 +497,8 @@ zpool_do_add(int argc, char **argv)
int c;
nvlist_t *nvroot;
char *poolname;
zpool_boot_label_t boot_type;
uint64_t boot_size;
int ret;
zpool_handle_t *zhp;
nvlist_t *config;
Expand Down Expand Up @@ -544,9 +547,15 @@ zpool_do_add(int argc, char **argv)
return (1);
}

if (zpool_is_bootable(zhp))
boot_type = ZPOOL_COPY_BOOT_LABEL;
else
boot_type = ZPOOL_NO_BOOT_LABEL;

/* pass off to get_vdev_spec for processing */
boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
argc, argv);
boot_type, boot_size, argc, argv);
if (nvroot == NULL) {
zpool_close(zhp);
return (1);
Expand Down Expand Up @@ -767,10 +776,11 @@ zpool_do_labelclear(int argc, char **argv)
}

/*
* zpool create [-fnd] [-o property=value] ...
* zpool create [-fnd] [-B] [-o property=value] ...
* [-O file-system-property=value] ...
* [-R root] [-m mountpoint] <pool> <dev> ...
*
* -B Create boot partition.
* -f Force creation, even if devices appear in use
* -n Do not create the pool, but display the resulting layout if it
* were to be created.
Expand All @@ -787,12 +797,16 @@ zpool_do_labelclear(int argc, char **argv)
* we get the nvlist back from get_vdev_spec(), we either print out the contents
* (if '-n' was specified), or pass it to libzfs to do the creation.
*/

#define SYSTEM256 (256 * 1024 * 1024)
int
zpool_do_create(int argc, char **argv)
{
boolean_t force = B_FALSE;
boolean_t dryrun = B_FALSE;
boolean_t enable_all_pool_feat = B_TRUE;
zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL;
uint64_t boot_size = 0;
int c;
nvlist_t *nvroot = NULL;
char *poolname;
Expand All @@ -804,7 +818,7 @@ zpool_do_create(int argc, char **argv)
char *propval;

/* check options */
while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) {
while ((c = getopt(argc, argv, ":fndBR:m:o:O:")) != -1) {
switch (c) {
case 'f':
force = B_TRUE;
Expand All @@ -815,6 +829,15 @@ zpool_do_create(int argc, char **argv)
case 'd':
enable_all_pool_feat = B_FALSE;
break;
case 'B':
/*
* We should create the system partition.
* Also make sure the size is set.
*/
boot_type = ZPOOL_CREATE_BOOT_LABEL;
if (boot_size == 0)
boot_size = SYSTEM256;
break;
case 'R':
altroot = optarg;
if (add_prop_list(zpool_prop_to_name(
Expand Down Expand Up @@ -844,6 +867,20 @@ zpool_do_create(int argc, char **argv)
if (add_prop_list(optarg, propval, &props, B_TRUE))
goto errout;

/*
* Get bootsize value for make_root_vdev().
*/
if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) {
if (zfs_nicestrtonum(g_zfs, propval,
&boot_size) < 0 || boot_size == 0) {
(void) fprintf(stderr,
gettext("bad boot partition size "
"'%s': %s\n"), propval,
libzfs_error_description(g_zfs));
goto errout;
}
}

/*
* If the user is creating a pool that doesn't support
* feature flags, don't enable any features.
Expand Down Expand Up @@ -921,9 +958,43 @@ zpool_do_create(int argc, char **argv)
goto errout;
}

/*
* Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used,
* and not set otherwise.
*/
if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
const char *propname;
char *strptr, *buf = NULL;
int rv;

propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
if (nvlist_lookup_string(props, propname, &strptr) != 0) {
(void) asprintf(&buf, "%" PRIu64, boot_size);
if (buf == NULL) {
(void) fprintf(stderr,
gettext("internal error: out of memory\n"));
goto errout;
}
rv = add_prop_list(propname, buf, &props, B_TRUE);
free(buf);
if (rv != 0)
goto errout;
}
} else {
const char *propname;
char *strptr;

propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
if (nvlist_lookup_string(props, propname, &strptr) == 0) {
(void) fprintf(stderr, gettext("error: setting boot "
"partition size requires option '-B'\n"));
goto errout;
}
}

/* pass off to get_vdev_spec for bulk processing */
nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
argc - 1, argv + 1);
boot_type, boot_size, argc - 1, argv + 1);
if (nvroot == NULL)
goto errout;

Expand Down Expand Up @@ -3183,6 +3254,8 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
nvlist_t *nvroot;
char *poolname, *old_disk, *new_disk;
zpool_handle_t *zhp;
zpool_boot_label_t boot_type;
uint64_t boot_size;
int ret;

/* check options */
Expand Down Expand Up @@ -3247,8 +3320,14 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
return (1);
}

if (zpool_is_bootable(zhp))
boot_type = ZPOOL_COPY_BOOT_LABEL;
else
boot_type = ZPOOL_NO_BOOT_LABEL;

boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
argc, argv);
boot_type, boot_size, argc, argv);
if (nvroot == NULL) {
zpool_close(zhp);
return (1);
Expand Down
3 changes: 2 additions & 1 deletion usr/src/cmd/zpool/zpool_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ uint_t num_logs(nvlist_t *nv);
*/

nvlist_t *make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
boolean_t replacing, boolean_t dryrun, int argc, char **argv);
boolean_t replacing, boolean_t dryrun, zpool_boot_label_t boot_type,
uint64_t boot_size, int argc, char **argv);
nvlist_t *split_mirror_vdev(zpool_handle_t *zhp, char *newname,
nvlist_t *props, splitflags_t flags, int argc, char **argv);

Expand Down
77 changes: 59 additions & 18 deletions usr/src/cmd/zpool/zpool_vdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -876,14 +876,15 @@ check_replication(nvlist_t *config, nvlist_t *newroot)
* Go through and find any whole disks in the vdev specification, labelling them
* as appropriate. When constructing the vdev spec, we were unable to open this
* device in order to provide a devid. Now that we have labelled the disk and
* know that slice 0 is valid, we can construct the devid now.
* know the pool slice is valid, we can construct the devid now.
*
* If the disk was already labeled with an EFI label, we will have gotten the
* devid already (because we were able to open the whole disk). Otherwise, we
* need to get the devid after we label the disk.
*/
static int
make_disks(zpool_handle_t *zhp, nvlist_t *nv)
make_disks(zpool_handle_t *zhp, nvlist_t *nv, zpool_boot_label_t boot_type,
uint64_t boot_size)
{
nvlist_t **child;
uint_t c, children;
Expand All @@ -892,6 +893,7 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
uint64_t wholedisk;
int fd;
int ret;
int slice;
ddi_devid_t devid;
char *minor = NULL, *devid_str = NULL;

Expand All @@ -909,20 +911,36 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
* slice and stat()ing the device.
*/
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
&wholedisk) != 0 || !wholedisk)
return (0);

diskname = strrchr(path, '/');
assert(diskname != NULL);
diskname++;
if (zpool_label_disk(g_zfs, zhp, diskname) == -1)
return (-1);

if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
&wholedisk) != 0 || !wholedisk) {
/*
* This is not whole disk, return error if
* boot partition creation was requested
*/
if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
(void) fprintf(stderr,
gettext("creating boot partition is only "
"supported on whole disk vdevs: %s\n"),
diskname);
return (-1);
}
return (0);
}

ret = zpool_label_disk(g_zfs, zhp, diskname, boot_type,
boot_size, &slice);
if (ret == -1)
return (ret);

/*
* Fill in the devid, now that we've labeled the disk.
*/
(void) snprintf(buf, sizeof (buf), "%ss0", path);
(void) snprintf(buf, sizeof (buf), "%ss%d", path, slice);
if ((fd = open(buf, O_RDONLY)) < 0) {
(void) fprintf(stderr,
gettext("cannot open '%s': %s\n"),
Expand All @@ -945,7 +963,7 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
}

/*
* Update the path to refer to the 's0' slice. The presence of
* Update the path to refer to the pool slice. The presence of
* the 'whole_disk' field indicates to the CLI that we should
* chop off the slice number when displaying the device in
* future output.
Expand All @@ -957,21 +975,36 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
return (0);
}

for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c])) != 0)
/* illumos kernel does not support booting from multi-vdev pools. */
if ((boot_type == ZPOOL_CREATE_BOOT_LABEL)) {
if ((strcmp(type, VDEV_TYPE_ROOT) == 0) && children > 1) {
(void) fprintf(stderr, gettext("boot pool "
"can not have more than one vdev\n"));
return (-1);
}
}

for (c = 0; c < children; c++) {
ret = make_disks(zhp, child[c], boot_type, boot_size);
if (ret != 0)
return (ret);
}

if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
&child, &children) == 0)
for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c])) != 0)
for (c = 0; c < children; c++) {
ret = make_disks(zhp, child[c], boot_type, boot_size);
if (ret != 0)
return (ret);
}

if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
&child, &children) == 0)
for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c])) != 0)
for (c = 0; c < children; c++) {
ret = make_disks(zhp, child[c], boot_type, boot_size);
if (ret != 0)
return (ret);
}

return (0);
}
Expand Down Expand Up @@ -1367,6 +1400,7 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
{
nvlist_t *newroot = NULL, **child;
uint_t c, children;
zpool_boot_label_t boot_type;

if (argc > 0) {
if ((newroot = construct_spec(argc, argv)) == NULL) {
Expand All @@ -1375,7 +1409,13 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
return (NULL);
}

if (!flags.dryrun && make_disks(zhp, newroot) != 0) {
if (zpool_is_bootable(zhp))
boot_type = ZPOOL_COPY_BOOT_LABEL;
else
boot_type = ZPOOL_NO_BOOT_LABEL;

if (!flags.dryrun &&
make_disks(zhp, newroot, boot_type, 0) != 0) {
nvlist_free(newroot);
return (NULL);
}
Expand Down Expand Up @@ -1419,7 +1459,8 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
*/
nvlist_t *
make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
boolean_t replacing, boolean_t dryrun, int argc, char **argv)
boolean_t replacing, boolean_t dryrun, zpool_boot_label_t boot_type,
uint64_t boot_size, int argc, char **argv)
{
nvlist_t *newroot;
nvlist_t *poolconfig = NULL;
Expand Down Expand Up @@ -1460,7 +1501,7 @@ make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
/*
* Run through the vdev specification and label any whole disks found.
*/
if (!dryrun && make_disks(zhp, newroot) != 0) {
if (!dryrun && make_disks(zhp, newroot, boot_type, boot_size) != 0) {
nvlist_free(newroot);
return (NULL);
}
Expand Down
4 changes: 4 additions & 0 deletions usr/src/common/zfs/zpool_prop.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ zpool_prop_init(void)
PROP_READONLY, ZFS_TYPE_POOL, "<1.00x or higher if deduped>",
"DEDUP");

/* system partition size */
zprop_register_number(ZPOOL_PROP_BOOTSIZE, "bootsize", 0, PROP_ONETIME,
ZFS_TYPE_POOL, "<size>", "BOOTSIZE");

/* default number properties */
zprop_register_number(ZPOOL_PROP_VERSION, "version", SPA_VERSION,
PROP_DEFAULT, ZFS_TYPE_POOL, "<version>", "VERSION");
Expand Down
Loading

0 comments on commit 7855d95

Please sign in to comment.