]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/geom/vinum/geom_vinum_list.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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/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 }