4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
25 * Copyright 2015 RackTop Systems.
26 * Copyright 2016 Nexenta Systems, Inc.
30 * Pool import support functions.
32 * To import a pool, we rely on reading the configuration information from the
33 * ZFS label of each device. If we successfully read the label, then we
34 * organize the configuration information in the following hierarchy:
36 * pool guid -> toplevel vdev guid -> label txg
38 * Duplicate entries matching this same tuple will be discarded. Once we have
39 * examined every device, we pick the best label txg config for each toplevel
40 * vdev. We then arrange these toplevel vdevs into a complete pool config, and
41 * update any paths that have changed. Finally, we attempt to import the pool
42 * using our derived config, and record the results.
45 #include <sys/types.h>
47 #include <sys/ioctl.h>
49 #include <sys/sysctl.h>
63 #include <sys/efi_partition.h>
64 #include <thread_pool.h>
67 #include <sys/vdev_impl.h>
71 #include "zutil_import.h"
74 * Update a leaf vdev's persistent device strings
76 * - only applies for a dedicated leaf vdev (aka whole disk)
77 * - updated during pool create|add|attach|import
78 * - used for matching device matching during auto-{online,expand,replace}
79 * - stored in a leaf disk config label (i.e. alongside 'path' NVP)
80 * - these strings are currently not used in kernel (i.e. for vdev_disk_open)
82 * On FreeBSD we currently just strip devid and phys_path to avoid confusion.
85 update_vdev_config_dev_strs(nvlist_t
*nv
)
87 (void) nvlist_remove_all(nv
, ZPOOL_CONFIG_DEVID
);
88 (void) nvlist_remove_all(nv
, ZPOOL_CONFIG_PHYS_PATH
);
92 * Do not even look at these devices.
94 static const char * const excluded_devs
[] = {
99 #define EXCLUDED_DIR "/dev/"
100 #define EXCLUDED_DIR_LEN 5
103 zpool_open_func(void *arg
)
105 rdsk_node_t
*rn
= arg
;
106 struct stat64 statbuf
;
114 * Do not even look at excluded devices.
116 if (strncmp(rn
->rn_name
, EXCLUDED_DIR
, EXCLUDED_DIR_LEN
) == 0) {
117 char *name
= rn
->rn_name
+ EXCLUDED_DIR_LEN
;
118 for (i
= 0; i
< nitems(excluded_devs
); ++i
) {
119 const char *excluded_name
= excluded_devs
[i
];
120 size_t len
= strlen(excluded_name
);
121 if (strncmp(name
, excluded_name
, len
) == 0) {
128 * O_NONBLOCK so we don't hang trying to open things like serial ports.
130 if ((fd
= open(rn
->rn_name
, O_RDONLY
|O_NONBLOCK
|O_CLOEXEC
)) < 0)
134 * Ignore failed stats.
136 if (fstat64(fd
, &statbuf
) != 0)
139 * We only want regular files, character devs and block devs.
141 if (S_ISREG(statbuf
.st_mode
)) {
142 /* Check if this file is too small to hold a zpool. */
143 if (statbuf
.st_size
< SPA_MINDEVSIZE
) {
146 } else if (S_ISCHR(statbuf
.st_mode
) || S_ISBLK(statbuf
.st_mode
)) {
147 /* Check if this device is too small to hold a zpool. */
148 if (ioctl(fd
, DIOCGMEDIASIZE
, &mediasize
) != 0 ||
149 mediasize
< SPA_MINDEVSIZE
) {
156 if (zpool_read_label(fd
, &config
, &num_labels
) != 0)
158 if (num_labels
== 0) {
163 rn
->rn_config
= config
;
164 rn
->rn_num_labels
= num_labels
;
166 /* TODO: Reuse labelpaths logic from Linux? */
171 static const char * const
172 zpool_default_import_path
[] = {
177 zpool_default_search_paths(size_t *count
)
179 *count
= nitems(zpool_default_import_path
);
180 return (zpool_default_import_path
);
184 zpool_find_import_blkid(libpc_handle_t
*hdl
, pthread_mutex_t
*lock
,
185 avl_tree_t
**slice_cache
)
187 const char *oid
= "vfs.zfs.vol.recursive";
188 char *end
, path
[MAXPATHLEN
];
193 struct gprovider
*pp
;
196 size_t pathleft
, size
= sizeof (value
);
197 boolean_t skip_zvols
= B_FALSE
;
199 end
= stpcpy(path
, "/dev/");
200 pathleft
= &path
[sizeof (path
)] - end
;
202 error
= geom_gettree(&mesh
);
206 if (sysctlbyname(oid
, &value
, &size
, NULL
, 0) == 0 && value
== 0)
209 *slice_cache
= zutil_alloc(hdl
, sizeof (avl_tree_t
));
210 avl_create(*slice_cache
, slice_cache_compare
, sizeof (rdsk_node_t
),
211 offsetof(rdsk_node_t
, rn_node
));
213 LIST_FOREACH(mp
, &mesh
.lg_class
, lg_class
) {
214 if (skip_zvols
&& strcmp(mp
->lg_name
, "ZFS::ZVOL") == 0)
216 LIST_FOREACH(gp
, &mp
->lg_geom
, lg_geom
) {
217 LIST_FOREACH(pp
, &gp
->lg_provider
, lg_provider
) {
218 strlcpy(end
, pp
->lg_name
, pathleft
);
219 slice
= zutil_alloc(hdl
, sizeof (rdsk_node_t
));
220 slice
->rn_name
= zutil_strdup(hdl
, path
);
221 slice
->rn_vdev_guid
= 0;
222 slice
->rn_lock
= lock
;
223 slice
->rn_avl
= *slice_cache
;
225 slice
->rn_labelpaths
= B_FALSE
;
226 slice
->rn_order
= IMPORT_ORDER_DEFAULT
;
228 pthread_mutex_lock(lock
);
229 if (avl_find(*slice_cache
, slice
, &where
)) {
230 free(slice
->rn_name
);
233 avl_insert(*slice_cache
, slice
, where
);
235 pthread_mutex_unlock(lock
);
240 geom_deletetree(&mesh
);
246 zfs_dev_flush(int fd
)
253 update_vdevs_config_dev_sysfs_path(nvlist_t
*config
)