]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/geom/misc/subr.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / sbin / geom / misc / subr.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
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 THE AUTHORS 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 THE AUTHORS 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 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/disk.h>
34 #include <sys/endian.h>
35 #include <sys/uio.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <paths.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <limits.h>
42 #include <inttypes.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <strings.h>
46 #include <unistd.h>
47 #include <assert.h>
48 #include <libgeom.h>
49
50 #include "misc/subr.h"
51
52
53 struct std_metadata {
54         char            md_magic[16];
55         uint32_t        md_version;
56 };
57
58 static void
59 std_metadata_decode(const unsigned char *data, struct std_metadata *md)
60 {
61
62         bcopy(data, md->md_magic, sizeof(md->md_magic));
63         md->md_version = le32dec(data + 16);
64 }
65
66 /*
67  * Greatest Common Divisor.
68  */
69 static unsigned int
70 gcd(unsigned int a, unsigned int b)
71 {
72         unsigned int c;
73
74         while (b != 0) {
75                 c = a;
76                 a = b;
77                 b = (c % b);
78         }
79         return (a);
80 }
81
82 /*
83  * Least Common Multiple.
84  */
85 unsigned int
86 g_lcm(unsigned int a, unsigned int b)
87 {
88
89         return ((a * b) / gcd(a, b));
90 }
91
92 uint32_t
93 bitcount32(uint32_t x)
94 {
95
96         x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
97         x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
98         x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4);
99         x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8);
100         x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16);
101         return (x);
102 }
103
104 /*
105  * The size of a sector is context specific (i.e. determined by the
106  * media). But when users enter a value with a SI unit, they really
107  * mean the byte-size or byte-offset and not the size or offset in
108  * sectors. We should map the byte-oriented value into a sector-oriented
109  * value when we already know the sector size in bytes. At this time
110  * we can use g_parse_lba() function. It converts user specified
111  * value into sectors with following conditions:
112  * o  Sectors size taken as argument from caller.
113  * o  When no SI unit is specified the value is in sectors.
114  * o  With an SI unit the value is in bytes.
115  * o  The 'b' suffix forces byte interpretation and the 's'
116  *    suffix forces sector interpretation.
117  *
118  * Thus:
119  * o  2 and 2s mean 2 sectors, and 2b means 2 bytes.
120  * o  4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors.
121  *
122  */
123 int
124 g_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors)
125 {
126         off_t number, mult, unit;
127         char *s;
128
129         assert(lbastr != NULL);
130         assert(sectorsize > 0);
131         assert(sectors != NULL);
132
133         number = (off_t)strtoimax(lbastr, &s, 0);
134         if (s == lbastr || number < 0)
135                 return (EINVAL);
136
137         mult = 1;
138         unit = sectorsize;
139         if (*s == '\0')
140                 goto done;
141         switch (*s) {
142         case 'e': case 'E':
143                 mult *= 1024;
144                 /* FALLTHROUGH */
145         case 'p': case 'P':
146                 mult *= 1024;
147                 /* FALLTHROUGH */
148         case 't': case 'T':
149                 mult *= 1024;
150                 /* FALLTHROUGH */
151         case 'g': case 'G':
152                 mult *= 1024;
153                 /* FALLTHROUGH */
154         case 'm': case 'M':
155                 mult *= 1024;
156                 /* FALLTHROUGH */
157         case 'k': case 'K':
158                 mult *= 1024;
159                 break;
160         default:
161                 goto sfx;
162         }
163         unit = 1;       /* bytes */
164         s++;
165         if (*s == '\0')
166                 goto done;
167 sfx:
168         switch (*s) {
169         case 's': case 'S':
170                 unit = sectorsize;      /* sector */
171                 break;
172         case 'b': case 'B':
173                 unit = 1;               /* bytes */
174                 break;
175         default:
176                 return (EINVAL);
177         }
178         s++;
179         if (*s != '\0')
180                 return (EINVAL);
181 done:
182         if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number)
183                 return (ERANGE);
184         number *= mult * unit;
185         if (number % sectorsize)
186                 return (EINVAL);
187         number /= sectorsize;
188         *sectors = number;
189         return (0);
190 }
191
192 off_t
193 g_get_mediasize(const char *name)
194 {
195         off_t mediasize;
196         int fd;
197
198         fd = g_open(name, 0);
199         if (fd == -1)
200                 return (0);
201         mediasize = g_mediasize(fd);
202         if (mediasize == -1)
203                 mediasize = 0;
204         (void)g_close(fd);
205         return (mediasize);
206 }
207
208 unsigned int
209 g_get_sectorsize(const char *name)
210 {
211         ssize_t sectorsize;
212         int fd;
213
214         fd = g_open(name, 0);
215         if (fd == -1)
216                 return (0);
217         sectorsize = g_sectorsize(fd);
218         if (sectorsize == -1)
219                 sectorsize = 0;
220         (void)g_close(fd);
221         return ((unsigned int)sectorsize);
222 }
223
224 int
225 g_metadata_read(const char *name, unsigned char *md, size_t size,
226     const char *magic)
227 {
228         struct std_metadata stdmd;
229         unsigned char *sector;
230         ssize_t sectorsize;
231         off_t mediasize;
232         int error, fd;
233
234         sector = NULL;
235         error = 0;
236
237         fd = g_open(name, 0);
238         if (fd == -1)
239                 return (errno);
240         mediasize = g_mediasize(fd);
241         if (mediasize == -1) {
242                 error = errno;
243                 goto out;
244         }
245         sectorsize = g_sectorsize(fd);
246         if (sectorsize == -1) {
247                 error = errno;
248                 goto out;
249         }
250         assert(sectorsize >= (ssize_t)size);
251         sector = malloc(sectorsize);
252         if (sector == NULL) {
253                 error = ENOMEM;
254                 goto out;
255         }
256         if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
257             sectorsize) {
258                 error = errno;
259                 goto out;
260         }
261         if (magic != NULL) {
262                 std_metadata_decode(sector, &stdmd);
263                 if (strcmp(stdmd.md_magic, magic) != 0) {
264                         error = EINVAL;
265                         goto out;
266                 }
267         }
268         bcopy(sector, md, size);
269 out:
270         if (sector != NULL)
271                 free(sector);
272         g_close(fd);
273         return (error);
274 }
275
276 /* 
277  * Actually write the GEOM label to the provider
278  *
279  * @param name  GEOM provider's name (ie "ada0")
280  * @param md    Pointer to the label data to write
281  * @param size  Size of the data pointed to by md
282  */
283 int
284 g_metadata_store(const char *name, const unsigned char *md, size_t size)
285 {
286         unsigned char *sector;
287         ssize_t sectorsize;
288         off_t mediasize;
289         int error, fd;
290
291         sector = NULL;
292         error = 0;
293
294         fd = g_open(name, 1);
295         if (fd == -1)
296                 return (errno);
297         mediasize = g_mediasize(fd);
298         if (mediasize == -1) {
299                 error = errno;
300                 goto out;
301         }
302         sectorsize = g_sectorsize(fd);
303         if (sectorsize == -1) {
304                 error = errno;
305                 goto out;
306         }
307         assert(sectorsize >= (ssize_t)size);
308         sector = malloc(sectorsize);
309         if (sector == NULL) {
310                 error = ENOMEM;
311                 goto out;
312         }
313         bcopy(md, sector, size);
314         bzero(sector + size, sectorsize - size);
315         if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
316             sectorsize) {
317                 error = errno;
318                 goto out;
319         }
320         (void)g_flush(fd);
321 out:
322         if (sector != NULL)
323                 free(sector);
324         (void)g_close(fd);
325         return (error);
326 }
327
328 int
329 g_metadata_clear(const char *name, const char *magic)
330 {
331         struct std_metadata md;
332         unsigned char *sector;
333         ssize_t sectorsize;
334         off_t mediasize;
335         int error, fd;
336
337         sector = NULL;
338         error = 0;
339
340         fd = g_open(name, 1);
341         if (fd == -1)
342                 return (errno);
343         mediasize = g_mediasize(fd);
344         if (mediasize == 0) {
345                 error = errno;
346                 goto out;
347         }
348         sectorsize = g_sectorsize(fd);
349         if (sectorsize <= 0) {
350                 error = errno;
351                 goto out;
352         }
353         sector = malloc(sectorsize);
354         if (sector == NULL) {
355                 error = ENOMEM;
356                 goto out;
357         }
358         if (magic != NULL) {
359                 if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
360                     sectorsize) {
361                         error = errno;
362                         goto out;
363                 }
364                 std_metadata_decode(sector, &md);
365                 if (strcmp(md.md_magic, magic) != 0) {
366                         error = EINVAL;
367                         goto out;
368                 }
369         }
370         bzero(sector, sectorsize);
371         if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
372             sectorsize) {
373                 error = errno;
374                 goto out;
375         }
376         (void)g_flush(fd);
377 out:
378         free(sector);
379         g_close(fd);
380         return (error);
381 }
382
383 /*
384  * Set an error message, if one does not already exist.
385  */
386 void
387 gctl_error(struct gctl_req *req, const char *error, ...)
388 {
389         va_list ap;
390
391         if (req != NULL && req->error != NULL)
392                 return;
393         va_start(ap, error);
394         if (req != NULL) {
395                 vasprintf(&req->error, error, ap);
396         } else {
397                 vfprintf(stderr, error, ap);
398                 fprintf(stderr, "\n");
399         }
400         va_end(ap);
401 }
402
403 static void *
404 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
405 {
406         struct gctl_req_arg *argp;
407         char param[256];
408         unsigned int i;
409         void *p;
410
411         vsnprintf(param, sizeof(param), pfmt, ap);
412         for (i = 0; i < req->narg; i++) {
413                 argp = &req->arg[i];
414                 if (strcmp(param, argp->name))
415                         continue;
416                 if (!(argp->flag & GCTL_PARAM_RD))
417                         continue;
418                 p = argp->value;
419                 if (len == 0) {
420                         /* We are looking for a string. */
421                         if (argp->len < 1) {
422                                 fprintf(stderr, "No length argument (%s).\n",
423                                     param);
424                                 abort();
425                         }
426                         if (((char *)p)[argp->len - 1] != '\0') {
427                                 fprintf(stderr, "Unterminated argument (%s).\n",
428                                     param);
429                                 abort();
430                         }
431                 } else if ((int)len != argp->len) {
432                         fprintf(stderr, "Wrong length %s argument.\n", param);
433                         abort();
434                 }
435                 return (p);
436         }
437         fprintf(stderr, "No such argument (%s).\n", param);
438         abort();
439 }
440
441 int
442 gctl_get_int(struct gctl_req *req, const char *pfmt, ...)
443 {
444         int *p;
445         va_list ap;
446
447         va_start(ap, pfmt);
448         p = gctl_get_param(req, sizeof(int), pfmt, ap);
449         va_end(ap);
450         return (*p);
451 }
452
453 intmax_t
454 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
455 {
456         intmax_t *p;
457         va_list ap;
458
459         va_start(ap, pfmt);
460         p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
461         va_end(ap);
462         return (*p);
463 }
464
465 const char *
466 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
467 {
468         const char *p;
469         va_list ap;
470
471         va_start(ap, pfmt);
472         p = gctl_get_param(req, 0, pfmt, ap);
473         va_end(ap);
474         return (p);
475 }
476
477 int
478 gctl_change_param(struct gctl_req *req, const char *name, int len,
479     const void *value)
480 {
481         struct gctl_req_arg *ap;
482         unsigned int i;
483
484         if (req == NULL || req->error != NULL)
485                 return (EDOOFUS);
486         for (i = 0; i < req->narg; i++) {
487                 ap = &req->arg[i];
488                 if (strcmp(ap->name, name) != 0)
489                         continue;
490                 ap->value = __DECONST(void *, value);
491                 if (len >= 0) {
492                         ap->flag &= ~GCTL_PARAM_ASCII;
493                         ap->len = len;
494                 } else if (len < 0) {
495                         ap->flag |= GCTL_PARAM_ASCII;
496                         ap->len = strlen(value) + 1;
497                 }
498                 return (0);
499         }
500         return (ENOENT);
501 }
502
503 int
504 gctl_delete_param(struct gctl_req *req, const char *name)
505 {
506         struct gctl_req_arg *ap;
507         unsigned int i;
508
509         if (req == NULL || req->error != NULL)
510                 return (EDOOFUS);
511
512         i = 0;
513         while (i < req->narg) {
514                 ap = &req->arg[i];
515                 if (strcmp(ap->name, name) == 0)
516                         break;
517                 i++;
518         }
519         if (i == req->narg)
520                 return (ENOENT);
521
522         free(ap->name);
523         req->narg--;
524         while (i < req->narg) {
525                 req->arg[i] = req->arg[i + 1];
526                 i++;
527         }
528         return (0);
529 }
530
531 int
532 gctl_has_param(struct gctl_req *req, const char *name)
533 {
534         struct gctl_req_arg *ap;
535         unsigned int i;
536
537         if (req == NULL || req->error != NULL)
538                 return (0);
539
540         for (i = 0; i < req->narg; i++) {
541                 ap = &req->arg[i];
542                 if (strcmp(ap->name, name) == 0)
543                         return (1);
544         }
545         return (0);
546 }