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