]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/geom/vinum/geom_vinum_list.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / geom / vinum / geom_vinum_list.c
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 }