mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
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 <behlendorf1@llnl.gov> Signed-off-by: Tony Hutter <hutter2@llnl.gov> Closes #15243
This commit is contained in:
committed by
Brian Behlendorf
parent
35252ae0fd
commit
11574a7934
@@ -141,6 +141,17 @@ zfs_unavail_pool(zpool_handle_t *zhp, void *data)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an array of strings to the zed log
|
||||
*/
|
||||
static void lines_to_zed_log_msg(char **lines, int lines_cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < lines_cnt; i++) {
|
||||
zed_log_msg(LOG_INFO, "%s", lines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Two stage replace on Linux
|
||||
* since we get disk notifications
|
||||
@@ -195,6 +206,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
boolean_t is_mpath_wholedisk = B_FALSE;
|
||||
uint_t c;
|
||||
vdev_stat_t *vs;
|
||||
char **lines = NULL;
|
||||
int lines_cnt = 0;
|
||||
|
||||
if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
|
||||
return;
|
||||
@@ -377,6 +390,22 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
|
||||
if (is_mpath_wholedisk) {
|
||||
/* Don't label device mapper or multipath disks. */
|
||||
zed_log_msg(LOG_INFO,
|
||||
" it's a multipath wholedisk, don't label");
|
||||
if (zpool_prepare_disk(zhp, vdev, "autoreplace", &lines,
|
||||
&lines_cnt) != 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zpool_prepare_disk: could not "
|
||||
"prepare '%s' (%s)", fullpath,
|
||||
libzfs_error_description(g_zfshdl));
|
||||
if (lines_cnt > 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zfs_prepare_disk output:");
|
||||
lines_to_zed_log_msg(lines, lines_cnt);
|
||||
}
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
return;
|
||||
}
|
||||
} else if (!labeled) {
|
||||
/*
|
||||
* we're auto-replacing a raw disk, so label it first
|
||||
@@ -399,10 +428,18 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
* If this is a request to label a whole disk, then attempt to
|
||||
* write out the label.
|
||||
*/
|
||||
if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
|
||||
zed_log_msg(LOG_INFO, " zpool_label_disk: could not "
|
||||
if (zpool_prepare_and_label_disk(g_zfshdl, zhp, leafname,
|
||||
vdev, "autoreplace", &lines, &lines_cnt) != 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zpool_prepare_and_label_disk: could not "
|
||||
"label '%s' (%s)", leafname,
|
||||
libzfs_error_description(g_zfshdl));
|
||||
if (lines_cnt > 0) {
|
||||
zed_log_msg(LOG_INFO,
|
||||
" zfs_prepare_disk output:");
|
||||
lines_to_zed_log_msg(lines, lines_cnt);
|
||||
}
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
(void) zpool_vdev_online(zhp, fullpath,
|
||||
ZFS_ONLINE_FORCEFAULT, &newstate);
|
||||
@@ -457,6 +494,8 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
|
||||
DEV_BYID_PATH, new_devid);
|
||||
}
|
||||
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
/*
|
||||
* Construct the root vdev to pass to zpool_vdev_attach(). While adding
|
||||
* the entire vdev structure is harmless, we construct a reduced set of
|
||||
|
||||
+8
-28
@@ -439,39 +439,23 @@ static void
|
||||
vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
|
||||
{
|
||||
int rc;
|
||||
char *argv[2] = {cmd, 0};
|
||||
char *env[5] = {"PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL, NULL, NULL,
|
||||
NULL};
|
||||
char *argv[2] = {cmd};
|
||||
char **env;
|
||||
char **lines = NULL;
|
||||
int lines_cnt = 0;
|
||||
int i;
|
||||
|
||||
/* Setup our custom environment variables */
|
||||
rc = asprintf(&env[1], "VDEV_PATH=%s",
|
||||
data->path ? data->path : "");
|
||||
if (rc == -1) {
|
||||
env[1] = NULL;
|
||||
env = zpool_vdev_script_alloc_env(data->pool, data->path, data->upath,
|
||||
data->vdev_enc_sysfs_path, NULL, NULL);
|
||||
if (env == NULL)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = asprintf(&env[2], "VDEV_UPATH=%s",
|
||||
data->upath ? data->upath : "");
|
||||
if (rc == -1) {
|
||||
env[2] = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = asprintf(&env[3], "VDEV_ENC_SYSFS_PATH=%s",
|
||||
data->vdev_enc_sysfs_path ?
|
||||
data->vdev_enc_sysfs_path : "");
|
||||
if (rc == -1) {
|
||||
env[3] = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Run the command */
|
||||
rc = libzfs_run_process_get_stdout_nopath(cmd, argv, env, &lines,
|
||||
&lines_cnt);
|
||||
|
||||
zpool_vdev_script_free_env(env);
|
||||
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
@@ -483,10 +467,6 @@ vdev_run_cmd(vdev_cmd_data_t *data, char *cmd)
|
||||
out:
|
||||
if (lines != NULL)
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
/* Start with i = 1 since env[0] was statically allocated */
|
||||
for (i = 1; i < ARRAY_SIZE(env); i++)
|
||||
free(env[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -124,6 +124,10 @@ vdev_cmd_data_list_t *all_pools_for_each_vdev_run(int argc, char **argv,
|
||||
|
||||
void free_vdev_cmd_data_list(vdev_cmd_data_list_t *vcdl);
|
||||
|
||||
void free_vdev_cmd_data(vdev_cmd_data_t *data);
|
||||
|
||||
int vdev_run_cmd_simple(char *path, char *cmd);
|
||||
|
||||
int check_device(const char *path, boolean_t force,
|
||||
boolean_t isspare, boolean_t iswholedisk);
|
||||
boolean_t check_sector_size_database(char *path, int *sector_size);
|
||||
|
||||
+36
-7
@@ -921,6 +921,15 @@ zero_label(char *path)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
lines_to_stderr(char *lines[], int lines_cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < lines_cnt; i++) {
|
||||
fprintf(stderr, "%s\n", lines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -932,7 +941,7 @@ zero_label(char *path)
|
||||
* 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, boolean_t replacing)
|
||||
{
|
||||
nvlist_t **child;
|
||||
uint_t c, children;
|
||||
@@ -1017,6 +1026,8 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
|
||||
*/
|
||||
if (!is_exclusive && !is_spare(NULL, udevpath)) {
|
||||
char *devnode = strrchr(devpath, '/') + 1;
|
||||
char **lines = NULL;
|
||||
int lines_cnt = 0;
|
||||
|
||||
ret = strncmp(udevpath, UDISK_ROOT, strlen(UDISK_ROOT));
|
||||
if (ret == 0) {
|
||||
@@ -1028,9 +1039,27 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
|
||||
/*
|
||||
* When labeling a pool the raw device node name
|
||||
* is provided as it appears under /dev/.
|
||||
*
|
||||
* Note that 'zhp' will be NULL when we're creating a
|
||||
* pool.
|
||||
*/
|
||||
if (zpool_label_disk(g_zfs, zhp, devnode) == -1)
|
||||
if (zpool_prepare_and_label_disk(g_zfs, zhp, devnode,
|
||||
nv, zhp == NULL ? "create" :
|
||||
replacing ? "replace" : "add", &lines,
|
||||
&lines_cnt) != 0) {
|
||||
(void) fprintf(stderr,
|
||||
gettext(
|
||||
"Error preparing/labeling disk.\n"));
|
||||
if (lines_cnt > 0) {
|
||||
(void) fprintf(stderr,
|
||||
gettext("zfs_prepare_disk output:\n"));
|
||||
lines_to_stderr(lines, lines_cnt);
|
||||
}
|
||||
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
return (-1);
|
||||
}
|
||||
libzfs_free_str_array(lines, lines_cnt);
|
||||
|
||||
/*
|
||||
* Wait for udev to signal the device is available
|
||||
@@ -1067,19 +1096,19 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv)
|
||||
}
|
||||
|
||||
for (c = 0; c < children; c++)
|
||||
if ((ret = make_disks(zhp, child[c])) != 0)
|
||||
if ((ret = make_disks(zhp, child[c], replacing)) != 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)
|
||||
if ((ret = make_disks(zhp, child[c], replacing)) != 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)
|
||||
if ((ret = make_disks(zhp, child[c], replacing)) != 0)
|
||||
return (ret);
|
||||
|
||||
return (0);
|
||||
@@ -1740,7 +1769,7 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!flags.dryrun && make_disks(zhp, newroot) != 0) {
|
||||
if (!flags.dryrun && make_disks(zhp, newroot, B_FALSE) != 0) {
|
||||
nvlist_free(newroot);
|
||||
return (NULL);
|
||||
}
|
||||
@@ -1861,7 +1890,7 @@ make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, 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, replacing) != 0) {
|
||||
nvlist_free(newroot);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user