Skip to content

Commit b53077a

Browse files
authored
Add zfs_prepare_disk script for disk firmware install
Have libzfs call a special `zfs_prepare_disk` script before a disk is included into the pool. The user can edit this script to add things like a disk firmware update or a disk health check. Use of the script is totally optional. See the zfs_prepare_disk manpage for full details. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Tony Hutter <[email protected]> Closes openzfs#15243
1 parent 4647353 commit b53077a

File tree

14 files changed

+388
-35
lines changed

14 files changed

+388
-35
lines changed

cmd/zed/agents/zfs_mod.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,17 @@ zfs_unavail_pool(zpool_handle_t *zhp, void *data)
146146
return (0);
147147
}
148148

149+
/*
150+
* Write an array of strings to the zed log
151+
*/
152+
static void lines_to_zed_log_msg(char **lines, int lines_cnt)
153+
{
154+
int i;
155+
for (i = 0; i < lines_cnt; i++) {
156+
zed_log_msg(LOG_INFO, "%s", lines[i]);
157+
}
158+
}
159+
149160
/*
150161
* Two stage replace on Linux
151162
* since we get disk notifications
@@ -200,6 +211,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
200211
boolean_t is_mpath_wholedisk = B_FALSE;
201212
uint_t c;
202213
vdev_stat_t *vs;
214+
char **lines = NULL;
215+
int lines_cnt = 0;
203216

204217
if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
205218
return;
@@ -383,6 +396,22 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
383396

384397
if (is_mpath_wholedisk) {
385398
/* Don't label device mapper or multipath disks. */
399+
zed_log_msg(LOG_INFO,
400+
" it's a multipath wholedisk, don't label");
401+
if (zpool_prepare_disk(zhp, vdev, "autoreplace", &lines,
402+
&lines_cnt) != 0) {
403+
zed_log_msg(LOG_INFO,
404+
" zpool_prepare_disk: could not "
405+
"prepare '%s' (%s)", fullpath,
406+
libzfs_error_description(g_zfshdl));
407+
if (lines_cnt > 0) {
408+
zed_log_msg(LOG_INFO,
409+
" zfs_prepare_disk output:");
410+
lines_to_zed_log_msg(lines, lines_cnt);
411+
}
412+
libzfs_free_str_array(lines, lines_cnt);
413+
return;
414+
}
386415
} else if (!labeled) {
387416
/*
388417
* we're auto-replacing a raw disk, so label it first
@@ -405,10 +434,18 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
405434
* If this is a request to label a whole disk, then attempt to
406435
* write out the label.
407436
*/
408-
if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
409-
zed_log_msg(LOG_INFO, " zpool_label_disk: could not "
437+
if (zpool_prepare_and_label_disk(g_zfshdl, zhp, leafname,
438+
vdev, "autoreplace", &lines, &lines_cnt) != 0) {
439+
zed_log_msg(LOG_INFO,
440+
" zpool_prepare_and_label_disk: could not "
410441
"label '%s' (%s)", leafname,
411442
libzfs_error_description(g_zfshdl));
443+
if (lines_cnt > 0) {
444+
zed_log_msg(LOG_INFO,
445+
" zfs_prepare_disk output:");
446+
lines_to_zed_log_msg(lines, lines_cnt);
447+
}
448+
libzfs_free_str_array(lines, lines_cnt);
412449

413450
(void) zpool_vdev_online(zhp, fullpath,
414451
ZFS_ONLINE_FORCEFAULT, &newstate);
@@ -468,6 +505,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
468505
DEV_BYID_PATH, new_devid);
469506
}
470507

508+
libzfs_free_str_array(lines, lines_cnt);
509+
471510
/*
472511
* Construct the root vdev to pass to zpool_vdev_attach(). While adding
473512
* the entire vdev structure is harmless, we construct a reduced set of

cmd/zpool/zpool_iter.c

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -443,37 +443,22 @@ vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
443443
{
444444
int rc;
445445
char *argv[2] = {cmd};
446-
char *env[5] = {(char *)"PATH=/bin:/sbin:/usr/bin:/usr/sbin"};
446+
char **env;
447447
char **lines = NULL;
448448
int lines_cnt = 0;
449449
int i;
450450

451-
/* Setup our custom environment variables */
452-
rc = asprintf(&env[1], "VDEV_PATH=%s",
453-
data->path ? data->path : "");
454-
if (rc == -1) {
455-
env[1] = NULL;
451+
env = zpool_vdev_script_alloc_env(data->pool, data->path, data->upath,
452+
data->vdev_enc_sysfs_path, NULL, NULL);
453+
if (env == NULL)
456454
goto out;
457-
}
458-
459-
rc = asprintf(&env[2], "VDEV_UPATH=%s",
460-
data->upath ? data->upath : "");
461-
if (rc == -1) {
462-
env[2] = NULL;
463-
goto out;
464-
}
465-
466-
rc = asprintf(&env[3], "VDEV_ENC_SYSFS_PATH=%s",
467-
data->vdev_enc_sysfs_path ?
468-
data->vdev_enc_sysfs_path : "");
469-
if (rc == -1) {
470-
env[3] = NULL;
471-
goto out;
472-
}
473455

474456
/* Run the command */
475457
rc = libzfs_run_process_get_stdout_nopath(cmd, argv, env, &lines,
476458
&lines_cnt);
459+
460+
zpool_vdev_script_free_env(env);
461+
477462
if (rc != 0)
478463
goto out;
479464

@@ -485,10 +470,6 @@ vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
485470
out:
486471
if (lines != NULL)
487472
libzfs_free_str_array(lines, lines_cnt);
488-
489-
/* Start with i = 1 since env[0] was statically allocated */
490-
for (i = 1; i < ARRAY_SIZE(env); i++)
491-
free(env[i]);
492473
}
493474

