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