170d586c0SPoul-Henning Kamp /* 270d586c0SPoul-Henning Kamp * ---------------------------------------------------------------------------- 370d586c0SPoul-Henning Kamp * "THE BEER-WARE LICENSE" (Revision 42): 470d586c0SPoul-Henning Kamp * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 570d586c0SPoul-Henning Kamp * can do whatever you want with this stuff. If we meet some day, and you think 670d586c0SPoul-Henning Kamp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 770d586c0SPoul-Henning Kamp * ---------------------------------------------------------------------------- 870d586c0SPoul-Henning Kamp * 970d586c0SPoul-Henning Kamp * $FreeBSD$ 1070d586c0SPoul-Henning Kamp * 1170d586c0SPoul-Henning Kamp */ 1270d586c0SPoul-Henning Kamp 1370d586c0SPoul-Henning Kamp #include <stdio.h> 1470d586c0SPoul-Henning Kamp #include <stdlib.h> 1570d586c0SPoul-Henning Kamp #include <fcntl.h> 1670d586c0SPoul-Henning Kamp #include <unistd.h> 1770d586c0SPoul-Henning Kamp #include <string.h> 1870d586c0SPoul-Henning Kamp #include <err.h> 1970d586c0SPoul-Henning Kamp #include <sys/ioctl.h> 2070d586c0SPoul-Henning Kamp #include <sys/param.h> 2157e9624eSPoul-Henning Kamp #include <sys/module.h> 2257e9624eSPoul-Henning Kamp #include <sys/linker.h> 2370d586c0SPoul-Henning Kamp #include <sys/mdioctl.h> 24174b5e9aSPoul-Henning Kamp #include <sys/sysctl.h> 25174b5e9aSPoul-Henning Kamp #include <sys/queue.h> 26174b5e9aSPoul-Henning Kamp 27174b5e9aSPoul-Henning Kamp int intcmp(const void *, const void *); 28174b5e9aSPoul-Henning Kamp int list(const int); 29174b5e9aSPoul-Henning Kamp int query(const int, const int); 3070d586c0SPoul-Henning Kamp 3170d586c0SPoul-Henning Kamp struct md_ioctl mdio; 3270d586c0SPoul-Henning Kamp 33174b5e9aSPoul-Henning Kamp enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; 3470d586c0SPoul-Henning Kamp 3557e9624eSPoul-Henning Kamp void mdmaybeload(void); 3657e9624eSPoul-Henning Kamp 37c2ef0b73SPoul-Henning Kamp void 38c2ef0b73SPoul-Henning Kamp usage() 39c2ef0b73SPoul-Henning Kamp { 408f8def9eSPoul-Henning Kamp fprintf(stderr, "Usage:\n"); 418f8def9eSPoul-Henning Kamp fprintf(stderr, "\tmdconfig -a -t type [-o [no]option]... [ -f file] [-s size] [-u unit]\n"); 428f8def9eSPoul-Henning Kamp fprintf(stderr, "\tmdconfig -d -u unit\n"); 43174b5e9aSPoul-Henning Kamp fprintf(stderr, "\tmdconfig -l [-u unit]\n"); 44c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n"); 45c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\toption = {cluster, compress, reserve, autounit}\n"); 46c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%dk (kB), %%dm (MB) or %%dg (GB)\n"); 47c2ef0b73SPoul-Henning Kamp exit(1); 48c2ef0b73SPoul-Henning Kamp } 49c2ef0b73SPoul-Henning Kamp 5070d586c0SPoul-Henning Kamp int 5170d586c0SPoul-Henning Kamp main(int argc, char **argv) 5270d586c0SPoul-Henning Kamp { 5370d586c0SPoul-Henning Kamp int ch, fd, i; 54c2ef0b73SPoul-Henning Kamp char *p; 55c2ef0b73SPoul-Henning Kamp int cmdline = 0; 5670d586c0SPoul-Henning Kamp 5770d586c0SPoul-Henning Kamp for (;;) { 58174b5e9aSPoul-Henning Kamp ch = getopt(argc, argv, "ab:df:lo:s:t:u:"); 5970d586c0SPoul-Henning Kamp if (ch == -1) 6070d586c0SPoul-Henning Kamp break; 6170d586c0SPoul-Henning Kamp switch (ch) { 6270d586c0SPoul-Henning Kamp case 'a': 63c2ef0b73SPoul-Henning Kamp if (cmdline != 0) 64c2ef0b73SPoul-Henning Kamp usage(); 6570d586c0SPoul-Henning Kamp action = ATTACH; 66c2ef0b73SPoul-Henning Kamp cmdline = 1; 6770d586c0SPoul-Henning Kamp break; 6870d586c0SPoul-Henning Kamp case 'd': 69c2ef0b73SPoul-Henning Kamp if (cmdline != 0) 70c2ef0b73SPoul-Henning Kamp usage(); 7170d586c0SPoul-Henning Kamp action = DETACH; 728f8def9eSPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT; 738f8def9eSPoul-Henning Kamp cmdline = 3; 74c2ef0b73SPoul-Henning Kamp break; 75174b5e9aSPoul-Henning Kamp case 'l': 76174b5e9aSPoul-Henning Kamp if (cmdline != 0) 77174b5e9aSPoul-Henning Kamp usage(); 78174b5e9aSPoul-Henning Kamp action = LIST; 79174b5e9aSPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT; 80174b5e9aSPoul-Henning Kamp cmdline = 3; 81174b5e9aSPoul-Henning Kamp break; 82c2ef0b73SPoul-Henning Kamp case 't': 83c2ef0b73SPoul-Henning Kamp if (cmdline != 1) 84c2ef0b73SPoul-Henning Kamp usage(); 85c2ef0b73SPoul-Henning Kamp if (!strcmp(optarg, "malloc")) { 86c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_MALLOC; 87c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; 88c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "preload")) { 89c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_PRELOAD; 90c2ef0b73SPoul-Henning Kamp mdio.md_options = 0; 91c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "vnode")) { 92c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_VNODE; 93c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 94c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "swap")) { 95c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_SWAP; 96c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 97c2ef0b73SPoul-Henning Kamp } else { 98c2ef0b73SPoul-Henning Kamp usage(); 99c2ef0b73SPoul-Henning Kamp } 100c2ef0b73SPoul-Henning Kamp cmdline=2; 10170d586c0SPoul-Henning Kamp break; 10270d586c0SPoul-Henning Kamp case 'f': 103c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 104c2ef0b73SPoul-Henning Kamp usage(); 1053b42f2f3SPoul-Henning Kamp mdio.md_file = optarg; 10670d586c0SPoul-Henning Kamp break; 10770d586c0SPoul-Henning Kamp case 'o': 108c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 109c2ef0b73SPoul-Henning Kamp usage(); 11070d586c0SPoul-Henning Kamp if (!strcmp(optarg, "cluster")) 11170d586c0SPoul-Henning Kamp mdio.md_options |= MD_CLUSTER; 11270d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "nocluster")) 11370d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_CLUSTER; 114c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "compress")) 115c2ef0b73SPoul-Henning Kamp mdio.md_options |= MD_COMPRESS; 116c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "nocompress")) 117c2ef0b73SPoul-Henning Kamp mdio.md_options &= ~MD_COMPRESS; 11870d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "reserve")) 11970d586c0SPoul-Henning Kamp mdio.md_options |= MD_RESERVE; 12070d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "noreserve")) 12170d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_RESERVE; 12270d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "autounit")) 12370d586c0SPoul-Henning Kamp mdio.md_options |= MD_AUTOUNIT; 12470d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "noautounit")) 12570d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_AUTOUNIT; 12670d586c0SPoul-Henning Kamp else 12770d586c0SPoul-Henning Kamp errx(1, "Unknown option."); 12870d586c0SPoul-Henning Kamp break; 12970d586c0SPoul-Henning Kamp case 's': 130c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 131c2ef0b73SPoul-Henning Kamp usage(); 132c2ef0b73SPoul-Henning Kamp mdio.md_size = strtoul(optarg, &p, 0); 133c2ef0b73SPoul-Henning Kamp if (p == NULL || *p == '\0') 134c2ef0b73SPoul-Henning Kamp ; 135c2ef0b73SPoul-Henning Kamp else if (*p == 'k' || *p == 'K') 136c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 / DEV_BSIZE); 137c2ef0b73SPoul-Henning Kamp else if (*p == 'm' || *p == 'M') 138c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 * 1024 / DEV_BSIZE); 139c2ef0b73SPoul-Henning Kamp else if (*p == 'g' || *p == 'G') 140c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 * 1024 * 1024 / DEV_BSIZE); 14170d586c0SPoul-Henning Kamp else 142c2ef0b73SPoul-Henning Kamp errx(1, "Unknown suffix on -s argument"); 14370d586c0SPoul-Henning Kamp break; 14470d586c0SPoul-Henning Kamp case 'u': 1458f8def9eSPoul-Henning Kamp if (cmdline != 2 && cmdline != 3) 146c2ef0b73SPoul-Henning Kamp usage(); 147fb1023d6SPoul-Henning Kamp if (!strncmp(optarg, "/dev/", 5)) 148fb1023d6SPoul-Henning Kamp optarg += 5; 149174b5e9aSPoul-Henning Kamp if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) 150fb1023d6SPoul-Henning Kamp optarg += 2; 151fb1023d6SPoul-Henning Kamp mdio.md_unit = strtoul(optarg, NULL, 0); 15270d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_AUTOUNIT; 15370d586c0SPoul-Henning Kamp break; 15470d586c0SPoul-Henning Kamp default: 155c2ef0b73SPoul-Henning Kamp usage(); 15670d586c0SPoul-Henning Kamp } 15770d586c0SPoul-Henning Kamp } 15870d586c0SPoul-Henning Kamp 15957e9624eSPoul-Henning Kamp mdmaybeload(); 160174b5e9aSPoul-Henning Kamp fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 16170d586c0SPoul-Henning Kamp if (fd < 0) 162174b5e9aSPoul-Henning Kamp err(1, "open(/dev/%s)", MDCTL_NAME); 163174b5e9aSPoul-Henning Kamp if (action == LIST) { 164174b5e9aSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 165174b5e9aSPoul-Henning Kamp list(fd); 166174b5e9aSPoul-Henning Kamp else 167174b5e9aSPoul-Henning Kamp query(fd, mdio.md_unit); 168174b5e9aSPoul-Henning Kamp } else if (action == ATTACH) { 16970d586c0SPoul-Henning Kamp i = ioctl(fd, MDIOCATTACH, &mdio); 170174b5e9aSPoul-Henning Kamp if (i < 0) 171174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 1728f8def9eSPoul-Henning Kamp } else { 1738f8def9eSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 1748f8def9eSPoul-Henning Kamp usage(); 175c2ef0b73SPoul-Henning Kamp i = ioctl(fd, MDIOCDETACH, &mdio); 17670d586c0SPoul-Henning Kamp if (i < 0) 177174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 178174b5e9aSPoul-Henning Kamp } 1798f8def9eSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 180174b5e9aSPoul-Henning Kamp printf("%s%d\n", MD_NAME, mdio.md_unit); 181174b5e9aSPoul-Henning Kamp close (fd); 182174b5e9aSPoul-Henning Kamp return (0); 183174b5e9aSPoul-Henning Kamp } 184174b5e9aSPoul-Henning Kamp 185174b5e9aSPoul-Henning Kamp int 186174b5e9aSPoul-Henning Kamp intcmp(const void *a, const void *b) 187174b5e9aSPoul-Henning Kamp { 188174b5e9aSPoul-Henning Kamp 189174b5e9aSPoul-Henning Kamp return (*(int *)a - *(int *)b); 190174b5e9aSPoul-Henning Kamp } 191174b5e9aSPoul-Henning Kamp 192174b5e9aSPoul-Henning Kamp struct dl { 193174b5e9aSPoul-Henning Kamp int unit; 194174b5e9aSPoul-Henning Kamp SLIST_ENTRY(dl) slist; 195174b5e9aSPoul-Henning Kamp }; 196174b5e9aSPoul-Henning Kamp 197174b5e9aSPoul-Henning Kamp SLIST_HEAD(, dl) dlist = SLIST_HEAD_INITIALIZER(&dlist); 198174b5e9aSPoul-Henning Kamp 199174b5e9aSPoul-Henning Kamp int 200174b5e9aSPoul-Henning Kamp list(const int fd) 201174b5e9aSPoul-Henning Kamp { 202174b5e9aSPoul-Henning Kamp char *disklist, *p, *p2, *p3; 203174b5e9aSPoul-Henning Kamp int unit, dll; 204174b5e9aSPoul-Henning Kamp struct dl *dp, *di, *dn; 205174b5e9aSPoul-Henning Kamp 206174b5e9aSPoul-Henning Kamp if (sysctlbyname("kern.disks", NULL, &dll, NULL, NULL) == -1) 207174b5e9aSPoul-Henning Kamp err(1, "sysctlbyname: kern.disks"); 208174b5e9aSPoul-Henning Kamp if ( (disklist = malloc(dll)) == NULL) 209174b5e9aSPoul-Henning Kamp err(1, "malloc"); 210174b5e9aSPoul-Henning Kamp if (sysctlbyname("kern.disks", disklist, &dll, NULL, NULL) == -1) 211174b5e9aSPoul-Henning Kamp err(1, "sysctlbyname: kern.disks"); 212174b5e9aSPoul-Henning Kamp 213174b5e9aSPoul-Henning Kamp for (p = disklist; 214174b5e9aSPoul-Henning Kamp (p2 = strsep(&p, " ")) != NULL;) { 215174b5e9aSPoul-Henning Kamp if (strncmp(p2, MD_NAME, sizeof(MD_NAME) - 1) != 0) 216174b5e9aSPoul-Henning Kamp continue; 217174b5e9aSPoul-Henning Kamp p2 += 2; 218174b5e9aSPoul-Henning Kamp unit = strtoul(p2, &p3, 10); 219174b5e9aSPoul-Henning Kamp if (p2 == p3) 220174b5e9aSPoul-Henning Kamp continue; 221174b5e9aSPoul-Henning Kamp dp = calloc(sizeof *dp, 1); 222174b5e9aSPoul-Henning Kamp dp->unit = unit; 223174b5e9aSPoul-Henning Kamp dn = SLIST_FIRST(&dlist); 224174b5e9aSPoul-Henning Kamp if (dn == NULL || dn->unit > unit) { 225174b5e9aSPoul-Henning Kamp SLIST_INSERT_HEAD(&dlist, dp, slist); 226174b5e9aSPoul-Henning Kamp } else { 227174b5e9aSPoul-Henning Kamp SLIST_FOREACH(di, &dlist, slist) { 228174b5e9aSPoul-Henning Kamp dn = SLIST_NEXT(di, slist); 229174b5e9aSPoul-Henning Kamp if (dn == NULL || dn->unit > unit) { 230174b5e9aSPoul-Henning Kamp SLIST_INSERT_AFTER(di, dp, slist); 231174b5e9aSPoul-Henning Kamp break; 232174b5e9aSPoul-Henning Kamp } 233174b5e9aSPoul-Henning Kamp } 234174b5e9aSPoul-Henning Kamp } 235174b5e9aSPoul-Henning Kamp } 236174b5e9aSPoul-Henning Kamp SLIST_FOREACH(di, &dlist, slist) 237174b5e9aSPoul-Henning Kamp query(fd, di->unit); 238174b5e9aSPoul-Henning Kamp while (!SLIST_EMPTY(&dlist)) { 239174b5e9aSPoul-Henning Kamp di = SLIST_FIRST(&dlist); 240174b5e9aSPoul-Henning Kamp SLIST_REMOVE_HEAD(&dlist, slist); 241174b5e9aSPoul-Henning Kamp free(di); 242174b5e9aSPoul-Henning Kamp } 243174b5e9aSPoul-Henning Kamp free(disklist); 244174b5e9aSPoul-Henning Kamp return (0); 245174b5e9aSPoul-Henning Kamp } 246174b5e9aSPoul-Henning Kamp 247174b5e9aSPoul-Henning Kamp int 248174b5e9aSPoul-Henning Kamp query(const int fd, const int unit) 249174b5e9aSPoul-Henning Kamp { 250174b5e9aSPoul-Henning Kamp 251174b5e9aSPoul-Henning Kamp mdio.md_unit = unit; 252174b5e9aSPoul-Henning Kamp 253174b5e9aSPoul-Henning Kamp if (ioctl(fd, MDIOCQUERY, &mdio) < 0) 254174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 255174b5e9aSPoul-Henning Kamp 256174b5e9aSPoul-Henning Kamp switch (mdio.md_type) { 257174b5e9aSPoul-Henning Kamp case MD_MALLOC: 258174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tmalloc\t%d KBytes\n", MD_NAME, 259174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 260174b5e9aSPoul-Henning Kamp break; 261174b5e9aSPoul-Henning Kamp case MD_PRELOAD: 262174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tpreload\t%d KBytes\n", MD_NAME, 263174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 264174b5e9aSPoul-Henning Kamp break; 265174b5e9aSPoul-Henning Kamp case MD_SWAP: 266174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tswap\t%d KBytes\n", MD_NAME, 267174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 268174b5e9aSPoul-Henning Kamp break; 269174b5e9aSPoul-Henning Kamp case MD_VNODE: 270174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tvnode\t%d KBytes\n", MD_NAME, 271174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 272174b5e9aSPoul-Henning Kamp break; 273174b5e9aSPoul-Henning Kamp } 274174b5e9aSPoul-Henning Kamp 27570d586c0SPoul-Henning Kamp return (0); 27670d586c0SPoul-Henning Kamp } 27770d586c0SPoul-Henning Kamp 27857e9624eSPoul-Henning Kamp void 27957e9624eSPoul-Henning Kamp mdmaybeload(void) 28057e9624eSPoul-Henning Kamp { 28157e9624eSPoul-Henning Kamp struct module_stat mstat; 28257e9624eSPoul-Henning Kamp int fileid, modid; 28357e9624eSPoul-Henning Kamp char *name = "md"; 28457e9624eSPoul-Henning Kamp char *cp; 28557e9624eSPoul-Henning Kamp 28657e9624eSPoul-Henning Kamp /* scan files in kernel */ 28757e9624eSPoul-Henning Kamp mstat.version = sizeof(struct module_stat); 28857e9624eSPoul-Henning Kamp for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 28957e9624eSPoul-Henning Kamp /* scan modules in file */ 29057e9624eSPoul-Henning Kamp for (modid = kldfirstmod(fileid); modid > 0; 29157e9624eSPoul-Henning Kamp modid = modfnext(modid)) { 29257e9624eSPoul-Henning Kamp if (modstat(modid, &mstat) < 0) 29357e9624eSPoul-Henning Kamp continue; 29457e9624eSPoul-Henning Kamp /* strip bus name if present */ 29557e9624eSPoul-Henning Kamp if ((cp = strchr(mstat.name, '/')) != NULL) { 29657e9624eSPoul-Henning Kamp cp++; 29757e9624eSPoul-Henning Kamp } else { 29857e9624eSPoul-Henning Kamp cp = mstat.name; 29957e9624eSPoul-Henning Kamp } 30057e9624eSPoul-Henning Kamp /* already loaded? */ 30157e9624eSPoul-Henning Kamp if (!strcmp(name, cp)) 30257e9624eSPoul-Henning Kamp return; 30357e9624eSPoul-Henning Kamp } 30457e9624eSPoul-Henning Kamp } 30557e9624eSPoul-Henning Kamp /* not present, we should try to load it */ 30657e9624eSPoul-Henning Kamp kldload(name); 30757e9624eSPoul-Henning Kamp } 30857e9624eSPoul-Henning Kamp 309