Path: blob/main/sys/contrib/openzfs/lib/libzfs/libzfs_import.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright 2015 Nexenta Systems, Inc. All rights reserved.23* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.24* Copyright (c) 2012, 2018 by Delphix. All rights reserved.25* Copyright 2015 RackTop Systems.26* Copyright (c) 2016, Intel Corporation.27*/2829#include <errno.h>30#include <libintl.h>31#include <libgen.h>32#include <stddef.h>33#include <stdlib.h>34#include <string.h>35#include <sys/stat.h>36#include <unistd.h>37#include <sys/vdev_impl.h>38#include <libzfs.h>39#include "libzfs_impl.h"40#include <libzutil.h>41#include <sys/arc_impl.h>4243/*44* Returns true if the named pool matches the given GUID.45*/46static int47pool_active(libzfs_handle_t *hdl, const char *name, uint64_t guid,48boolean_t *isactive)49{50zpool_handle_t *zhp;5152if (zpool_open_silent(hdl, name, &zhp) != 0)53return (-1);5455if (zhp == NULL) {56*isactive = B_FALSE;57return (0);58}5960uint64_t theguid = fnvlist_lookup_uint64(zhp->zpool_config,61ZPOOL_CONFIG_POOL_GUID);6263zpool_close(zhp);6465*isactive = (theguid == guid);66return (0);67}6869static nvlist_t *70refresh_config(libzfs_handle_t *hdl, nvlist_t *config)71{72nvlist_t *nvl;73zfs_cmd_t zc = {"\0"};74int err, dstbuf_size;7576zcmd_write_conf_nvlist(hdl, &zc, config);7778dstbuf_size = MAX(CONFIG_BUF_MINSIZE, zc.zc_nvlist_conf_size * 32);7980zcmd_alloc_dst_nvlist(hdl, &zc, dstbuf_size);8182while ((err = zfs_ioctl(hdl, ZFS_IOC_POOL_TRYIMPORT,83&zc)) != 0 && errno == ENOMEM)84zcmd_expand_dst_nvlist(hdl, &zc);8586if (err) {87zcmd_free_nvlists(&zc);88return (NULL);89}9091if (zcmd_read_dst_nvlist(hdl, &zc, &nvl) != 0) {92zcmd_free_nvlists(&zc);93return (NULL);94}9596zcmd_free_nvlists(&zc);97return (nvl);98}99100static nvlist_t *101refresh_config_libzfs(void *handle, nvlist_t *tryconfig)102{103return (refresh_config((libzfs_handle_t *)handle, tryconfig));104}105106static int107pool_active_libzfs(void *handle, const char *name, uint64_t guid,108boolean_t *isactive)109{110return (pool_active((libzfs_handle_t *)handle, name, guid, isactive));111}112113const pool_config_ops_t libzfs_config_ops = {114.pco_refresh_config = refresh_config_libzfs,115.pco_pool_active = pool_active_libzfs,116};117118/*119* Return the offset of the given label.120*/121static uint64_t122label_offset(uint64_t size, int l)123{124ASSERT0(P2PHASE_TYPED(size, sizeof (vdev_label_t), uint64_t));125return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ?1260 : size - VDEV_LABELS * sizeof (vdev_label_t)));127}128129/*130* Given a file descriptor, clear (zero) the label information. This function131* is used in the appliance stack as part of the ZFS sysevent module and132* to implement the "zpool labelclear" command.133*/134int135zpool_clear_label(int fd)136{137struct stat64 statbuf;138int l;139vdev_label_t *label;140uint64_t size;141boolean_t labels_cleared = B_FALSE, clear_l2arc_header = B_FALSE,142header_cleared = B_FALSE;143144if (fstat64_blk(fd, &statbuf) == -1)145return (0);146147size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);148149if ((label = calloc(1, sizeof (vdev_label_t))) == NULL)150return (-1);151152for (l = 0; l < VDEV_LABELS; l++) {153uint64_t state, guid, l2cache;154nvlist_t *config;155156if (pread64(fd, label, sizeof (vdev_label_t),157label_offset(size, l)) != sizeof (vdev_label_t)) {158continue;159}160161if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist,162sizeof (label->vl_vdev_phys.vp_nvlist), &config, 0) != 0) {163continue;164}165166/* Skip labels which do not have a valid guid. */167if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,168&guid) != 0 || guid == 0) {169nvlist_free(config);170continue;171}172173/* Skip labels which are not in a known valid state. */174if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,175&state) != 0 || state > POOL_STATE_L2CACHE) {176nvlist_free(config);177continue;178}179180/* If the device is a cache device clear the header. */181if (!clear_l2arc_header) {182if (nvlist_lookup_uint64(config,183ZPOOL_CONFIG_POOL_STATE, &l2cache) == 0 &&184l2cache == POOL_STATE_L2CACHE) {185clear_l2arc_header = B_TRUE;186}187}188189nvlist_free(config);190191/*192* A valid label was found, overwrite this label's nvlist193* and uberblocks with zeros on disk. This is done to prevent194* system utilities, like blkid, from incorrectly detecting a195* partial label. The leading pad space is left untouched.196*/197memset(label, 0, sizeof (vdev_label_t));198size_t label_size = sizeof (vdev_label_t) - (2 * VDEV_PAD_SIZE);199200if (pwrite64(fd, label, label_size, label_offset(size, l) +201(2 * VDEV_PAD_SIZE)) == label_size)202labels_cleared = B_TRUE;203}204205if (clear_l2arc_header) {206_Static_assert(sizeof (*label) >= sizeof (l2arc_dev_hdr_phys_t),207"label < l2arc_dev_hdr_phys_t");208memset(label, 0, sizeof (l2arc_dev_hdr_phys_t));209if (pwrite64(fd, label, sizeof (l2arc_dev_hdr_phys_t),210VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t))211header_cleared = B_TRUE;212}213214free(label);215216if (!labels_cleared || (clear_l2arc_header && !header_cleared))217return (-1);218219return (0);220}221222static boolean_t223find_guid(nvlist_t *nv, uint64_t guid)224{225nvlist_t **child;226uint_t c, children;227228if (fnvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID) == guid)229return (B_TRUE);230231if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,232&child, &children) == 0) {233for (c = 0; c < children; c++)234if (find_guid(child[c], guid))235return (B_TRUE);236}237238return (B_FALSE);239}240241typedef struct aux_cbdata {242const char *cb_type;243uint64_t cb_guid;244zpool_handle_t *cb_zhp;245} aux_cbdata_t;246247static int248find_aux(zpool_handle_t *zhp, void *data)249{250aux_cbdata_t *cbp = data;251nvlist_t **list;252uint_t count;253254nvlist_t *nvroot = fnvlist_lookup_nvlist(zhp->zpool_config,255ZPOOL_CONFIG_VDEV_TREE);256257if (nvlist_lookup_nvlist_array(nvroot, cbp->cb_type,258&list, &count) == 0) {259for (uint_t i = 0; i < count; i++) {260uint64_t guid = fnvlist_lookup_uint64(list[i],261ZPOOL_CONFIG_GUID);262if (guid == cbp->cb_guid) {263cbp->cb_zhp = zhp;264return (1);265}266}267}268269zpool_close(zhp);270return (0);271}272273/*274* Determines if the pool is in use. If so, it returns true and the state of275* the pool as well as the name of the pool. Name string is allocated and276* must be freed by the caller.277*/278int279zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,280boolean_t *inuse)281{282nvlist_t *config;283const char *name = NULL;284boolean_t ret;285uint64_t guid = 0, vdev_guid;286zpool_handle_t *zhp;287nvlist_t *pool_config;288uint64_t stateval, isspare;289aux_cbdata_t cb = { 0 };290boolean_t isactive;291292*inuse = B_FALSE;293294if (zpool_read_label(fd, &config, NULL) != 0)295return (-1);296297if (config == NULL)298return (0);299300stateval = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE);301vdev_guid = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID);302303if (stateval != POOL_STATE_SPARE && stateval != POOL_STATE_L2CACHE) {304name = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);305guid = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID);306}307308switch (stateval) {309case POOL_STATE_EXPORTED:310/*311* A pool with an exported state may in fact be imported312* read-only, so check the in-core state to see if it's313* active and imported read-only. If it is, set314* its state to active.315*/316if (pool_active(hdl, name, guid, &isactive) == 0 && isactive &&317(zhp = zpool_open_canfail(hdl, name)) != NULL) {318if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))319stateval = POOL_STATE_ACTIVE;320321/*322* All we needed the zpool handle for is the323* readonly prop check.324*/325zpool_close(zhp);326}327328ret = B_TRUE;329break;330331case POOL_STATE_ACTIVE:332/*333* For an active pool, we have to determine if it's really part334* of a currently active pool (in which case the pool will exist335* and the guid will be the same), or whether it's part of an336* active pool that was disconnected without being explicitly337* exported.338*/339if (pool_active(hdl, name, guid, &isactive) != 0) {340nvlist_free(config);341return (-1);342}343344if (isactive) {345/*346* Because the device may have been removed while347* offlined, we only report it as active if the vdev is348* still present in the config. Otherwise, pretend like349* it's not in use.350*/351if ((zhp = zpool_open_canfail(hdl, name)) != NULL &&352(pool_config = zpool_get_config(zhp, NULL))353!= NULL) {354nvlist_t *nvroot = fnvlist_lookup_nvlist(355pool_config, ZPOOL_CONFIG_VDEV_TREE);356ret = find_guid(nvroot, vdev_guid);357} else {358ret = B_FALSE;359}360361/*362* If this is an active spare within another pool, we363* treat it like an unused hot spare. This allows the364* user to create a pool with a hot spare that currently365* in use within another pool. Since we return B_TRUE,366* libdiskmgt will continue to prevent generic consumers367* from using the device.368*/369if (ret && nvlist_lookup_uint64(config,370ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare)371stateval = POOL_STATE_SPARE;372373if (zhp != NULL)374zpool_close(zhp);375} else {376stateval = POOL_STATE_POTENTIALLY_ACTIVE;377ret = B_TRUE;378}379break;380381case POOL_STATE_SPARE:382/*383* For a hot spare, it can be either definitively in use, or384* potentially active. To determine if it's in use, we iterate385* over all pools in the system and search for one with a spare386* with a matching guid.387*388* Due to the shared nature of spares, we don't actually report389* the potentially active case as in use. This means the user390* can freely create pools on the hot spares of exported pools,391* but to do otherwise makes the resulting code complicated, and392* we end up having to deal with this case anyway.393*/394cb.cb_zhp = NULL;395cb.cb_guid = vdev_guid;396cb.cb_type = ZPOOL_CONFIG_SPARES;397if (zpool_iter(hdl, find_aux, &cb) == 1) {398name = (char *)zpool_get_name(cb.cb_zhp);399ret = B_TRUE;400} else {401ret = B_FALSE;402}403break;404405case POOL_STATE_L2CACHE:406407/*408* Check if any pool is currently using this l2cache device.409*/410cb.cb_zhp = NULL;411cb.cb_guid = vdev_guid;412cb.cb_type = ZPOOL_CONFIG_L2CACHE;413if (zpool_iter(hdl, find_aux, &cb) == 1) {414name = (char *)zpool_get_name(cb.cb_zhp);415ret = B_TRUE;416} else {417ret = B_FALSE;418}419break;420421default:422ret = B_FALSE;423}424425426if (ret) {427*namestr = zfs_strdup(hdl, name);428*state = (pool_state_t)stateval;429}430431if (cb.cb_zhp)432zpool_close(cb.cb_zhp);433434nvlist_free(config);435*inuse = ret;436return (0);437}438439440