]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/vinum/geom_vinum_share.c
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[FreeBSD/FreeBSD.git] / sys / geom / vinum / geom_vinum_share.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2004, 2007 Lukas Ertl
5  * Copyright (c) 1997, 1998, 1999
6  *      Nan Yang Computer Services Limited.  All rights reserved.
7  *
8  *  Parts written by Greg Lehey
9  *
10  *  This software is distributed under the so-called ``Berkeley
11  *  License'':
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *      This product includes software developed by Nan Yang Computer
24  *      Services Limited.
25  * 4. Neither the name of the Company nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * This software is provided ``as is'', and any express or implied
30  * warranties, including, but not limited to, the implied warranties of
31  * merchantability and fitness for a particular purpose are disclaimed.
32  * In no event shall the company or contributors be liable for any
33  * direct, indirect, incidental, special, exemplary, or consequential
34  * damages (including, but not limited to, procurement of substitute
35  * goods or services; loss of use, data, or profits; or business
36  * interruption) however caused and on any theory of liability, whether
37  * in contract, strict liability, or tort (including negligence or
38  * otherwise) arising in any way out of the use of this software, even if
39  * advised of the possibility of such damage.
40  *
41  */
42
43 /* This file is shared between kernel and userland. */
44
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47
48 #include <sys/param.h>
49 #ifdef _KERNEL
50 #include <sys/malloc.h>
51 #include <sys/systm.h>
52
53 #include <geom/geom.h>
54 #define iswhite(c) (((c) == ' ') || ((c) == '\t'))
55 #else
56 #include <ctype.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #define iswhite isspace
61 #define g_free  free
62 #endif /* _KERNEL */
63
64 #include <sys/mutex.h>
65 #include <sys/queue.h>
66
67 #include <geom/vinum/geom_vinum_var.h>
68 #include <geom/vinum/geom_vinum_share.h>
69
70 /*
71  * Take a blank separated list of tokens and turn it into a list of
72  * individual nul-delimited strings.  Build a list of pointers at
73  * token, which must have enough space for the tokens.  Return the
74  * number of tokens, or -1 on error (typically a missing string
75  * delimiter).
76  */
77 int
78 gv_tokenize(char *cptr, char *token[], int maxtoken)
79 {
80         int tokennr;    /* Index of this token. */
81         char delim;     /* Delimiter for searching for the partner. */
82         
83         for (tokennr = 0; tokennr < maxtoken;) {
84
85                 /* Skip leading white space. */
86                 while (iswhite(*cptr))
87                         cptr++;
88
89                 /* End of line. */
90                 if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#'))
91                         return tokennr;
92
93                 delim = *cptr;
94                 token[tokennr] = cptr;          /* Point to it. */
95                 tokennr++;                      /* One more. */
96
97                 /* Run off the end? */
98                 if (tokennr == maxtoken)
99                         return tokennr;
100
101                 /* Quoted? */
102                 if ((delim == '\'') || (delim == '"')) {
103                         for (;;) {
104                                 cptr++;
105
106                                 /* Found the partner. */
107                                 if ((*cptr == delim) && (cptr[-1] != '\\')) {
108                                         cptr++;
109
110                                         /* Space after closing quote needed. */
111                                         if (!iswhite(*cptr))
112                                                 return -1;
113
114                                         /* Delimit. */
115                                         *cptr++ = '\0';
116
117                                 /* End-of-line? */
118                                 } else if ((*cptr == '\0') || (*cptr == '\n'))
119                                         return -1;
120                         }
121
122                 /* Not quoted. */
123                 } else {
124                         while ((*cptr != '\0') &&
125                             (!iswhite(*cptr)) &&
126                             (*cptr != '\n'))
127                                 cptr++;
128
129                         /* Not end-of-line; delimit and move to the next. */
130                         if (*cptr != '\0')
131                                 *cptr++ = '\0';
132                 }
133         }
134
135         /* Can't get here. */
136         return maxtoken;
137 }
138
139
140 /*
141  * Take a number with an optional scale factor and convert it to a number of
142  * bytes.
143  *
144  * The scale factors are:
145  *
146  * s    sectors (of 512 bytes)
147  * b    blocks (of 512 bytes).  This unit is deprecated, because it's
148  *      confusing, but maintained to avoid confusing Veritas users.
149  * k    kilobytes (1024 bytes)
150  * m    megabytes (of 1024 * 1024 bytes)
151  * g    gigabytes (of 1024 * 1024 * 1024 bytes)
152  *
153  * XXX: need a way to signal error
154  */
155 off_t
156 gv_sizespec(char *spec)
157 {
158         uint64_t size;
159         char *s;
160         int sign;
161         
162         size = 0;
163         sign = 1;
164         if (spec != NULL) {             /* we have a parameter */
165                 s = spec;
166                 if (*s == '-') {        /* negative, */
167                         sign = -1;
168                         s++;            /* skip */
169                 }
170
171                 /* It's numeric. */
172                 if ((*s >= '0') && (*s <= '9')) {
173
174                         /* It's numeric. */
175                         while ((*s >= '0') && (*s <= '9'))
176                                 /* Convert it. */
177                                 size = size * 10 + *s++ - '0';
178
179                         switch (*s) {
180                         case '\0':
181                                 return size * sign;
182                         
183                         case 'B':
184                         case 'b':
185                         case 'S':
186                         case 's':
187                                 return size * sign * 512;
188                         
189                         case 'K':
190                         case 'k':
191                                 return size * sign * 1024;
192                         
193                         case 'M':
194                         case 'm':
195                                 return size * sign * 1024 * 1024;
196                         
197                         case 'G':
198                         case 'g':
199                                 return size * sign * 1024 * 1024 * 1024;
200                         }
201                 }
202         }
203
204         return (0);
205 }
206
207 const char *
208 gv_drivestate(int state)
209 {
210         switch (state) {
211         case GV_DRIVE_DOWN:
212                 return "down";
213         case GV_DRIVE_UP:
214                 return "up";
215         default:
216                 return "??";
217         }
218 }
219
220 int
221 gv_drivestatei(char *buf)
222 {
223         if (!strcmp(buf, "up"))
224                 return (GV_DRIVE_UP);
225         else
226                 return (GV_DRIVE_DOWN);
227 }
228
229 /* Translate from a string to a subdisk state. */
230 int
231 gv_sdstatei(char *buf)
232 {
233         if (!strcmp(buf, "up"))
234                 return (GV_SD_UP);
235         else if (!strcmp(buf, "reviving"))
236                 return (GV_SD_REVIVING);
237         else if (!strcmp(buf, "initializing"))
238                 return (GV_SD_INITIALIZING);
239         else if (!strcmp(buf, "stale"))
240                 return (GV_SD_STALE);
241         else
242                 return (GV_SD_DOWN);
243 }
244
245 /* Translate from a subdisk state to a string. */
246 const char *
247 gv_sdstate(int state)
248 {
249         switch (state) {
250         case GV_SD_INITIALIZING:
251                 return "initializing";
252         case GV_SD_STALE:
253                 return "stale";
254         case GV_SD_DOWN:
255                 return "down";
256         case GV_SD_REVIVING:
257                 return "reviving";
258         case GV_SD_UP:
259                 return "up";
260         default:
261                 return "??";
262         }
263 }
264
265 /* Translate from a string to a plex state. */
266 int
267 gv_plexstatei(char *buf)
268 {
269         if (!strcmp(buf, "up"))
270                 return (GV_PLEX_UP);
271         else if (!strcmp(buf, "initializing"))
272                 return (GV_PLEX_INITIALIZING);
273         else if (!strcmp(buf, "degraded"))
274                 return (GV_PLEX_DEGRADED);
275         else if (!strcmp(buf, "growable"))
276                 return (GV_PLEX_GROWABLE);
277         else
278                 return (GV_PLEX_DOWN);
279 }
280
281 /* Translate from a plex state to a string. */
282 const char *
283 gv_plexstate(int state)
284 {
285         switch (state) {
286         case GV_PLEX_DOWN:
287                 return "down";
288         case GV_PLEX_INITIALIZING:
289                 return "initializing";
290         case GV_PLEX_DEGRADED:
291                 return "degraded";
292         case GV_PLEX_GROWABLE:
293                 return "growable";
294         case GV_PLEX_UP:
295                 return "up";
296         default:
297                 return "??";
298         }
299 }
300
301 /* Translate from a string to a plex organization. */
302 int
303 gv_plexorgi(char *buf)
304 {
305         if (!strcmp(buf, "concat"))
306                 return (GV_PLEX_CONCAT);
307         else if (!strcmp(buf, "striped"))
308                 return (GV_PLEX_STRIPED);
309         else if (!strcmp(buf, "raid5"))
310                 return (GV_PLEX_RAID5);
311         else
312                 return (GV_PLEX_DISORG);
313 }
314
315 int
316 gv_volstatei(char *buf)
317 {
318         if (!strcmp(buf, "up"))
319                 return (GV_VOL_UP);
320         else
321                 return (GV_VOL_DOWN);
322 }
323
324 const char *
325 gv_volstate(int state)
326 {
327         switch (state) {
328         case GV_VOL_UP:
329                 return "up";
330         case GV_VOL_DOWN:
331                 return "down";
332         default:
333                 return "??";
334         }
335 }
336
337 /* Translate from a plex organization to a string. */
338 const char *
339 gv_plexorg(int org)
340 {
341         switch (org) {
342         case GV_PLEX_DISORG:
343                 return "??";
344         case GV_PLEX_CONCAT:
345                 return "concat";
346         case GV_PLEX_STRIPED:
347                 return "striped";
348         case GV_PLEX_RAID5:
349                 return "raid5";
350         default:
351                 return "??";
352         }
353 }
354
355 const char *
356 gv_plexorg_short(int org)
357 {
358         switch (org) {
359         case GV_PLEX_DISORG:
360                 return "??";
361         case GV_PLEX_CONCAT:
362                 return "C";
363         case GV_PLEX_STRIPED:
364                 return "S";
365         case GV_PLEX_RAID5:
366                 return "R5";
367         default:
368                 return "??";
369         }
370 }
371
372 struct gv_sd *
373 gv_alloc_sd(void)
374 {
375         struct gv_sd *s;
376
377 #ifdef _KERNEL
378         s = g_malloc(sizeof(struct gv_sd), M_NOWAIT);
379 #else
380         s = malloc(sizeof(struct gv_sd));
381 #endif
382         if (s == NULL)
383                 return (NULL);
384         bzero(s, sizeof(struct gv_sd));
385         s->plex_offset = -1;
386         s->size = -1;
387         s->drive_offset = -1;
388         return (s);
389 }
390
391 struct gv_drive *
392 gv_alloc_drive(void)
393 {
394         struct gv_drive *d;
395
396 #ifdef _KERNEL
397         d = g_malloc(sizeof(struct gv_drive), M_NOWAIT);
398 #else
399         d = malloc(sizeof(struct gv_drive));
400 #endif
401         if (d == NULL)
402                 return (NULL);
403         bzero(d, sizeof(struct gv_drive));
404         return (d);
405 }
406
407 struct gv_volume *
408 gv_alloc_volume(void)
409 {
410         struct gv_volume *v;
411
412 #ifdef _KERNEL
413         v = g_malloc(sizeof(struct gv_volume), M_NOWAIT);
414 #else
415         v = malloc(sizeof(struct gv_volume));
416 #endif
417         if (v == NULL)
418                 return (NULL);
419         bzero(v, sizeof(struct gv_volume));
420         return (v);
421 }
422
423 struct gv_plex *
424 gv_alloc_plex(void)
425 {
426         struct gv_plex *p;
427
428 #ifdef _KERNEL
429         p = g_malloc(sizeof(struct gv_plex), M_NOWAIT);
430 #else
431         p = malloc(sizeof(struct gv_plex));
432 #endif
433         if (p == NULL)
434                 return (NULL);
435         bzero(p, sizeof(struct gv_plex));
436         return (p);
437 }
438
439 /* Get a new drive object. */
440 struct gv_drive *
441 gv_new_drive(int max, char *token[])
442 {
443         struct gv_drive *d;
444         int j, errors;
445         char *ptr;
446
447         if (token[1] == NULL || *token[1] == '\0')
448                 return (NULL);
449         d = gv_alloc_drive();
450         if (d == NULL)
451                 return (NULL);
452         errors = 0;
453         for (j = 1; j < max; j++) {
454                 if (!strcmp(token[j], "state")) {
455                         j++;
456                         if (j >= max) {
457                                 errors++;
458                                 break;
459                         }
460                         d->state = gv_drivestatei(token[j]);
461                 } else if (!strcmp(token[j], "device")) {
462                         j++;
463                         if (j >= max) {
464                                 errors++;
465                                 break;
466                         }
467                         ptr = token[j];
468
469                         if (strncmp(ptr, "/dev/", 5) == 0)
470                                 ptr += 5;
471                         strlcpy(d->device, ptr, sizeof(d->device));
472                 } else {
473                         /* We assume this is the drive name. */
474                         strlcpy(d->name, token[j], sizeof(d->name));
475                 }
476         }
477
478         if (strlen(d->name) == 0 || strlen(d->device) == 0)
479                 errors++;
480
481         if (errors) {
482                 g_free(d);
483                 return (NULL);
484         }
485
486         return (d);
487 }
488
489 /* Get a new volume object. */
490 struct gv_volume *
491 gv_new_volume(int max, char *token[])
492 {
493         struct gv_volume *v;
494         int j, errors;
495
496         if (token[1] == NULL || *token[1] == '\0')
497                 return (NULL);
498
499         v = gv_alloc_volume();
500         if (v == NULL)
501                 return (NULL);
502
503         errors = 0;
504         for (j = 1; j < max; j++) {
505                 if (!strcmp(token[j], "state")) {
506                         j++;
507                         if (j >= max) {
508                                 errors++;
509                                 break;
510                         }
511                         v->state = gv_volstatei(token[j]);
512                 } else {
513                         /* We assume this is the volume name. */
514                         strlcpy(v->name, token[j], sizeof(v->name));
515                 }
516         }
517
518         if (strlen(v->name) == 0)
519                 errors++;
520
521         if (errors) {
522                 g_free(v);
523                 return (NULL);
524         }
525
526         return (v);
527 }
528
529 /* Get a new plex object. */
530 struct gv_plex *
531 gv_new_plex(int max, char *token[])
532 {
533         struct gv_plex *p;
534         int j, errors;
535
536         if (token[1] == NULL || *token[1] == '\0')
537                 return (NULL);
538
539         p = gv_alloc_plex();
540         if (p == NULL)
541                 return (NULL);
542
543         errors = 0;
544         for (j = 1; j < max; j++) {
545                 if (!strcmp(token[j], "name")) {
546                         j++;
547                         if (j >= max) {
548                                 errors++;
549                                 break;
550                         }
551                         strlcpy(p->name, token[j], sizeof(p->name));
552                 } else if (!strcmp(token[j], "org")) {
553                         j++;
554                         if (j >= max) {
555                                 errors++;
556                                 break;
557                         }
558                         p->org = gv_plexorgi(token[j]);
559                         if ((p->org == GV_PLEX_RAID5) ||
560                             (p->org == GV_PLEX_STRIPED)) {
561                                 j++;
562                                 if (j >= max) {
563                                         errors++;
564                                         break;
565                                 }
566                                 p->stripesize = gv_sizespec(token[j]);
567                                 if (p->stripesize == 0) {
568                                         errors++;
569                                         break;
570                                 }
571                         }
572                 } else if (!strcmp(token[j], "state")) {
573                         j++;
574                         if (j >= max) {
575                                 errors++;
576                                 break;
577                         }
578                         p->state = gv_plexstatei(token[j]);
579                 } else if (!strcmp(token[j], "vol") ||
580                             !strcmp(token[j], "volume")) {
581                         j++;
582                         if (j >= max) {
583                                 errors++;
584                                 break;
585                         }
586                         strlcpy(p->volume, token[j], sizeof(p->volume));
587                 } else {
588                         errors++;
589                         break;
590                 }
591         }
592
593         if (errors) {
594                 g_free(p);
595                 return (NULL);
596         }
597
598         return (p);
599 }
600
601
602
603 /* Get a new subdisk object. */
604 struct gv_sd *
605 gv_new_sd(int max, char *token[])
606 {
607         struct gv_sd *s;
608         int j, errors;
609
610         if (token[1] == NULL || *token[1] == '\0')
611                 return (NULL);
612
613         s = gv_alloc_sd();
614         if (s == NULL)
615                 return (NULL);
616
617         errors = 0;
618         for (j = 1; j < max; j++) {
619                 if (!strcmp(token[j], "name")) {
620                         j++;
621                         if (j >= max) {
622                                 errors++;
623                                 break;
624                         }
625                         strlcpy(s->name, token[j], sizeof(s->name));
626                 } else if (!strcmp(token[j], "drive")) {
627                         j++;
628                         if (j >= max) {
629                                 errors++;
630                                 break;
631                         }
632                         strlcpy(s->drive, token[j], sizeof(s->drive));
633                 } else if (!strcmp(token[j], "plex")) {
634                         j++;
635                         if (j >= max) {
636                                 errors++;
637                                 break;
638                         }
639                         strlcpy(s->plex, token[j], sizeof(s->plex));
640                 } else if (!strcmp(token[j], "state")) {
641                         j++;
642                         if (j >= max) {
643                                 errors++;
644                                 break;
645                         }
646                         s->state = gv_sdstatei(token[j]);
647                 } else if (!strcmp(token[j], "len") ||
648                     !strcmp(token[j], "length")) {
649                         j++;
650                         if (j >= max) {
651                                 errors++;
652                                 break;
653                         }
654                         s->size = gv_sizespec(token[j]);
655                         if (s->size <= 0)
656                                 s->size = -1;
657                 } else if (!strcmp(token[j], "driveoffset")) {
658                         j++;
659                         if (j >= max) {
660                                 errors++;
661                                 break;
662                         }
663                         s->drive_offset = gv_sizespec(token[j]);
664                         if (s->drive_offset != 0 &&
665                             s->drive_offset < GV_DATA_START) {
666                                 errors++;
667                                 break;
668                         }
669                 } else if (!strcmp(token[j], "plexoffset")) {
670                         j++;
671                         if (j >= max) {
672                                 errors++;
673                                 break;
674                         }
675                         s->plex_offset = gv_sizespec(token[j]);
676                         if (s->plex_offset < 0) {
677                                 errors++;
678                                 break;
679                         }
680                 } else {
681                         errors++;
682                         break;
683                 }
684         }
685
686         if (strlen(s->drive) == 0)
687                 errors++;
688
689         if (errors) {
690                 g_free(s);
691                 return (NULL);
692         }
693
694         return (s);
695 }
696
697 /*
698  * Take a size in bytes and return a pointer to a string which represents the
699  * size best.  If lj is != 0, return left justified, otherwise in a fixed 10
700  * character field suitable for columnar printing.
701  *
702  * Note this uses a static string: it's only intended to be used immediately
703  * for printing.
704  */
705 const char *
706 gv_roughlength(off_t bytes, int lj)
707 {
708         static char desc[16];
709         
710         /* Gigabytes. */
711         if (bytes > (off_t)MEGABYTE * 10000)
712                 snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB",
713                     bytes / GIGABYTE);
714
715         /* Megabytes. */
716         else if (bytes > KILOBYTE * 10000)
717                 snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB",
718                     bytes / MEGABYTE);
719
720         /* Kilobytes. */
721         else if (bytes > 10000)
722                 snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB",
723                     bytes / KILOBYTE);
724
725         /* Bytes. */
726         else
727                 snprintf(desc, sizeof(desc), lj ? "%jd  B" : "%10jd  B", bytes);
728
729         return (desc);
730 }