xref: /freebsd/sys/geom/vinum/geom_vinum_list.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
1 /*-
2  *  Copyright (c) 2004, 2007 Lukas Ertl
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  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/libkern.h>
32 #include <sys/malloc.h>
33 
34 #include <geom/geom.h>
35 #include <geom/vinum/geom_vinum_var.h>
36 #include <geom/vinum/geom_vinum.h>
37 #include <geom/vinum/geom_vinum_share.h>
38 
39 void	gv_lvi(struct gv_volume *, struct sbuf *, int);
40 void	gv_lpi(struct gv_plex *, struct sbuf *, int);
41 void	gv_lsi(struct gv_sd *, struct sbuf *, int);
42 void	gv_ldi(struct gv_drive *, struct sbuf *, int);
43 
44 void
45 gv_list(struct g_geom *gp, struct gctl_req *req)
46 {
47 	struct gv_softc *sc;
48 	struct gv_drive *d;
49 	struct gv_plex *p;
50 	struct gv_sd *s;
51 	struct gv_volume *v;
52 	struct sbuf *sb;
53 	int *argc, i, *flags, type;
54 	char *arg, buf[20], *cmd;
55 
56 	argc = gctl_get_paraml(req, "argc", sizeof(*argc));
57 
58 	if (argc == NULL) {
59 		gctl_error(req, "no arguments given");
60 		return;
61 	}
62 
63 	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
64 	if (flags == NULL) {
65 		gctl_error(req, "no flags given");
66 		return;
67 	}
68 
69 	sc = gp->softc;
70 
71 	sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
72 
73 	/* Figure out which command was given. */
74 	cmd = gctl_get_param(req, "cmd", NULL);
75 	if (cmd == NULL) {
76 		gctl_error(req, "no command given");
77 		return;
78 	}
79 
80 	/* List specific objects or everything. */
81 	if (!strcmp(cmd, "list") || !strcmp(cmd, "l")) {
82 		if (*argc) {
83 			for (i = 0; i < *argc; i++) {
84 				snprintf(buf, sizeof(buf), "argv%d", i);
85 				arg = gctl_get_param(req, buf, NULL);
86 				if (arg == NULL)
87 					continue;
88 				type = gv_object_type(sc, arg);
89 				switch (type) {
90 				case GV_TYPE_VOL:
91 					v = gv_find_vol(sc, arg);
92 					gv_lvi(v, sb, *flags);
93 					break;
94 				case GV_TYPE_PLEX:
95 					p = gv_find_plex(sc, arg);
96 					gv_lpi(p, sb, *flags);
97 					break;
98 				case GV_TYPE_SD:
99 					s = gv_find_sd(sc, arg);
100 					gv_lsi(s, sb, *flags);
101 					break;
102 				case GV_TYPE_DRIVE:
103 					d = gv_find_drive(sc, arg);
104 					gv_ldi(d, sb, *flags);
105 					break;
106 				default:
107 					gctl_error(req, "unknown object '%s'",
108 					    arg);
109 					break;
110 				}
111 			}
112 		} else {
113 			gv_ld(gp, req, sb);
114 			sbuf_printf(sb, "\n");
115 			gv_lv(gp, req, sb);
116 			sbuf_printf(sb, "\n");
117 			gv_lp(gp, req, sb);
118 			sbuf_printf(sb, "\n");
119 			gv_ls(gp, req, sb);
120 		}
121 
122 	/* List drives. */
123 	} else if (!strcmp(cmd, "ld")) {
124 		if (*argc) {
125 			for (i = 0; i < *argc; i++) {
126 				snprintf(buf, sizeof(buf), "argv%d", i);
127 				arg = gctl_get_param(req, buf, NULL);
128 				if (arg == NULL)
129 					continue;
130 				type = gv_object_type(sc, arg);
131 				if (type != GV_TYPE_DRIVE) {
132 					gctl_error(req, "'%s' is not a drive",
133 					    arg);
134 					continue;
135 				} else {
136 					d = gv_find_drive(sc, arg);
137 					gv_ldi(d, sb, *flags);
138 				}
139 			}
140 		} else
141 			gv_ld(gp, req, sb);
142 
143 	/* List volumes. */
144 	} else if (!strcmp(cmd, "lv")) {
145 		if (*argc) {
146 			for (i = 0; i < *argc; i++) {
147 				snprintf(buf, sizeof(buf), "argv%d", i);
148 				arg = gctl_get_param(req, buf, NULL);
149 				if (arg == NULL)
150 					continue;
151 				type = gv_object_type(sc, arg);
152 				if (type != GV_TYPE_VOL) {
153 					gctl_error(req, "'%s' is not a volume",
154 					    arg);
155 					continue;
156 				} else {
157 					v = gv_find_vol(sc, arg);
158 					gv_lvi(v, sb, *flags);
159 				}
160 			}
161 		} else
162 			gv_lv(gp, req, sb);
163 
164 	/* List plexes. */
165 	} else if (!strcmp(cmd, "lp")) {
166 		if (*argc) {
167 			for (i = 0; i < *argc; i++) {
168 				snprintf(buf, sizeof(buf), "argv%d", i);
169 				arg = gctl_get_param(req, buf, NULL);
170 				if (arg == NULL)
171 					continue;
172 				type = gv_object_type(sc, arg);
173 				if (type != GV_TYPE_PLEX) {
174 					gctl_error(req, "'%s' is not a plex",
175 					    arg);
176 					continue;
177 				} else {
178 					p = gv_find_plex(sc, arg);
179 					gv_lpi(p, sb, *flags);
180 				}
181 			}
182 		} else
183 			gv_lp(gp, req, sb);
184 
185 	/* List subdisks. */
186 	} else if (!strcmp(cmd, "ls")) {
187 		if (*argc) {
188 			for (i = 0; i < *argc; i++) {
189 				snprintf(buf, sizeof(buf), "argv%d", i);
190 				arg = gctl_get_param(req, buf, NULL);
191 				if (arg == NULL)
192 					continue;
193 				type = gv_object_type(sc, arg);
194 				if (type != GV_TYPE_SD) {
195 					gctl_error(req, "'%s' is not a subdisk",
196 					    arg);
197 					continue;
198 				} else {
199 					s = gv_find_sd(sc, arg);
200 					gv_lsi(s, sb, *flags);
201 				}
202 			}
203 		} else
204 			gv_ls(gp, req, sb);
205 
206 	} else
207 		gctl_error(req, "unknown command '%s'", cmd);
208 
209 	sbuf_finish(sb);
210 	gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1);
211 	sbuf_delete(sb);
212 }
213 
214 /* List one or more volumes. */
215 void
216 gv_lv(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
217 {
218 	struct gv_softc *sc;
219 	struct gv_volume *v;
220 	int i, *flags;
221 
222 	sc = gp->softc;
223 	i = 0;
224 
225 	LIST_FOREACH(v, &sc->volumes, volume)
226 		i++;
227 
228 	sbuf_printf(sb, "%d volume%s:\n", i, i == 1 ? "" : "s");
229 
230 	if (i) {
231 		flags = gctl_get_paraml(req, "flags", sizeof(*flags));
232 		LIST_FOREACH(v, &sc->volumes, volume)
233 			gv_lvi(v, sb, *flags);
234 	}
235 }
236 
237 /* List a single volume. */
238 void
239 gv_lvi(struct gv_volume *v, struct sbuf *sb, int flags)
240 {
241 	struct gv_plex *p;
242 	int i;
243 
244 	if (flags & GV_FLAG_V) {
245 		sbuf_printf(sb, "Volume %s:\tSize: %jd bytes (%jd MB)\n",
246 		    v->name, (intmax_t)v->size, (intmax_t)v->size / MEGABYTE);
247 		sbuf_printf(sb, "\t\tState: %s\n", gv_volstate(v->state));
248 	} else {
249 		sbuf_printf(sb, "V %-21s State: %s\tPlexes: %7d\tSize: %s\n",
250 		    v->name, gv_volstate(v->state), v->plexcount,
251 		    gv_roughlength(v->size, 0));
252 	}
253 
254 	if (flags & GV_FLAG_VV) {
255 		i = 0;
256 		LIST_FOREACH(p, &v->plexes, in_volume) {
257 			sbuf_printf(sb, "\t\tPlex %2d:\t%s\t(%s), %s\n", i,
258 			    p->name, gv_plexstate(p->state),
259 			    gv_roughlength(p->size, 0));
260 			i++;
261 		}
262 	}
263 
264 	if (flags & GV_FLAG_R) {
265 		LIST_FOREACH(p, &v->plexes, in_volume)
266 			gv_lpi(p, sb, flags);
267 	}
268 }
269 
270 /* List one or more plexes. */
271 void
272 gv_lp(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
273 {
274 	struct gv_softc *sc;
275 	struct gv_plex *p;
276 	int i, *flags;
277 
278 	sc = gp->softc;
279 	i = 0;
280 
281 	LIST_FOREACH(p, &sc->plexes, plex)
282 		i++;
283 
284 	sbuf_printf(sb, "%d plex%s:\n", i, i == 1 ? "" : "es");
285 
286 	if (i) {
287 		flags = gctl_get_paraml(req, "flags", sizeof(*flags));
288 		LIST_FOREACH(p, &sc->plexes, plex)
289 			gv_lpi(p, sb, *flags);
290 	}
291 }
292 
293 /* List a single plex. */
294 void
295 gv_lpi(struct gv_plex *p, struct sbuf *sb, int flags)
296 {
297 	struct gv_sd *s;
298 	int i;
299 
300 	if (flags & GV_FLAG_V) {
301 		sbuf_printf(sb, "Plex %s:\tSize:\t%9jd bytes (%jd MB)\n",
302 		    p->name, (intmax_t)p->size, (intmax_t)p->size / MEGABYTE);
303 		sbuf_printf(sb, "\t\tSubdisks: %8d\n", p->sdcount);
304 		sbuf_printf(sb, "\t\tState: %s\n", gv_plexstate(p->state));
305 		if ((p->flags & GV_PLEX_SYNCING) ||
306 		    (p->flags & GV_PLEX_GROWING) ||
307 		    (p->flags & GV_PLEX_REBUILDING)) {
308 			sbuf_printf(sb, "\t\tSynced: ");
309 			sbuf_printf(sb, "%16jd bytes (%d%%)\n",
310 			    (intmax_t)p->synced,
311 			    (p->size > 0) ? (int)((p->synced * 100) / p->size) :
312 			    0);
313 		}
314 		sbuf_printf(sb, "\t\tOrganization: %s", gv_plexorg(p->org));
315 		if (gv_is_striped(p)) {
316 			sbuf_printf(sb, "\tStripe size: %s\n",
317 			    gv_roughlength(p->stripesize, 1));
318 		}
319 		sbuf_printf(sb, "\t\tFlags: %d\n", p->flags);
320 		if (p->vol_sc != NULL) {
321 			sbuf_printf(sb, "\t\tPart of volume %s\n", p->volume);
322 		}
323 	} else {
324 		sbuf_printf(sb, "P %-18s %2s State: ", p->name,
325 		gv_plexorg_short(p->org));
326 		if ((p->flags & GV_PLEX_SYNCING) ||
327 		    (p->flags & GV_PLEX_GROWING) ||
328 		    (p->flags & GV_PLEX_REBUILDING)) {
329 			sbuf_printf(sb, "S %d%%\t", (int)((p->synced * 100) /
330 			    p->size));
331 		} else {
332 			sbuf_printf(sb, "%s\t", gv_plexstate(p->state));
333 		}
334 		sbuf_printf(sb, "Subdisks: %5d\tSize: %s\n", p->sdcount,
335 		    gv_roughlength(p->size, 0));
336 	}
337 
338 	if (flags & GV_FLAG_VV) {
339 		i = 0;
340 		LIST_FOREACH(s, &p->subdisks, in_plex) {
341 			sbuf_printf(sb, "\t\tSubdisk %d:\t%s\n", i, s->name);
342 			sbuf_printf(sb, "\t\t  state: %s\tsize %11jd "
343 			    "(%jd MB)\n", gv_sdstate(s->state),
344 			    (intmax_t)s->size, (intmax_t)s->size / MEGABYTE);
345 			if (p->org == GV_PLEX_CONCAT) {
346 				sbuf_printf(sb, "\t\t\toffset %9jd (0x%jx)\n",
347 				    (intmax_t)s->plex_offset,
348 				    (intmax_t)s->plex_offset);
349 			}
350 			i++;
351 		}
352 	}
353 
354 	if (flags & GV_FLAG_R) {
355 		LIST_FOREACH(s, &p->subdisks, in_plex)
356 			gv_lsi(s, sb, flags);
357 	}
358 }
359 
360 /* List one or more subdisks. */
361 void
362 gv_ls(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
363 {
364 	struct gv_softc *sc;
365 	struct gv_sd *s;
366 	int i, *flags;
367 
368 	sc = gp->softc;
369 	i = 0;
370 
371 	LIST_FOREACH(s, &sc->subdisks, sd)
372 		i++;
373 
374 	sbuf_printf(sb, "%d subdisk%s:\n", i, i == 1 ? "" : "s");
375 
376 	if (i) {
377 		flags = gctl_get_paraml(req, "flags", sizeof(*flags));
378 		LIST_FOREACH(s, &sc->subdisks, sd)
379 			gv_lsi(s, sb, *flags);
380 	}
381 }
382 
383 /* List a single subdisk. */
384 void
385 gv_lsi(struct gv_sd *s, struct sbuf *sb, int flags)
386 {
387 	if (flags & GV_FLAG_V) {
388 		sbuf_printf(sb, "Subdisk %s:\n", s->name);
389 		sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n",
390 		    (intmax_t)s->size, (intmax_t)s->size / MEGABYTE);
391 		sbuf_printf(sb, "\t\tState: %s\n", gv_sdstate(s->state));
392 
393 		if (s->state == GV_SD_INITIALIZING ||
394 		    s->state == GV_SD_REVIVING) {
395 			if (s->state == GV_SD_INITIALIZING)
396 				sbuf_printf(sb, "\t\tInitialized: ");
397 			else
398 				sbuf_printf(sb, "\t\tRevived: ");
399 
400 			sbuf_printf(sb, "%16jd bytes (%d%%)\n",
401 			    (intmax_t)s->initialized,
402 			    (int)((s->initialized * 100) / s->size));
403 		}
404 
405 		if (s->plex_sc != NULL) {
406 			sbuf_printf(sb, "\t\tPlex %s at offset %jd (%s)\n",
407 			    s->plex, (intmax_t)s->plex_offset,
408 			    gv_roughlength(s->plex_offset, 1));
409 		}
410 
411 		sbuf_printf(sb, "\t\tDrive %s (%s) at offset %jd (%s)\n",
412 		    s->drive,
413 		    s->drive_sc == NULL ? "*missing*" : s->drive_sc->name,
414 		    (intmax_t)s->drive_offset,
415 		    gv_roughlength(s->drive_offset, 1));
416 		sbuf_printf(sb, "\t\tFlags: %d\n", s->flags);
417 	} else {
418 		sbuf_printf(sb, "S %-21s State: ", s->name);
419 		if (s->state == GV_SD_INITIALIZING ||
420 		    s->state == GV_SD_REVIVING) {
421 			if (s->state == GV_SD_INITIALIZING)
422 				sbuf_printf(sb, "I ");
423 			else
424 				sbuf_printf(sb, "R ");
425 			sbuf_printf(sb, "%d%%\t",
426 			    (int)((s->initialized * 100) / s->size));
427 		} else {
428 			sbuf_printf(sb, "%s\t", gv_sdstate(s->state));
429 		}
430 		sbuf_printf(sb, "D: %-12s Size: %s\n", s->drive,
431 		    gv_roughlength(s->size, 0));
432 	}
433 }
434 
435 /* List one or more drives. */
436 void
437 gv_ld(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb)
438 {
439 	struct gv_softc *sc;
440 	struct gv_drive *d;
441 	int i, *flags;
442 
443 	sc = gp->softc;
444 	i = 0;
445 
446 	LIST_FOREACH(d, &sc->drives, drive)
447 		i++;
448 
449 	sbuf_printf(sb, "%d drive%s:\n", i, i == 1 ? "" : "s");
450 
451 	if (i) {
452 		flags = gctl_get_paraml(req, "flags", sizeof(*flags));
453 		LIST_FOREACH(d, &sc->drives, drive)
454 			gv_ldi(d, sb, *flags);
455 	}
456 }
457 
458 /* List a single drive. */
459 void
460 gv_ldi(struct gv_drive *d, struct sbuf *sb, int flags)
461 {
462 	struct gv_freelist *fl;
463 	struct gv_sd *s;
464 
465 	/* Verbose listing. */
466 	if (flags & GV_FLAG_V) {
467 		sbuf_printf(sb, "Drive %s:\tDevice %s\n", d->name, d->device);
468 		sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n",
469 		    (intmax_t)d->size, (intmax_t)d->size / MEGABYTE);
470 		sbuf_printf(sb, "\t\tUsed: %16jd bytes (%jd MB)\n",
471 		    (intmax_t)d->size - d->avail,
472 		    (intmax_t)(d->size - d->avail) / MEGABYTE);
473 		sbuf_printf(sb, "\t\tAvailable: %11jd bytes (%jd MB)\n",
474 		    (intmax_t)d->avail, (intmax_t)d->avail / MEGABYTE);
475 		sbuf_printf(sb, "\t\tState: %s\n", gv_drivestate(d->state));
476 		sbuf_printf(sb, "\t\tFlags: %d\n", d->flags);
477 
478 		/* Be very verbose. */
479 		if (flags & GV_FLAG_VV) {
480 			sbuf_printf(sb, "\t\tFree list contains %d entries:\n",
481 			    d->freelist_entries);
482 			sbuf_printf(sb, "\t\t   Offset\t     Size\n");
483 			LIST_FOREACH(fl, &d->freelist, freelist)
484 				sbuf_printf(sb, "\t\t%9jd\t%9jd\n",
485 				    (intmax_t)fl->offset, (intmax_t)fl->size);
486 		}
487 	} else {
488 		sbuf_printf(sb, "D %-21s State: %s\t/dev/%s\tA: %jd/%jd MB "
489 		    "(%d%%)\n", d->name, gv_drivestate(d->state), d->device,
490 		    (intmax_t)d->avail / MEGABYTE, (intmax_t)d->size / MEGABYTE,
491 		    d->size > 0 ? (int)((d->avail * 100) / d->size) : 0);
492 	}
493 
494 	/* Recursive listing. */
495 	if (flags & GV_FLAG_R) {
496 		LIST_FOREACH(s, &d->subdisks, from_drive)
497 			gv_lsi(s, sb, flags);
498 	}
499 }
500