494475
/*

cmd/zpool/zpool_util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ vdev_cmd_data_list_t *all_pools_for_each_vdev_run(int argc, char **argv,
126126

127127
void free_vdev_cmd_data_list(vdev_cmd_data_list_t *vcdl);
128128

129+
void free_vdev_cmd_data(vdev_cmd_data_t *data);
130+
131+
int vdev_run_cmd_simple(char *path, char *cmd);
132+
129133
int check_device(const char *path, boolean_t force,
130134
boolean_t isspare, boolean_t iswholedisk);
131135
boolean_t check_sector_size_database(char *path, int *sector_size);

cmd/zpool/zpool_vdev.c

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,15 @@ zero_label(const char *path)
936936
return (0);
937937
}
938938

939+
static void
940+
lines_to_stderr(char *lines[], int lines_cnt)
941+
{
942+
int i;
943+
for (i = 0; i < lines_cnt; i++) {
944+
fprintf(stderr, "%s\n", lines[i]);
945+
}
946+
}
947+
939948
/*
940949
* Go through and find any whole disks in the vdev specification, labelling them
941950
* as appropriate. When constructing the vdev spec, we were unable to open this
@@ -947,7 +956,7 @@ zero_label(const char *path)
947956
* need to get the devid after we label the disk.
948957
*/
949958
static int
950-
make_disks(zpool_handle_t *zhp, nvlist_t *nv)
959+
make_disks(zpool_handle_t *zhp, nvlist_t *nv, boolean_t replacing)
951960
{
952961
nvlist_t **child;
953962
uint_t c, children;
@@ -1032,6 +1041,8 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
10321041
*/
10331042
if (!is_exclusive && !is_spare(NULL, udevpath)) {
10341043
char *devnode = strrchr(devpath, '/') + 1;
1044+
char **lines = NULL;
1045+
int lines_cnt = 0;
10351046

10361047
ret = strncmp(udevpath, UDISK_ROOT, strlen(UDISK_ROOT));
10371048
if (ret == 0) {
@@ -1043,9 +1054,27 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
10431054
/*
10441055
* When labeling a pool the raw device node name
10451056
* is provided as it appears under /dev/.
1057+
*
1058+
* Note that 'zhp' will be NULL when we're creating a
1059+
* pool.
10461060
*/
1047-
if (zpool_label_disk(g_zfs, zhp, devnode) == -1)
1061+
if (zpool_prepare_and_label_disk(g_zfs, zhp, devnode,
1062+
nv, zhp == NULL ? "create" :
1063+
replacing ? "replace" : "add", &lines,
1064+
&lines_cnt) != 0) {
1065+
(void) fprintf(stderr,
1066+
gettext(
1067+
"Error preparing/labeling disk.\n"));
1068+
if (lines_cnt > 0) {
1069+
(void) fprintf(stderr,
1070+
gettext("zfs_prepare_disk output:\n"));
1071+
lines_to_stderr(lines, lines_cnt);
1072+
}
1073+
1074+
libzfs_free_str_array(lines, lines_cnt);
10481075
return (-1);
1076+
}
1077+
libzfs_free_str_array(lines, lines_cnt);
10491078

10501079
/*
10511080
* Wait for udev to signal the device is available
@@ -1082,19 +1111,19 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
10821111
}
10831112

10841113
for (c = 0; c < children; c++)
1085-
if ((ret = make_disks(zhp, child[c])) != 0)
1114+
if ((ret = make_disks(zhp, child[c], replacing)) != 0)
10861115
return (ret);
10871116

10881117
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
10891118
&child, &children) == 0)
10901119
for (c = 0; c < children; c++)
1091-
if ((ret = make_disks(zhp, child[c])) != 0)
1120+
if ((ret = make_disks(zhp, child[c], replacing)) != 0)
10921121
return (ret);
10931122

10941123
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
10951124
&child, &children) == 0)
10961125
for (c = 0; c < children; c++)
1097-
if ((ret = make_disks(zhp, child[c])) != 0)
1126+
if ((ret = make_disks(zhp, child[c], replacing)) != 0)
10981127
return (ret);
10991128

11001129
return (0);
@@ -1752,7 +1781,7 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
17521781
return (NULL);
17531782
}
17541783

1755-
if (!flags.dryrun && make_disks(zhp, newroot) != 0) {
1784+
if (!flags.dryrun && make_disks(zhp, newroot, B_FALSE) != 0) {
17561785
nvlist_free(newroot);
17571786
return (NULL);
17581787
}
@@ -1873,7 +1902,7 @@ make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, int force, int check_rep,
18731902
/*
18741903
* Run through the vdev specification and label any whole disks found.
18751904
*/
1876-
if (!dryrun && make_disks(zhp, newroot) != 0) {
1905+
if (!dryrun && make_disks(zhp, newroot, replacing) != 0) {
18771906
nvlist_free(newroot);
18781907
return (NULL);
18791908
}

config/Rules.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ AM_CPPFLAGS += -D_REENTRANT
3333
AM_CPPFLAGS += -D_FILE_OFFSET_BITS=64
3434
AM_CPPFLAGS += -D_LARGEFILE64_SOURCE
3535
AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\"
36+
AM_CPPFLAGS += -DZFSEXECDIR=\"$(zfsexecdir)\"
3637
AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\"
3738
AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\"
3839
AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\"

contrib/debian/openzfs-zfsutils.install

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ usr/bin/zvol_wait
3535
usr/lib/modules-load.d/ lib/
3636
usr/lib/zfs-linux/zpool.d/
3737
usr/lib/zfs-linux/zpool_influxdb
38+
usr/lib/zfs-linux/zfs_prepare_disk
3839
usr/sbin/arc_summary
3940
usr/sbin/arcstat
4041
usr/sbin/dbufstat
@@ -88,6 +89,7 @@ usr/share/man/man8/zfs-wait.8
8889
usr/share/man/man8/zfs-zone.8
8990
usr/share/man/man8/zfs.8
9091
usr/share/man/man8/zfs_ids_to_path.8
92+
usr/share/man/man8/zfs_prepare_disk.8
9193
usr/share/man/man7/zfsconcepts.7
9294
usr/share/man/man7/zfsprops.7
9395
usr/share/man/man8/zgenhostid.8

include/libzfs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,15 @@ _LIBZFS_H nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
326326
boolean_t *, boolean_t *, boolean_t *);
327327
_LIBZFS_H int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *,
328328
const char *);
329+
_LIBZFS_H int zpool_prepare_disk(zpool_handle_t *zhp, nvlist_t *vdev_nv,
330+
const char *prepare_str, char **lines[], int *lines_cnt);
331+
_LIBZFS_H int zpool_prepare_and_label_disk(libzfs_handle_t *hdl,
332+
zpool_handle_t *, const char *, nvlist_t *vdev_nv, const char *prepare_str,
333+
char **lines[], int *lines_cnt);
334+
_LIBZFS_H char ** zpool_vdev_script_alloc_env(const char *pool_name,
335+
const char *vdev_path, const char *vdev_upath,
336+
const char *vdev_enc_sysfs_path, const char *opt_key, const char *opt_val);
337+
_LIBZFS_H void zpool_vdev_script_free_env(char **env);
329338
_LIBZFS_H uint64_t zpool_vdev_path_to_guid(zpool_handle_t *zhp,
330339
const char *path);
331340

lib/libzfs/libzfs.abi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@
514514
<elf-symbol name='zpool_open' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
515515
<elf-symbol name='zpool_open_canfail' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
516516
<elf-symbol name='zpool_pool_state_to_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
517+
<elf-symbol name='zpool_prepare_and_label_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
518+
<elf-symbol name='zpool_prepare_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
517519
<elf-symbol name='zpool_print_unsup_feat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
518520
<elf-symbol name='zpool_prop_align_right' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
519521
<elf-symbol name='zpool_prop_column_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -561,6 +563,8 @@
561563
<elf-symbol name='zpool_vdev_remove' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
562564
<elf-symbol name='zpool_vdev_remove_cancel' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
563565
<elf-symbol name='zpool_vdev_remove_wanted' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
566+
<elf-symbol name='zpool_vdev_script_alloc_env' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
567+
<elf-symbol name='zpool_vdev_script_free_env' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
564568
<elf-symbol name='zpool_vdev_split' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
565569
<elf-symbol name='zpool_wait' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
566570
<elf-symbol name='zpool_wait_status' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>

0 commit comments

Comments
 (0)