changeset 12296 | 7cf402a7f374 |
parent 11935 | 538c866aaac6 |
child 12321 | c2943f5c6eb9 |
12295:e16f396f04a1 | 12296:7cf402a7f374 |
---|---|
18 * |
18 * |
19 * CDDL HEADER END |
19 * CDDL HEADER END |
20 */ |
20 */ |
21 |
21 |
22 /* |
22 /* |
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. |
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. |
24 * Use is subject to license terms. |
|
25 */ |
24 */ |
26 |
25 |
27 #include <assert.h> |
26 #include <assert.h> |
28 #include <ctype.h> |
27 #include <ctype.h> |
29 #include <dirent.h> |
28 #include <dirent.h> |
40 #include <unistd.h> |
39 #include <unistd.h> |
41 #include <priv.h> |
40 #include <priv.h> |
42 #include <pwd.h> |
41 #include <pwd.h> |
43 #include <zone.h> |
42 #include <zone.h> |
44 #include <sys/fs/zfs.h> |
43 #include <sys/fs/zfs.h> |
45 |
|
46 #include <sys/stat.h> |
44 #include <sys/stat.h> |
47 |
45 |
48 #include <libzfs.h> |
46 #include <libzfs.h> |
49 |
47 |
50 #include "zpool_util.h" |
48 #include "zpool_util.h" |
213 case HELP_IOSTAT: |
211 case HELP_IOSTAT: |
214 return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " |
212 return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " |
215 "[count]]\n")); |
213 "[count]]\n")); |
216 case HELP_LIST: |
214 case HELP_LIST: |
217 return (gettext("\tlist [-H] [-o property[,...]] " |
215 return (gettext("\tlist [-H] [-o property[,...]] " |
218 "[pool] ...\n")); |
216 "[-T d|u] [pool] ... [interval [count]]\n")); |
219 case HELP_OFFLINE: |
217 case HELP_OFFLINE: |
220 return (gettext("\toffline [-t] <pool> <device> ...\n")); |
218 return (gettext("\toffline [-t] <pool> <device> ...\n")); |
221 case HELP_ONLINE: |
219 case HELP_ONLINE: |
222 return (gettext("\tonline <pool> <device> ...\n")); |
220 return (gettext("\tonline <pool> <device> ...\n")); |
223 case HELP_REPLACE: |
221 case HELP_REPLACE: |
226 case HELP_REMOVE: |
224 case HELP_REMOVE: |
227 return (gettext("\tremove <pool> <device> ...\n")); |
225 return (gettext("\tremove <pool> <device> ...\n")); |
228 case HELP_SCRUB: |
226 case HELP_SCRUB: |
229 return (gettext("\tscrub [-s] <pool> ...\n")); |
227 return (gettext("\tscrub [-s] <pool> ...\n")); |
230 case HELP_STATUS: |
228 case HELP_STATUS: |
231 return (gettext("\tstatus [-vx] [pool] ...\n")); |
229 return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " |
230 "[count]]\n")); |
|
232 case HELP_UPGRADE: |
231 case HELP_UPGRADE: |
233 return (gettext("\tupgrade\n" |
232 return (gettext("\tupgrade\n" |
234 "\tupgrade -v\n" |
233 "\tupgrade -v\n" |
235 "\tupgrade [-V version] <-a | pool ...>\n")); |
234 "\tupgrade [-V version] <-a | pool ...>\n")); |
236 case HELP_GET: |
235 case HELP_GET: |
517 |
516 |
518 return (ret); |
517 return (ret); |
519 } |
518 } |
520 |
519 |
521 /* |
520 /* |
522 * zpool remove <pool> <vdev> ... |
521 * zpool remove <pool> <vdev> ... |
523 * |
522 * |
524 * Removes the given vdev from the pool. Currently, this only supports removing |
523 * Removes the given vdev from the pool. Currently, this supports removing |
525 * spares and cache devices from the pool. Eventually, we'll want to support |
524 * spares, cache, and log devices from the pool. |
526 * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs. |
|
527 */ |
525 */ |
528 int |
526 int |
529 zpool_do_remove(int argc, char **argv) |
527 zpool_do_remove(int argc, char **argv) |
530 { |
528 { |
531 char *poolname; |
529 char *poolname; |
1042 print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, |
1040 print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, |
1043 int namewidth, int depth, boolean_t isspare) |
1041 int namewidth, int depth, boolean_t isspare) |
1044 { |
1042 { |
1045 nvlist_t **child; |
1043 nvlist_t **child; |
1046 uint_t c, children; |
1044 uint_t c, children; |
1045 pool_scan_stat_t *ps = NULL; |
|
1047 vdev_stat_t *vs; |
1046 vdev_stat_t *vs; |
1048 char rbuf[6], wbuf[6], cbuf[6], repaired[7]; |
1047 char rbuf[6], wbuf[6], cbuf[6]; |
1049 char *vname; |
1048 char *vname; |
1050 uint64_t notpresent; |
1049 uint64_t notpresent; |
1051 spare_cbdata_t cb; |
1050 spare_cbdata_t cb; |
1052 char *state; |
1051 char *state; |
1053 |
1052 |
1054 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, |
|
1055 (uint64_t **)&vs, &c) == 0); |
|
1056 |
|
1057 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, |
1053 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, |
1058 &child, &children) != 0) |
1054 &child, &children) != 0) |
1059 children = 0; |
1055 children = 0; |
1056 |
|
1057 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, |
|
1058 (uint64_t **)&vs, &c) == 0); |
|
1060 |
1059 |
1061 state = zpool_state_to_name(vs->vs_state, vs->vs_aux); |
1060 state = zpool_state_to_name(vs->vs_state, vs->vs_aux); |
1062 if (isspare) { |
1061 if (isspare) { |
1063 /* |
1062 /* |
1064 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for |
1063 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for |
1145 |
1144 |
1146 default: |
1145 default: |
1147 (void) printf(gettext("corrupted data")); |
1146 (void) printf(gettext("corrupted data")); |
1148 break; |
1147 break; |
1149 } |
1148 } |
1150 } else if (vs->vs_scrub_repaired != 0 && children == 0) { |
1149 } |
1151 /* |
1150 |
1152 * Report bytes resilvered/repaired on leaf devices. |
1151 (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, |
1153 */ |
1152 (uint64_t **)&ps, &c); |
1154 zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired)); |
1153 |
1155 (void) printf(gettext(" %s %s"), repaired, |
1154 if (ps && ps->pss_state == DSS_SCANNING && |
1156 (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? |
1155 vs->vs_scan_processed != 0 && children == 0) { |
1157 "resilvered" : "repaired"); |
1156 (void) printf(gettext(" (%s)"), |
1157 (ps->pss_func == POOL_SCAN_RESILVER) ? |
|
1158 "resilvering" : "repairing"); |
|
1158 } |
1159 } |
1159 |
1160 |
1160 (void) printf("\n"); |
1161 (void) printf("\n"); |
1161 |
1162 |
1162 for (c = 0; c < children; c++) { |
1163 for (c = 0; c < children; c++) { |
1192 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); |
1193 verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); |
1193 if (strcmp(type, VDEV_TYPE_MISSING) == 0 || |
1194 if (strcmp(type, VDEV_TYPE_MISSING) == 0 || |
1194 strcmp(type, VDEV_TYPE_HOLE) == 0) |
1195 strcmp(type, VDEV_TYPE_HOLE) == 0) |
1195 return; |
1196 return; |
1196 |
1197 |
1197 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS, |
1198 verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, |
1198 (uint64_t **)&vs, &c) == 0); |
1199 (uint64_t **)&vs, &c) == 0); |
1199 |
1200 |
1200 (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); |
1201 (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); |
1201 (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); |
1202 (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); |
1202 |
1203 |
1331 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, |
1332 verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, |
1332 &pool_state) == 0); |
1333 &pool_state) == 0); |
1333 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, |
1334 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, |
1334 &nvroot) == 0); |
1335 &nvroot) == 0); |
1335 |
1336 |
1336 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, |
1337 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, |
1337 (uint64_t **)&vs, &vsc) == 0); |
1338 (uint64_t **)&vs, &vsc) == 0); |
1338 health = zpool_state_to_name(vs->vs_state, vs->vs_aux); |
1339 health = zpool_state_to_name(vs->vs_state, vs->vs_aux); |
1339 |
1340 |
1340 reason = zpool_import_status(config, &msgid); |
1341 reason = zpool_import_status(config, &msgid); |
1341 |
1342 |
1396 break; |
1397 break; |
1397 |
1398 |
1398 case ZPOOL_STATUS_BAD_LOG: |
1399 case ZPOOL_STATUS_BAD_LOG: |
1399 (void) printf(gettext("status: An intent log record cannot be " |
1400 (void) printf(gettext("status: An intent log record cannot be " |
1400 "read.\n")); |
1401 "read.\n")); |
1402 break; |
|
1403 |
|
1404 case ZPOOL_STATUS_RESILVERING: |
|
1405 (void) printf(gettext("status: One or more devices were being " |
|
1406 "resilvered.\n")); |
|
1401 break; |
1407 break; |
1402 |
1408 |
1403 default: |
1409 default: |
1404 /* |
1410 /* |
1405 * No other status can be seen when importing pools. |
1411 * No other status can be seen when importing pools. |
1988 uint64_t tdelta; |
1994 uint64_t tdelta; |
1989 double scale; |
1995 double scale; |
1990 char *vname; |
1996 char *vname; |
1991 |
1997 |
1992 if (oldnv != NULL) { |
1998 if (oldnv != NULL) { |
1993 verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS, |
1999 verify(nvlist_lookup_uint64_array(oldnv, |
1994 (uint64_t **)&oldvs, &c) == 0); |
2000 ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); |
1995 } else { |
2001 } else { |
1996 oldvs = &zerovs; |
2002 oldvs = &zerovs; |
1997 } |
2003 } |
1998 |
2004 |
1999 verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS, |
2005 verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, |
2000 (uint64_t **)&newvs, &c) == 0); |
2006 (uint64_t **)&newvs, &c) == 0); |
2001 |
2007 |
2002 if (strlen(name) + depth > cb->cb_namewidth) |
2008 if (strlen(name) + depth > cb->cb_namewidth) |
2003 (void) printf("%*s%s", depth, "", name); |
2009 (void) printf("%*s%s", depth, "", name); |
2004 else |
2010 else |
2044 if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, |
2050 if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, |
2045 &oldchild, &c) != 0) |
2051 &oldchild, &c) != 0) |
2046 return; |
2052 return; |
2047 |
2053 |
2048 for (c = 0; c < children; c++) { |
2054 for (c = 0; c < children; c++) { |
2055 uint64_t ishole = B_FALSE; |
|
2056 |
|
2057 if (nvlist_lookup_uint64(newchild[c], |
|
2058 ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) |
|
2059 continue; |
|
2060 |
|
2049 vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); |
2061 vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); |
2050 print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, |
2062 print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, |
2051 newchild[c], cb, depth + 2); |
2063 newchild[c], cb, depth + 2); |
2052 free(vname); |
2064 free(vname); |
2053 } |
2065 } |
2155 |
2167 |
2156 return (0); |
2168 return (0); |
2157 } |
2169 } |
2158 |
2170 |
2159 /* |
2171 /* |
2160 * zpool iostat [-T d|u] [-v] [pool] ... [interval [count]] |
2172 * Parse the input string, get the 'interval' and 'count' value if there is one. |
2161 * |
|
2162 * -T Display a timestamp in date(1) or Unix format |
|
2163 * -v Display statistics for individual vdevs |
|
2164 * |
|
2165 * This command can be tricky because we want to be able to deal with pool |
|
2166 * creation/destruction as well as vdev configuration changes. The bulk of this |
|
2167 * processing is handled by the pool_list_* routines in zpool_iter.c. We rely |
|
2168 * on pool_list_update() to detect the addition of new pools. Configuration |
|
2169 * changes are all handled within libzfs. |
|
2170 */ |
2173 */ |
2171 int |
2174 static void |
2172 zpool_do_iostat(int argc, char **argv) |
2175 get_interval_count(int *argcp, char **argv, unsigned long *iv, |
2173 { |
2176 unsigned long *cnt) |
2174 int c; |
2177 { |
2175 int ret; |
|
2176 int npools; |
|
2177 unsigned long interval = 0, count = 0; |
2178 unsigned long interval = 0, count = 0; |
2178 zpool_list_t *list; |
2179 int argc = *argcp, errno; |
2179 boolean_t verbose = B_FALSE; |
|
2180 iostat_cbdata_t cb; |
|
2181 |
|
2182 /* check options */ |
|
2183 while ((c = getopt(argc, argv, "T:v")) != -1) { |
|
2184 switch (c) { |
|
2185 case 'T': |
|
2186 if (optarg) { |
|
2187 if (*optarg == 'u') |
|
2188 timestamp_fmt = UDATE; |
|
2189 else if (*optarg == 'd') |
|
2190 timestamp_fmt = DDATE; |
|
2191 else |
|
2192 usage(B_FALSE); |
|
2193 } else { |
|
2194 usage(B_FALSE); |
|
2195 } |
|
2196 break; |
|
2197 case 'v': |
|
2198 verbose = B_TRUE; |
|
2199 break; |
|
2200 case '?': |
|
2201 (void) fprintf(stderr, gettext("invalid option '%c'\n"), |
|
2202 optopt); |
|
2203 usage(B_FALSE); |
|
2204 } |
|
2205 } |
|
2206 |
|
2207 argc -= optind; |
|
2208 argv += optind; |
|
2209 |
2180 |
2210 /* |
2181 /* |
2211 * Determine if the last argument is an integer or a pool name |
2182 * Determine if the last argument is an integer or a pool name |
2212 */ |
2183 */ |
2213 if (argc > 0 && isdigit(argv[argc - 1][0])) { |
2184 if (argc > 0 && isdigit(argv[argc - 1][0])) { |
2220 if (interval == 0) { |
2191 if (interval == 0) { |
2221 (void) fprintf(stderr, gettext("interval " |
2192 (void) fprintf(stderr, gettext("interval " |
2222 "cannot be zero\n")); |
2193 "cannot be zero\n")); |
2223 usage(B_FALSE); |
2194 usage(B_FALSE); |
2224 } |
2195 } |
2225 |
|
2226 /* |
2196 /* |
2227 * Ignore the last parameter |
2197 * Ignore the last parameter |
2228 */ |
2198 */ |
2229 argc--; |
2199 argc--; |
2230 } else { |
2200 } else { |
2237 } |
2207 } |
2238 } |
2208 } |
2239 |
2209 |
2240 /* |
2210 /* |
2241 * If the last argument is also an integer, then we have both a count |
2211 * If the last argument is also an integer, then we have both a count |
2242 * and an integer. |
2212 * and an interval. |
2243 */ |
2213 */ |
2244 if (argc > 0 && isdigit(argv[argc - 1][0])) { |
2214 if (argc > 0 && isdigit(argv[argc - 1][0])) { |
2245 char *end; |
2215 char *end; |
2246 |
2216 |
2247 errno = 0; |
2217 errno = 0; |
2261 argc--; |
2231 argc--; |
2262 } else { |
2232 } else { |
2263 interval = 0; |
2233 interval = 0; |
2264 } |
2234 } |
2265 } |
2235 } |
2236 |
|
2237 *iv = interval; |
|
2238 *cnt = count; |
|
2239 *argcp = argc; |
|
2240 } |
|
2241 |
|
2242 static void |
|
2243 get_timestamp_arg(char c) |
|
2244 { |
|
2245 if (c == 'u') |
|
2246 timestamp_fmt = UDATE; |
|
2247 else if (c == 'd') |
|
2248 timestamp_fmt = DDATE; |
|
2249 else |
|
2250 usage(B_FALSE); |
|
2251 } |
|
2252 |
|
2253 /* |
|
2254 * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] |
|
2255 * |
|
2256 * -v Display statistics for individual vdevs |
|
2257 * -T Display a timestamp in date(1) or Unix format |
|
2258 * |
|
2259 * This command can be tricky because we want to be able to deal with pool |
|
2260 * creation/destruction as well as vdev configuration changes. The bulk of this |
|
2261 * processing is handled by the pool_list_* routines in zpool_iter.c. We rely |
|
2262 * on pool_list_update() to detect the addition of new pools. Configuration |
|
2263 * changes are all handled within libzfs. |
|
2264 */ |
|
2265 int |
|
2266 zpool_do_iostat(int argc, char **argv) |
|
2267 { |
|
2268 int c; |
|
2269 int ret; |
|
2270 int npools; |
|
2271 unsigned long interval = 0, count = 0; |
|
2272 zpool_list_t *list; |
|
2273 boolean_t verbose = B_FALSE; |
|
2274 iostat_cbdata_t cb; |
|
2275 |
|
2276 /* check options */ |
|
2277 while ((c = getopt(argc, argv, "T:v")) != -1) { |
|
2278 switch (c) { |
|
2279 case 'T': |
|
2280 get_timestamp_arg(*optarg); |
|
2281 break; |
|
2282 case 'v': |
|
2283 verbose = B_TRUE; |
|
2284 break; |
|
2285 case '?': |
|
2286 (void) fprintf(stderr, gettext("invalid option '%c'\n"), |
|
2287 optopt); |
|
2288 usage(B_FALSE); |
|
2289 } |
|
2290 } |
|
2291 |
|
2292 argc -= optind; |
|
2293 argv += optind; |
|
2294 |
|
2295 get_interval_count(&argc, argv, &interval, &count); |
|
2266 |
2296 |
2267 /* |
2297 /* |
2268 * Construct the list of all interesting pools. |
2298 * Construct the list of all interesting pools. |
2269 */ |
2299 */ |
2270 ret = 0; |
2300 ret = 0; |
2462 |
2492 |
2463 return (0); |
2493 return (0); |
2464 } |
2494 } |
2465 |
2495 |
2466 /* |
2496 /* |
2467 * zpool list [-H] [-o prop[,prop]*] [pool] ... |
2497 * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] |
2468 * |
2498 * |
2469 * -H Scripted mode. Don't display headers, and separate properties |
2499 * -H Scripted mode. Don't display headers, and separate properties |
2470 * by a single tab. |
2500 * by a single tab. |
2471 * -o List of properties to display. Defaults to |
2501 * -o List of properties to display. Defaults to |
2472 * "name,size,allocated,free,capacity,health,altroot" |
2502 * "name,size,allocated,free,capacity,health,altroot" |
2503 * -T Display a timestamp in date(1) or Unix format |
|
2473 * |
2504 * |
2474 * List all pools in the system, whether or not they're healthy. Output space |
2505 * List all pools in the system, whether or not they're healthy. Output space |
2475 * statistics for each one, as well as health status summary. |
2506 * statistics for each one, as well as health status summary. |
2476 */ |
2507 */ |
2477 int |
2508 int |
2481 int ret; |
2512 int ret; |
2482 list_cbdata_t cb = { 0 }; |
2513 list_cbdata_t cb = { 0 }; |
2483 static char default_props[] = |
2514 static char default_props[] = |
2484 "name,size,allocated,free,capacity,dedupratio,health,altroot"; |
2515 "name,size,allocated,free,capacity,dedupratio,health,altroot"; |
2485 char *props = default_props; |
2516 char *props = default_props; |
2517 unsigned long interval = 0, count = 0; |
|
2486 |
2518 |
2487 /* check options */ |
2519 /* check options */ |
2488 while ((c = getopt(argc, argv, ":Ho:")) != -1) { |
2520 while ((c = getopt(argc, argv, ":Ho:T:")) != -1) { |
2489 switch (c) { |
2521 switch (c) { |
2490 case 'H': |
2522 case 'H': |
2491 cb.cb_scripted = B_TRUE; |
2523 cb.cb_scripted = B_TRUE; |
2492 break; |
2524 break; |
2493 case 'o': |
2525 case 'o': |
2494 props = optarg; |
2526 props = optarg; |
2527 break; |
|
2528 case 'T': |
|
2529 get_timestamp_arg(*optarg); |
|
2495 break; |
2530 break; |
2496 case ':': |
2531 case ':': |
2497 (void) fprintf(stderr, gettext("missing argument for " |
2532 (void) fprintf(stderr, gettext("missing argument for " |
2498 "'%c' option\n"), optopt); |
2533 "'%c' option\n"), optopt); |
2499 usage(B_FALSE); |
2534 usage(B_FALSE); |
2506 } |
2541 } |
2507 |
2542 |
2508 argc -= optind; |
2543 argc -= optind; |
2509 argv += optind; |
2544 argv += optind; |
2510 |
2545 |
2546 get_interval_count(&argc, argv, &interval, &count); |
|
2547 |
|
2511 if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) |
2548 if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) |
2512 usage(B_FALSE); |
2549 usage(B_FALSE); |
2513 |
2550 |
2514 cb.cb_first = B_TRUE; |
2551 cb.cb_first = B_TRUE; |
2515 |
2552 |
2516 ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, |
2553 for (;;) { |
2517 list_callback, &cb); |
2554 |
2555 if (timestamp_fmt != NODATE) |
|
2556 print_timestamp(timestamp_fmt); |
|
2557 |
|
2558 ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, |
|
2559 list_callback, &cb); |
|
2560 |
|
2561 if (argc == 0 && cb.cb_first && !cb.cb_scripted) { |
|
2562 (void) printf(gettext("no pools available\n")); |
|
2563 zprop_free_list(cb.cb_proplist); |
|
2564 return (0); |
|
2565 } |
|
2566 |
|
2567 if (interval == 0) |
|
2568 break; |
|
2569 |
|
2570 if (count != 0 && --count == 0) |
|
2571 break; |
|
2572 |
|
2573 (void) sleep(interval); |
|
2574 } |
|
2518 |
2575 |
2519 zprop_free_list(cb.cb_proplist); |
2576 zprop_free_list(cb.cb_proplist); |
2520 |
|
2521 if (argc == 0 && cb.cb_first && !cb.cb_scripted) { |
|
2522 (void) printf(gettext("no pools available\n")); |
|
2523 return (0); |
|
2524 } |
|
2525 |
|
2526 return (ret); |
2577 return (ret); |
2527 } |
2578 } |
2528 |
2579 |
2529 static nvlist_t * |
2580 static nvlist_t * |
2530 zpool_get_vdev_by_name(nvlist_t *nv, char *name) |
2581 zpool_get_vdev_by_name(nvlist_t *nv, char *name) |
3104 (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " |
3155 (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " |
3105 "currently unavailable\n"), zpool_get_name(zhp)); |
3156 "currently unavailable\n"), zpool_get_name(zhp)); |
3106 return (1); |
3157 return (1); |
3107 } |
3158 } |
3108 |
3159 |
3109 err = zpool_scrub(zhp, cb->cb_type); |
3160 err = zpool_scan(zhp, cb->cb_type); |
3110 |
3161 |
3111 return (err != 0); |
3162 return (err != 0); |
3112 } |
3163 } |
3113 |
3164 |
3114 /* |
3165 /* |
3120 zpool_do_scrub(int argc, char **argv) |
3171 zpool_do_scrub(int argc, char **argv) |
3121 { |
3172 { |
3122 int c; |
3173 int c; |
3123 scrub_cbdata_t cb; |
3174 scrub_cbdata_t cb; |
3124 |
3175 |
3125 cb.cb_type = POOL_SCRUB_EVERYTHING; |
3176 cb.cb_type = POOL_SCAN_SCRUB; |
3126 |
3177 |
3127 /* check options */ |
3178 /* check options */ |
3128 while ((c = getopt(argc, argv, "s")) != -1) { |
3179 while ((c = getopt(argc, argv, "s")) != -1) { |
3129 switch (c) { |
3180 switch (c) { |
3130 case 's': |
3181 case 's': |
3131 cb.cb_type = POOL_SCRUB_NONE; |
3182 cb.cb_type = POOL_SCAN_NONE; |
3132 break; |
3183 break; |
3133 case '?': |
3184 case '?': |
3134 (void) fprintf(stderr, gettext("invalid option '%c'\n"), |
3185 (void) fprintf(stderr, gettext("invalid option '%c'\n"), |
3135 optopt); |
3186 optopt); |
3136 usage(B_FALSE); |
3187 usage(B_FALSE); |
3161 |
3212 |
3162 /* |
3213 /* |
3163 * Print out detailed scrub status. |
3214 * Print out detailed scrub status. |
3164 */ |
3215 */ |
3165 void |
3216 void |
3166 print_scrub_status(nvlist_t *nvroot) |
3217 print_scan_status(pool_scan_stat_t *ps) |
3167 { |
3218 { |
3168 vdev_stat_t *vs; |
3219 time_t start, end; |
3169 uint_t vsc; |
3220 uint64_t elapsed, mins_left; |
3170 time_t start, end, now; |
3221 uint64_t pass_exam, examined, total; |
3222 uint_t rate; |
|
3171 double fraction_done; |
3223 double fraction_done; |
3172 uint64_t examined, total, minutes_left, minutes_taken; |
3224 char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; |
3173 char *scrub_type; |
3225 |
3174 |
3226 (void) printf(gettext(" scan: ")); |
3175 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, |
3227 |
3176 (uint64_t **)&vs, &vsc) == 0); |
3228 /* If there's never been a scan, there's not much to say. */ |
3177 |
3229 if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || |
3178 /* |
3230 ps->pss_func >= POOL_SCAN_FUNCS) { |
3179 * If there's never been a scrub, there's not much to say. |
|
3180 */ |
|
3181 if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) { |
|
3182 (void) printf(gettext("none requested\n")); |
3231 (void) printf(gettext("none requested\n")); |
3183 return; |
3232 return; |
3184 } |
3233 } |
3185 |
3234 |
3186 scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ? |
3235 start = ps->pss_start_time; |
3187 "resilver" : "scrub"; |
3236 end = ps->pss_end_time; |
3188 |
3237 zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); |
3189 start = vs->vs_scrub_start; |
3238 |
3190 end = vs->vs_scrub_end; |
3239 assert(ps->pss_func == POOL_SCAN_SCRUB || |
3191 now = time(NULL); |
3240 ps->pss_func == POOL_SCAN_RESILVER); |
3192 examined = vs->vs_scrub_examined; |
3241 /* |
3193 total = vs->vs_alloc; |
3242 * Scan is finished or canceled. |
3194 |
3243 */ |
3195 if (end != 0) { |
3244 if (ps->pss_state == DSS_FINISHED) { |
3196 minutes_taken = (uint64_t)((end - start) / 60); |
3245 uint64_t minutes_taken = (end - start) / 60; |
3197 |
3246 char *fmt; |
3198 (void) printf(gettext("%s %s after %lluh%um with %llu errors " |
3247 |
3199 "on %s"), |
3248 if (ps->pss_func == POOL_SCAN_SCRUB) { |
3200 scrub_type, vs->vs_scrub_complete ? "completed" : "stopped", |
3249 fmt = gettext("scrub repaired %s in %lluh%um with " |
3250 "%llu errors on %s"); |
|
3251 } else if (ps->pss_func == POOL_SCAN_RESILVER) { |
|
3252 fmt = gettext("resilvered %s in %lluh%um with " |
|
3253 "%llu errors on %s"); |
|
3254 } |
|
3255 /* LINTED */ |
|
3256 (void) printf(fmt, processed_buf, |
|
3201 (u_longlong_t)(minutes_taken / 60), |
3257 (u_longlong_t)(minutes_taken / 60), |
3202 (uint_t)(minutes_taken % 60), |
3258 (uint_t)(minutes_taken % 60), |
3203 (u_longlong_t)vs->vs_scrub_errors, ctime(&end)); |
3259 (u_longlong_t)ps->pss_errors, |
3260 ctime((time_t *)&end)); |
|
3204 return; |
3261 return; |
3205 } |
3262 } else if (ps->pss_state == DSS_CANCELED) { |
3206 |
3263 if (ps->pss_func == POOL_SCAN_SCRUB) { |
3207 if (examined == 0) |
3264 (void) printf(gettext("scrub canceled on %s"), |
3208 examined = 1; |
3265 ctime(&end)); |
3209 if (examined > total) |
3266 } else if (ps->pss_func == POOL_SCAN_RESILVER) { |
3210 total = examined; |
3267 (void) printf(gettext("resilver canceled on %s"), |
3211 |
3268 ctime(&end)); |
3269 } |
|
3270 return; |
|
3271 } |
|
3272 |
|
3273 assert(ps->pss_state == DSS_SCANNING); |
|
3274 |
|
3275 /* |
|
3276 * Scan is in progress. |
|
3277 */ |
|
3278 if (ps->pss_func == POOL_SCAN_SCRUB) { |
|
3279 (void) printf(gettext("scrub in progress since %s"), |
|
3280 ctime(&start)); |
|
3281 } else if (ps->pss_func == POOL_SCAN_RESILVER) { |
|
3282 (void) printf(gettext("resilver in progress since %s"), |
|
3283 ctime(&start)); |
|
3284 } |
|
3285 |
|
3286 examined = ps->pss_examined ? ps->pss_examined : 1; |
|
3287 total = ps->pss_to_examine; |
|
3212 fraction_done = (double)examined / total; |
3288 fraction_done = (double)examined / total; |
3213 minutes_left = (uint64_t)((now - start) * |
3289 |
3214 (1 - fraction_done) / fraction_done / 60); |
3290 /* elapsed time for this pass */ |
3215 minutes_taken = (uint64_t)((now - start) / 60); |
3291 elapsed = time(NULL) - ps->pss_pass_start; |
3216 |
3292 elapsed = elapsed ? elapsed : 1; |
3217 (void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, " |
3293 pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; |
3218 "%lluh%um to go\n"), |
3294 rate = pass_exam / elapsed; |
3219 scrub_type, (u_longlong_t)(minutes_taken / 60), |
3295 rate = rate ? rate : 1; |
3220 (uint_t)(minutes_taken % 60), 100 * fraction_done, |
3296 mins_left = ((total - examined) / rate) / 60; |
3221 (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60)); |
3297 |
3298 zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); |
|
3299 zfs_nicenum(total, total_buf, sizeof (total_buf)); |
|
3300 zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); |
|
3301 |
|
3302 (void) printf(gettext(" %s scanned out of %s at " |
|
3303 "%s/s, %lluh%um to go\n"), examined_buf, total_buf, rate_buf, |
|
3304 (u_longlong_t)(mins_left / 60), |
|
3305 (uint_t)(mins_left % 60)); |
|
3306 |
|
3307 if (ps->pss_func == POOL_SCAN_RESILVER) { |
|
3308 (void) printf(gettext(" %s resilvered, %.2f%% done\n"), |
|
3309 processed_buf, 100 * fraction_done); |
|
3310 } else if (ps->pss_func == POOL_SCAN_SCRUB) { |
|
3311 (void) printf(gettext(" %s repaired, %.2f%% done\n"), |
|
3312 processed_buf, 100 * fraction_done); |
|
3313 } |
|
3222 } |
3314 } |
3223 |
3315 |
3224 static void |
3316 static void |
3225 print_error_log(zpool_handle_t *zhp) |
3317 print_error_log(zpool_handle_t *zhp) |
3226 { |
3318 { |
3376 else |
3468 else |
3377 (void) printf("\n"); |
3469 (void) printf("\n"); |
3378 |
3470 |
3379 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, |
3471 verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, |
3380 &nvroot) == 0); |
3472 &nvroot) == 0); |
3381 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, |
3473 verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, |
3382 (uint64_t **)&vs, &c) == 0); |
3474 (uint64_t **)&vs, &c) == 0); |
3383 health = zpool_state_to_name(vs->vs_state, vs->vs_aux); |
3475 health = zpool_state_to_name(vs->vs_state, vs->vs_aux); |
3384 |
3476 |
3385 (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); |
3477 (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); |
3386 (void) printf(gettext(" state: %s\n"), health); |
3478 (void) printf(gettext(" state: %s\n"), health); |
3449 (void) printf(gettext("action: Online the device using " |
3541 (void) printf(gettext("action: Online the device using " |
3450 "'zpool online' or replace the device with\n\t'zpool " |
3542 "'zpool online' or replace the device with\n\t'zpool " |
3451 "replace'.\n")); |
3543 "replace'.\n")); |
3452 break; |
3544 break; |
3453 |
3545 |
3454 |
|
3455 case ZPOOL_STATUS_RESILVERING: |
3546 case ZPOOL_STATUS_RESILVERING: |
3456 (void) printf(gettext("status: One or more devices is " |
3547 (void) printf(gettext("status: One or more devices is " |
3457 "currently being resilvered. The pool will\n\tcontinue " |
3548 "currently being resilvered. The pool will\n\tcontinue " |
3458 "to function, possibly in a degraded state.\n")); |
3549 "to function, possibly in a degraded state.\n")); |
3459 (void) printf(gettext("action: Wait for the resilver to " |
3550 (void) printf(gettext("action: Wait for the resilver to " |
3547 if (config != NULL) { |
3638 if (config != NULL) { |
3548 int namewidth; |
3639 int namewidth; |
3549 uint64_t nerr; |
3640 uint64_t nerr; |
3550 nvlist_t **spares, **l2cache; |
3641 nvlist_t **spares, **l2cache; |
3551 uint_t nspares, nl2cache; |
3642 uint_t nspares, nl2cache; |
3552 |
3643 pool_scan_stat_t *ps = NULL; |
3553 |
3644 |
3554 (void) printf(gettext(" scrub: ")); |
3645 (void) nvlist_lookup_uint64_array(nvroot, |
3555 print_scrub_status(nvroot); |
3646 ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); |
3647 print_scan_status(ps); |
|
3556 |
3648 |
3557 namewidth = max_width(zhp, nvroot, 0, 0); |
3649 namewidth = max_width(zhp, nvroot, 0, 0); |
3558 if (namewidth < 10) |
3650 if (namewidth < 10) |
3559 namewidth = 10; |
3651 namewidth = 10; |
3560 |
3652 |
3618 |
3710 |
3619 return (0); |
3711 return (0); |
3620 } |
3712 } |
3621 |
3713 |
3622 /* |
3714 /* |
3623 * zpool status [-vx] [pool] ... |
3715 * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] |
3624 * |
3716 * |
3625 * -v Display complete error logs |
3717 * -v Display complete error logs |
3626 * -x Display only pools with potential problems |
3718 * -x Display only pools with potential problems |
3627 * -D Display dedup status (undocumented) |
3719 * -D Display dedup status (undocumented) |
3720 * -T Display a timestamp in date(1) or Unix format |
|
3628 * |
3721 * |
3629 * Describes the health status of all pools or some subset. |
3722 * Describes the health status of all pools or some subset. |
3630 */ |
3723 */ |
3631 int |
3724 int |
3632 zpool_do_status(int argc, char **argv) |
3725 zpool_do_status(int argc, char **argv) |
3633 { |
3726 { |
3634 int c; |
3727 int c; |
3635 int ret; |
3728 int ret; |
3729 unsigned long interval = 0, count = 0; |
|
3636 status_cbdata_t cb = { 0 }; |
3730 status_cbdata_t cb = { 0 }; |
3637 |
3731 |
3638 /* check options */ |
3732 /* check options */ |
3639 while ((c = getopt(argc, argv, "vxD")) != -1) { |
3733 while ((c = getopt(argc, argv, "vxDT:")) != -1) { |
3640 switch (c) { |
3734 switch (c) { |
3641 case 'v': |
3735 case 'v': |
3642 cb.cb_verbose = B_TRUE; |
3736 cb.cb_verbose = B_TRUE; |
3643 break; |
3737 break; |
3644 case 'x': |
3738 case 'x': |
3645 cb.cb_explain = B_TRUE; |
3739 cb.cb_explain = B_TRUE; |
3646 break; |
3740 break; |
3647 case 'D': |
3741 case 'D': |
3648 cb.cb_dedup_stats = B_TRUE; |
3742 cb.cb_dedup_stats = B_TRUE; |
3743 break; |
|
3744 case 'T': |
|
3745 get_timestamp_arg(*optarg); |
|
3649 break; |
3746 break; |
3650 case '?': |
3747 case '?': |
3651 (void) fprintf(stderr, gettext("invalid option '%c'\n"), |
3748 (void) fprintf(stderr, gettext("invalid option '%c'\n"), |
3652 optopt); |
3749 optopt); |
3653 usage(B_FALSE); |
3750 usage(B_FALSE); |
3655 } |
3752 } |
3656 |
3753 |
3657 argc -= optind; |
3754 argc -= optind; |
3658 argv += optind; |
3755 argv += optind; |
3659 |
3756 |
3660 cb.cb_first = B_TRUE; |
3757 get_interval_count(&argc, argv, &interval, &count); |
3661 |
3758 |
3662 if (argc == 0) |
3759 if (argc == 0) |
3663 cb.cb_allpools = B_TRUE; |
3760 cb.cb_allpools = B_TRUE; |
3664 |
3761 |
3665 ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb); |
3762 cb.cb_first = B_TRUE; |
3666 |
3763 |
3667 if (argc == 0 && cb.cb_count == 0) |
3764 for (;;) { |
3668 (void) printf(gettext("no pools available\n")); |
3765 if (timestamp_fmt != NODATE) |
3669 else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) |
3766 print_timestamp(timestamp_fmt); |
3670 (void) printf(gettext("all pools are healthy\n")); |
3767 |
3671 |
3768 ret = for_each_pool(argc, argv, B_TRUE, NULL, |
3672 return (ret); |
3769 status_callback, &cb); |
3770 |
|
3771 if (argc == 0 && cb.cb_count == 0) |
|
3772 (void) printf(gettext("no pools available\n")); |
|
3773 else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) |
|
3774 (void) printf(gettext("all pools are healthy\n")); |
|
3775 |
|
3776 if (ret != 0) |
|
3777 return (ret); |
|
3778 |
|
3779 if (interval == 0) |
|
3780 break; |
|
3781 |
|
3782 if (count != 0 && --count == 0) |
|
3783 break; |
|
3784 |
|
3785 (void) sleep(interval); |
|
3786 } |
|
3787 |
|
3788 return (0); |
|
3673 } |
3789 } |
3674 |
3790 |
3675 typedef struct upgrade_cbdata { |
3791 typedef struct upgrade_cbdata { |
3676 int cb_all; |
3792 int cb_all; |
3677 int cb_first; |
3793 int cb_first; |
3888 "(zero-length encoding)\n")); |
4004 "(zero-length encoding)\n")); |
3889 (void) printf(gettext(" 21 Deduplication\n")); |
4005 (void) printf(gettext(" 21 Deduplication\n")); |
3890 (void) printf(gettext(" 22 Received properties\n")); |
4006 (void) printf(gettext(" 22 Received properties\n")); |
3891 (void) printf(gettext(" 23 Slim ZIL\n")); |
4007 (void) printf(gettext(" 23 Slim ZIL\n")); |
3892 (void) printf(gettext(" 24 System attributes\n")); |
4008 (void) printf(gettext(" 24 System attributes\n")); |
4009 (void) printf(gettext(" 25 Improved scrub stats\n")); |
|
3893 (void) printf(gettext("\nFor more information on a particular " |
4010 (void) printf(gettext("\nFor more information on a particular " |
3894 "version, including supported releases, see:\n\n")); |
4011 "version, including supported releases, see:\n\n")); |
3895 (void) printf("http://www.opensolaris.org/os/community/zfs/" |
4012 (void) printf("http://www.opensolaris.org/os/community/zfs/" |
3896 "version/N\n\n"); |
4013 "version/N\n\n"); |
3897 (void) printf(gettext("Where 'N' is the version number.\n")); |
4014 (void) printf(gettext("Where 'N' is the version number.\n")); |
3991 if (ievent >= LOG_END) |
4108 if (ievent >= LOG_END) |
3992 continue; |
4109 continue; |
3993 (void) snprintf(internalstr, |
4110 (void) snprintf(internalstr, |
3994 sizeof (internalstr), |
4111 sizeof (internalstr), |
3995 "[internal %s txg:%lld] %s", |
4112 "[internal %s txg:%lld] %s", |
3996 hist_event_table[ievent], txg, |
4113 zfs_history_event_names[ievent], txg, |
3997 pathstr); |
4114 pathstr); |
3998 cmdstr = internalstr; |
4115 cmdstr = internalstr; |
3999 } |
4116 } |
4000 tsec = dst_time; |
4117 tsec = dst_time; |
4001 (void) localtime_r(&tsec, &t); |
4118 (void) localtime_r(&tsec, &t); |