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