]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/geom/vinum/geom_vinum_list.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / geom / vinum / geom_vinum_list.c
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 }