]> git.proxmox.com Git - mirror_zfs.git/blame - lib/libzpool/util.c
Correctly handle errors from kern_path
[mirror_zfs.git] / lib / libzpool / util.c
CommitLineData
34dc7c2f
BB
1/*
2 * CDDL HEADER START
3 *
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.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21/*
428870ff 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
ed828c0c 23 * Copyright (c) 2016 by Delphix. All rights reserved.
f3c8c9e6 24 * Copyright 2017 Jason King
34dc7c2f
BB
25 */
26
34dc7c2f
BB
27#include <assert.h>
28#include <sys/zfs_context.h>
29#include <sys/avl.h>
30#include <string.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <sys/spa.h>
34#include <sys/fs/zfs.h>
35#include <sys/refcount.h>
ed828c0c 36#include <dlfcn.h>
34dc7c2f
BB
37
38/*
39 * Routines needed by more than one client of libzpool.
40 */
41
f3c8c9e6
JK
42/* The largest suffix that can fit, aka an exabyte (2^60 / 10^18) */
43#define INDEX_MAX (6)
44
45/* Verify INDEX_MAX fits */
46CTASSERT_GLOBAL(INDEX_MAX * 10 < sizeof (uint64_t) * 8);
47
34dc7c2f 48void
f3c8c9e6
JK
49nicenum_scale(uint64_t n, size_t units, char *buf, size_t buflen,
50 uint32_t flags)
34dc7c2f 51{
f3c8c9e6
JK
52 uint64_t divamt = 1024;
53 uint64_t divisor = 1;
34dc7c2f 54 int index = 0;
f3c8c9e6 55 int rc = 0;
34dc7c2f
BB
56 char u;
57
f3c8c9e6
JK
58 if (units == 0)
59 units = 1;
60
61 if (n > 0) {
62 n *= units;
63 if (n < units)
64 goto overflow;
65 }
66
67 if (flags & NN_DIVISOR_1000)
68 divamt = 1000;
69
70 /*
71 * This tries to find the suffix S(n) such that
72 * S(n) <= n < S(n+1), where S(n) = 2^(n*10) | 10^(3*n)
73 * (i.e. 1024/1000, 1,048,576/1,000,000, etc). Stop once S(n)
74 * is the largest prefix supported (i.e. don't bother computing
75 * and checking S(n+1). Since INDEX_MAX should be the largest
76 * suffix that fits (currently an exabyte), S(INDEX_MAX + 1) is
77 * never checked as it would overflow.
78 */
79 while (index < INDEX_MAX) {
80 uint64_t newdiv = divisor * divamt;
81
82 /* CTASSERT() guarantee these never trip */
83 VERIFY3U(newdiv, >=, divamt);
84 VERIFY3U(newdiv, >=, divisor);
85
86 if (n < newdiv)
87 break;
88
89 divisor = newdiv;
34dc7c2f
BB
90 index++;
91 }
92
93 u = " KMGTPE"[index];
94
95 if (index == 0) {
f3c8c9e6
JK
96 rc = snprintf(buf, buflen, "%llu", (u_longlong_t)n);
97 } else if (n % divisor == 0) {
98 /*
99 * If this is an even multiple of the base, always display
100 * without any decimal precision.
101 */
102 rc = snprintf(buf, buflen, "%llu%c",
103 (u_longlong_t)(n / divisor), u);
34dc7c2f 104 } else {
f3c8c9e6
JK
105 /*
106 * We want to choose a precision that reflects the best choice
107 * for fitting in 5 characters. This can get rather tricky
108 * when we have numbers that are very close to an order of
109 * magnitude. For example, when displaying 10239 (which is
110 * really 9.999K), we want only a single place of precision
111 * for 10.0K. We could develop some complex heuristics for
112 * this, but it's much easier just to try each combination
113 * in turn.
114 */
115 int i;
116 for (i = 2; i >= 0; i--) {
117 if ((rc = snprintf(buf, buflen, "%.*f%c", i,
118 (double)n / divisor, u)) <= 5)
119 break;
120 }
34dc7c2f 121 }
f3c8c9e6
JK
122
123 if (rc + 1 > buflen || rc < 0)
124 goto overflow;
125
126 return;
127
128overflow:
129 /* prefer a more verbose message if possible */
130 if (buflen > 10)
131 (void) strlcpy(buf, "<overflow>", buflen);
132 else
133 (void) strlcpy(buf, "??", buflen);
134}
135
136void
137nicenum(uint64_t num, char *buf, size_t buflen)
138{
139 nicenum_scale(num, 1, buf, buflen, 0);
34dc7c2f
BB
140}
141
142static void
b128c09f 143show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
34dc7c2f 144{
34dc7c2f 145 vdev_stat_t *vs;
193a37cb 146 vdev_stat_t *v0 = { 0 };
34dc7c2f
BB
147 uint64_t sec;
148 uint64_t is_log = 0;
b128c09f
BB
149 nvlist_t **child;
150 uint_t c, children;
34dc7c2f
BB
151 char used[6], avail[6];
152 char rops[6], wops[6], rbytes[6], wbytes[6], rerr[6], werr[6], cerr[6];
153 char *prefix = "";
154
193a37cb
TH
155 v0 = umem_zalloc(sizeof (*v0), UMEM_NOFAIL);
156
b128c09f
BB
157 if (indent == 0 && desc != NULL) {
158 (void) printf(" "
34dc7c2f 159 " capacity operations bandwidth ---- errors ----\n");
b128c09f 160 (void) printf("description "
34dc7c2f
BB
161 "used avail read write read write read write cksum\n");
162 }
163
b128c09f
BB
164 if (desc != NULL) {
165 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &is_log);
166
167 if (is_log)
168 prefix = "log ";
169
428870ff 170 if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
b128c09f 171 (uint64_t **)&vs, &c) != 0)
193a37cb 172 vs = v0;
b128c09f
BB
173
174 sec = MAX(1, vs->vs_timestamp / NANOSEC);
175
f3c8c9e6
JK
176 nicenum(vs->vs_alloc, used, sizeof (used));
177 nicenum(vs->vs_space - vs->vs_alloc, avail, sizeof (avail));
178 nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops, sizeof (rops));
179 nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops, sizeof (wops));
180 nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes,
181 sizeof (rbytes));
182 nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes,
183 sizeof (wbytes));
184 nicenum(vs->vs_read_errors, rerr, sizeof (rerr));
185 nicenum(vs->vs_write_errors, werr, sizeof (werr));
186 nicenum(vs->vs_checksum_errors, cerr, sizeof (cerr));
b128c09f
BB
187
188 (void) printf("%*s%s%*s%*s%*s %5s %5s %5s %5s %5s %5s %5s\n",
189 indent, "",
190 prefix,
b8864a23 191 (int)(indent+strlen(prefix)-25-(vs->vs_space ? 0 : 12)),
b128c09f
BB
192 desc,
193 vs->vs_space ? 6 : 0, vs->vs_space ? used : "",
194 vs->vs_space ? 6 : 0, vs->vs_space ? avail : "",
195 rops, wops, rbytes, wbytes, rerr, werr, cerr);
196 }
193a37cb 197 free(v0);
b128c09f
BB
198
199 if (nvlist_lookup_nvlist_array(nv, ctype, &child, &children) != 0)
34dc7c2f
BB
200 return;
201
202 for (c = 0; c < children; c++) {
203 nvlist_t *cnv = child[c];
ccc92611 204 char *cname = NULL, *tname;
34dc7c2f 205 uint64_t np;
ccc92611 206 int len;
34dc7c2f
BB
207 if (nvlist_lookup_string(cnv, ZPOOL_CONFIG_PATH, &cname) &&
208 nvlist_lookup_string(cnv, ZPOOL_CONFIG_TYPE, &cname))
209 cname = "<unknown>";
ccc92611 210 len = strlen(cname) + 2;
211 tname = umem_zalloc(len, UMEM_NOFAIL);
212 (void) strlcpy(tname, cname, len);
34dc7c2f
BB
213 if (nvlist_lookup_uint64(cnv, ZPOOL_CONFIG_NPARITY, &np) == 0)
214 tname[strlen(tname)] = '0' + np;
b128c09f 215 show_vdev_stats(tname, ctype, cnv, indent + 2);
34dc7c2f
BB
216 free(tname);
217 }
218}
219
220void
221show_pool_stats(spa_t *spa)
222{
223 nvlist_t *config, *nvroot;
224 char *name;
225
b128c09f 226 VERIFY(spa_get_stats(spa_name(spa), &config, NULL, 0) == 0);
34dc7c2f
BB
227
228 VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
229 &nvroot) == 0);
230 VERIFY(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
231 &name) == 0);
232
b128c09f
BB
233 show_vdev_stats(name, ZPOOL_CONFIG_CHILDREN, nvroot, 0);
234 show_vdev_stats(NULL, ZPOOL_CONFIG_L2CACHE, nvroot, 0);
235 show_vdev_stats(NULL, ZPOOL_CONFIG_SPARES, nvroot, 0);
236
237 nvlist_free(config);
34dc7c2f 238}
ed828c0c
GM
239
240/*
241 * Sets given global variable in libzpool to given unsigned 32-bit value.
242 * arg: "<variable>=<value>"
243 */
244int
245set_global_var(char *arg)
246{
247 void *zpoolhdl;
248 char *varname = arg, *varval;
249 u_longlong_t val;
250
251#ifndef _LITTLE_ENDIAN
252 /*
253 * On big endian systems changing a 64-bit variable would set the high
254 * 32 bits instead of the low 32 bits, which could cause unexpected
255 * results.
256 */
257 fprintf(stderr, "Setting global variables is only supported on "
258 "little-endian systems\n");
259 return (ENOTSUP);
260#endif
7b0dc2a3 261 if (arg != NULL && (varval = strchr(arg, '=')) != NULL) {
ed828c0c
GM
262 *varval = '\0';
263 varval++;
264 val = strtoull(varval, NULL, 0);
265 if (val > UINT32_MAX) {
266 fprintf(stderr, "Value for global variable '%s' must "
267 "be a 32-bit unsigned integer\n", varname);
268 return (EOVERFLOW);
269 }
270 } else {
271 return (EINVAL);
272 }
273
274 zpoolhdl = dlopen("libzpool.so", RTLD_LAZY);
275 if (zpoolhdl != NULL) {
276 uint32_t *var;
277 var = dlsym(zpoolhdl, varname);
278 if (var == NULL) {
279 fprintf(stderr, "Global variable '%s' does not exist "
280 "in libzpool.so\n", varname);
281 return (EINVAL);
282 }
283 *var = (uint32_t)val;
284
285 dlclose(zpoolhdl);
286 } else {
287 fprintf(stderr, "Failed to open libzpool.so to set global "
288 "variable\n");
289 return (EIO);
290 }
291
292 return (0);
293}