Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/cddl/usr.sbin/zfsd/vdev.cc
103478 views
1
/*-
2
* Copyright (c) 2011, 2012, 2013, 2014 Spectra Logic Corporation
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions, and the following disclaimer,
10
* without modification.
11
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
12
* substantially similar to the "NO WARRANTY" disclaimer below
13
* ("Disclaimer") and any redistribution must be conditioned upon
14
* including a substantially similar Disclaimer requirement for further
15
* binary redistribution.
16
*
17
* NO WARRANTY
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
* POSSIBILITY OF SUCH DAMAGES.
29
*
30
* Authors: Justin T. Gibbs (Spectra Logic Corporation)
31
*/
32
33
/**
34
* \file vdev.cc
35
*
36
* Implementation of the Vdev class.
37
*/
38
#include <syslog.h>
39
#include <sys/cdefs.h>
40
#include <sys/byteorder.h>
41
#include <sys/fs/zfs.h>
42
43
#include <libzfs.h>
44
/*
45
* Undefine flush, defined by cpufunc.h on sparc64, because it conflicts with
46
* C++ flush methods
47
*/
48
#undef flush
49
50
#include <list>
51
#include <map>
52
#include <string>
53
#include <sstream>
54
55
#include <devdctl/guid.h>
56
#include <devdctl/event.h>
57
#include <devdctl/event_factory.h>
58
#include <devdctl/exception.h>
59
#include <devdctl/consumer.h>
60
61
#include "vdev.h"
62
#include "vdev_iterator.h"
63
#include "zfsd.h"
64
#include "zfsd_exception.h"
65
#include "zpool_list.h"
66
/*============================ Namespace Control =============================*/
67
using std::string;
68
using std::stringstream;
69
70
//- Special objects -----------------------------------------------------------
71
Vdev NonexistentVdev;
72
73
//- Vdev Inline Public Methods ------------------------------------------------
74
/*=========================== Class Implementations ==========================*/
75
/*----------------------------------- Vdev -----------------------------------*/
76
77
/* Special constructor for NonexistentVdev. */
78
Vdev::Vdev()
79
: m_poolConfig(NULL),
80
m_config(NULL)
81
{}
82
83
bool
84
Vdev::VdevLookupPoolGuid()
85
{
86
uint64_t guid;
87
if (nvlist_lookup_uint64(m_poolConfig, ZPOOL_CONFIG_POOL_GUID, &guid))
88
return (false);
89
m_poolGUID = guid;
90
return (true);
91
}
92
93
void
94
Vdev::VdevLookupGuid()
95
{
96
uint64_t guid;
97
if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_GUID, &guid) != 0)
98
throw ZfsdException("Unable to extract vdev GUID "
99
"from vdev config data.");
100
m_vdevGUID = guid;
101
}
102
103
Vdev::Vdev(zpool_handle_t *pool, nvlist_t *config)
104
: m_poolConfig(zpool_get_config(pool, NULL)),
105
m_config(config)
106
{
107
if (!VdevLookupPoolGuid())
108
throw ZfsdException("Can't extract pool GUID from handle.");
109
VdevLookupGuid();
110
}
111
112
Vdev::Vdev(nvlist_t *poolConfig, nvlist_t *config)
113
: m_poolConfig(poolConfig),
114
m_config(config)
115
{
116
if (!VdevLookupPoolGuid())
117
throw ZfsdException("Can't extract pool GUID from config.");
118
VdevLookupGuid();
119
}
120
121
Vdev::Vdev(nvlist_t *labelConfig)
122
: m_poolConfig(labelConfig),
123
m_config(labelConfig)
124
{
125
/*
126
* Spares do not have a Pool GUID. Tolerate its absence.
127
* Code accessing this Vdev in a context where the Pool GUID is
128
* required will find it invalid (as it is upon Vdev construction)
129
* and act accordingly.
130
*/
131
(void) VdevLookupPoolGuid();
132
VdevLookupGuid();
133
134
try {
135
m_config = VdevIterator(labelConfig).Find(m_vdevGUID);
136
} catch (const ZfsdException &exp) {
137
/*
138
* When reading a spare's label, it is normal not to find
139
* a list of vdevs
140
*/
141
m_config = NULL;
142
}
143
}
144
145
bool
146
Vdev::IsSpare() const
147
{
148
uint64_t is_spare(0);
149
150
if (m_config == NULL)
151
return (false);
152
153
(void)nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_IS_SPARE, &is_spare);
154
return (bool(is_spare));
155
}
156
157
vdev_state
158
Vdev::State() const
159
{
160
uint64_t *nvlist_array;
161
vdev_stat_t *vs;
162
uint_t vsc;
163
164
if (m_config == NULL) {
165
/*
166
* If we couldn't find the list of vdevs, that normally means
167
* that this is an available hotspare. In that case, we will
168
* presume it to be healthy. Even if this spare had formerly
169
* been in use, been degraded, and been replaced, the act of
170
* replacement wipes the degraded bit from the label. So we
171
* have no choice but to presume that it is healthy.
172
*/
173
return (VDEV_STATE_HEALTHY);
174
}
175
176
if (nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_VDEV_STATS,
177
&nvlist_array, &vsc) == 0) {
178
vs = reinterpret_cast<vdev_stat_t *>(nvlist_array);
179
return (static_cast<vdev_state>(vs->vs_state));
180
}
181
182
/*
183
* Stats are not available. This vdev was created from a label.
184
* Synthesize a state based on available data.
185
*/
186
uint64_t faulted(0);
187
uint64_t degraded(0);
188
(void)nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_FAULTED, &faulted);
189
(void)nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_DEGRADED, &degraded);
190
if (faulted)
191
return (VDEV_STATE_FAULTED);
192
if (degraded)
193
return (VDEV_STATE_DEGRADED);
194
return (VDEV_STATE_HEALTHY);
195
}
196
197
std::list<Vdev>
198
Vdev::Children()
199
{
200
nvlist_t **vdevChildren;
201
int result;
202
u_int numChildren;
203
std::list<Vdev> children;
204
205
if (m_poolConfig == NULL || m_config == NULL)
206
return (children);
207
208
result = nvlist_lookup_nvlist_array(m_config,
209
ZPOOL_CONFIG_CHILDREN, &vdevChildren, &numChildren);
210
if (result != 0)
211
return (children);
212
213
for (u_int c = 0;c < numChildren; c++)
214
children.push_back(Vdev(m_poolConfig, vdevChildren[c]));
215
216
return (children);
217
}
218
219
Vdev
220
Vdev::RootVdev()
221
{
222
nvlist_t *rootVdev;
223
224
if (m_poolConfig == NULL)
225
return (NonexistentVdev);
226
227
if (nvlist_lookup_nvlist(m_poolConfig, ZPOOL_CONFIG_VDEV_TREE,
228
&rootVdev) != 0)
229
return (NonexistentVdev);
230
return (Vdev(m_poolConfig, rootVdev));
231
}
232
233
/*
234
* Find our parent. This requires doing a traversal of the config; we can't
235
* cache it as leaf vdevs may change their pool config location (spare,
236
* replacing, mirror, etc).
237
*/
238
Vdev
239
Vdev::Parent()
240
{
241
std::list<Vdev> to_examine;
242
std::list<Vdev> children;
243
std::list<Vdev>::iterator children_it;
244
245
to_examine.push_back(RootVdev());
246
for (;;) {
247
if (to_examine.empty())
248
return (NonexistentVdev);
249
Vdev vd = to_examine.front();
250
if (vd.DoesNotExist())
251
return (NonexistentVdev);
252
to_examine.pop_front();
253
children = vd.Children();
254
children_it = children.begin();
255
for (;children_it != children.end(); children_it++) {
256
Vdev child = *children_it;
257
258
if (child.GUID() == GUID())
259
return (vd);
260
to_examine.push_front(child);
261
}
262
}
263
}
264
265
bool
266
Vdev::IsAvailableSpare() const
267
{
268
/* If we have a pool guid, we cannot be an available spare. */
269
if (PoolGUID())
270
return (false);
271
272
return (true);
273
}
274
275
bool
276
Vdev::IsSpare()
277
{
278
uint64_t spare;
279
if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_IS_SPARE, &spare) != 0)
280
return (false);
281
return (spare != 0);
282
}
283
284
bool
285
Vdev::IsActiveSpare() const
286
{
287
vdev_stat_t *vs;
288
uint_t c;
289
290
if (m_poolConfig == NULL)
291
return (false);
292
293
(void) nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_VDEV_STATS,
294
reinterpret_cast<uint64_t **>(&vs), &c);
295
if (vs == NULL || vs->vs_aux != VDEV_AUX_SPARED)
296
return (false);
297
return (true);
298
}
299
300
bool
301
Vdev::IsResilvering() const
302
{
303
pool_scan_stat_t *ps = NULL;
304
uint_t c;
305
306
if (State() != VDEV_STATE_HEALTHY)
307
return (false);
308
309
(void) nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_SCAN_STATS,
310
reinterpret_cast<uint64_t **>(&ps), &c);
311
if (ps == NULL || ps->pss_func != POOL_SCAN_RESILVER)
312
return (false);
313
return (true);
314
}
315
316
string
317
Vdev::GUIDString() const
318
{
319
stringstream vdevGUIDString;
320
321
vdevGUIDString << GUID();
322
return (vdevGUIDString.str());
323
}
324
325
string
326
Vdev::Name(zpool_handle_t *zhp, bool verbose) const
327
{
328
return (zpool_vdev_name(g_zfsHandle, zhp, m_config,
329
verbose ? B_TRUE : B_FALSE));
330
}
331
332
string
333
Vdev::Path() const
334
{
335
const char *path(NULL);
336
337
if ((m_config != NULL)
338
&& (nvlist_lookup_string(m_config, ZPOOL_CONFIG_PATH, &path) == 0))
339
return (path);
340
341
return ("");
342
}
343
344
string
345
Vdev::PhysicalPath() const
346
{
347
const char *path(NULL);
348
349
if ((m_config != NULL) && (nvlist_lookup_string(m_config,
350
ZPOOL_CONFIG_PHYS_PATH, &path) == 0))
351
return (path);
352
353
return ("");
354
}
355
356