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 list(const int); 28174b5e9aSPoul-Henning Kamp int query(const int, const int); 2970d586c0SPoul-Henning Kamp 3070d586c0SPoul-Henning Kamp struct md_ioctl mdio; 3170d586c0SPoul-Henning Kamp 32174b5e9aSPoul-Henning Kamp enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; 3370d586c0SPoul-Henning Kamp 3457e9624eSPoul-Henning Kamp void mdmaybeload(void); 3557e9624eSPoul-Henning Kamp 36c2ef0b73SPoul-Henning Kamp void 37c2ef0b73SPoul-Henning Kamp usage() 38c2ef0b73SPoul-Henning Kamp { 398f8def9eSPoul-Henning Kamp fprintf(stderr, "Usage:\n"); 408f8def9eSPoul-Henning Kamp fprintf(stderr, "\tmdconfig -a -t type [-o [no]option]... [ -f file] [-s size] [-u unit]\n"); 418f8def9eSPoul-Henning Kamp fprintf(stderr, "\tmdconfig -d -u unit\n"); 42174b5e9aSPoul-Henning Kamp fprintf(stderr, "\tmdconfig -l [-u unit]\n"); 43c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n"); 443f6f9216SPoul-Henning Kamp fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n"); 45c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%dk (kB), %%dm (MB) or %%dg (GB)\n"); 46c2ef0b73SPoul-Henning Kamp exit(1); 47c2ef0b73SPoul-Henning Kamp } 48c2ef0b73SPoul-Henning Kamp 4970d586c0SPoul-Henning Kamp int 5070d586c0SPoul-Henning Kamp main(int argc, char **argv) 5170d586c0SPoul-Henning Kamp { 5270d586c0SPoul-Henning Kamp int ch, fd, i; 53c2ef0b73SPoul-Henning Kamp char *p; 54c2ef0b73SPoul-Henning Kamp int cmdline = 0; 5570d586c0SPoul-Henning Kamp 5670d586c0SPoul-Henning Kamp for (;;) { 57174b5e9aSPoul-Henning Kamp ch = getopt(argc, argv, "ab:df:lo:s:t:u:"); 5870d586c0SPoul-Henning Kamp if (ch == -1) 5970d586c0SPoul-Henning Kamp break; 6070d586c0SPoul-Henning Kamp switch (ch) { 6170d586c0SPoul-Henning Kamp case 'a': 62c2ef0b73SPoul-Henning Kamp if (cmdline != 0) 63c2ef0b73SPoul-Henning Kamp usage(); 6470d586c0SPoul-Henning Kamp action = ATTACH; 65c2ef0b73SPoul-Henning Kamp cmdline = 1; 6670d586c0SPoul-Henning Kamp break; 6770d586c0SPoul-Henning Kamp case 'd': 68c2ef0b73SPoul-Henning Kamp if (cmdline != 0) 69c2ef0b73SPoul-Henning Kamp usage(); 7070d586c0SPoul-Henning Kamp action = DETACH; 718f8def9eSPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT; 728f8def9eSPoul-Henning Kamp cmdline = 3; 73c2ef0b73SPoul-Henning Kamp break; 74174b5e9aSPoul-Henning Kamp case 'l': 75174b5e9aSPoul-Henning Kamp if (cmdline != 0) 76174b5e9aSPoul-Henning Kamp usage(); 77174b5e9aSPoul-Henning Kamp action = LIST; 78174b5e9aSPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT; 79174b5e9aSPoul-Henning Kamp cmdline = 3; 80174b5e9aSPoul-Henning Kamp break; 81c2ef0b73SPoul-Henning Kamp case 't': 82c2ef0b73SPoul-Henning Kamp if (cmdline != 1) 83c2ef0b73SPoul-Henning Kamp usage(); 84c2ef0b73SPoul-Henning Kamp if (!strcmp(optarg, "malloc")) { 85c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_MALLOC; 86c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; 87c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "preload")) { 88c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_PRELOAD; 89c2ef0b73SPoul-Henning Kamp mdio.md_options = 0; 90c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "vnode")) { 91c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_VNODE; 92c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 93c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "swap")) { 94c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_SWAP; 95c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 96c2ef0b73SPoul-Henning Kamp } else { 97c2ef0b73SPoul-Henning Kamp usage(); 98c2ef0b73SPoul-Henning Kamp } 99c2ef0b73SPoul-Henning Kamp cmdline=2; 10070d586c0SPoul-Henning Kamp break; 10170d586c0SPoul-Henning Kamp case 'f': 102c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 103c2ef0b73SPoul-Henning Kamp usage(); 1043b42f2f3SPoul-Henning Kamp mdio.md_file = optarg; 10570d586c0SPoul-Henning Kamp break; 10670d586c0SPoul-Henning Kamp case 'o': 107c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 108c2ef0b73SPoul-Henning Kamp usage(); 10970d586c0SPoul-Henning Kamp if (!strcmp(optarg, "cluster")) 11070d586c0SPoul-Henning Kamp mdio.md_options |= MD_CLUSTER; 11170d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "nocluster")) 11270d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_CLUSTER; 113c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "compress")) 114c2ef0b73SPoul-Henning Kamp mdio.md_options |= MD_COMPRESS; 115c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "nocompress")) 116c2ef0b73SPoul-Henning Kamp mdio.md_options &= ~MD_COMPRESS; 11770d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "reserve")) 11870d586c0SPoul-Henning Kamp mdio.md_options |= MD_RESERVE; 11970d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "noreserve")) 12070d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_RESERVE; 12170d586c0SPoul-Henning Kamp else 12270d586c0SPoul-Henning Kamp errx(1, "Unknown option."); 12370d586c0SPoul-Henning Kamp break; 12470d586c0SPoul-Henning Kamp case 's': 125c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 126c2ef0b73SPoul-Henning Kamp usage(); 127c2ef0b73SPoul-Henning Kamp mdio.md_size = strtoul(optarg, &p, 0); 128c2ef0b73SPoul-Henning Kamp if (p == NULL || *p == '\0') 129c2ef0b73SPoul-Henning Kamp ; 130c2ef0b73SPoul-Henning Kamp else if (*p == 'k' || *p == 'K') 131c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 / DEV_BSIZE); 132c2ef0b73SPoul-Henning Kamp else if (*p == 'm' || *p == 'M') 133c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 * 1024 / DEV_BSIZE); 134c2ef0b73SPoul-Henning Kamp else if (*p == 'g' || *p == 'G') 135c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 * 1024 * 1024 / DEV_BSIZE); 13670d586c0SPoul-Henning Kamp else 137c2ef0b73SPoul-Henning Kamp errx(1, "Unknown suffix on -s argument"); 13870d586c0SPoul-Henning Kamp break; 13970d586c0SPoul-Henning Kamp case 'u': 1408f8def9eSPoul-Henning Kamp if (cmdline != 2 && cmdline != 3) 141c2ef0b73SPoul-Henning Kamp usage(); 142fb1023d6SPoul-Henning Kamp if (!strncmp(optarg, "/dev/", 5)) 143fb1023d6SPoul-Henning Kamp optarg += 5; 144174b5e9aSPoul-Henning Kamp if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) 145fb1023d6SPoul-Henning Kamp optarg += 2; 146fb1023d6SPoul-Henning Kamp mdio.md_unit = strtoul(optarg, NULL, 0); 14770d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_AUTOUNIT; 14870d586c0SPoul-Henning Kamp break; 14970d586c0SPoul-Henning Kamp default: 150c2ef0b73SPoul-Henning Kamp usage(); 15170d586c0SPoul-Henning Kamp } 15270d586c0SPoul-Henning Kamp } 15370d586c0SPoul-Henning Kamp 15457e9624eSPoul-Henning Kamp mdmaybeload(); 155174b5e9aSPoul-Henning Kamp fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 15670d586c0SPoul-Henning Kamp if (fd < 0) 157174b5e9aSPoul-Henning Kamp err(1, "open(/dev/%s)", MDCTL_NAME); 158174b5e9aSPoul-Henning Kamp if (action == LIST) { 159174b5e9aSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 160174b5e9aSPoul-Henning Kamp list(fd); 161174b5e9aSPoul-Henning Kamp else 162174b5e9aSPoul-Henning Kamp query(fd, mdio.md_unit); 163174b5e9aSPoul-Henning Kamp } else if (action == ATTACH) { 16470d586c0SPoul-Henning Kamp i = ioctl(fd, MDIOCATTACH, &mdio); 165174b5e9aSPoul-Henning Kamp if (i < 0) 166174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 16783da2a90SPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 16883da2a90SPoul-Henning Kamp printf("%s%d\n", MD_NAME, mdio.md_unit); 16983da2a90SPoul-Henning Kamp } else if (action == DETACH) { 1708f8def9eSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 1718f8def9eSPoul-Henning Kamp usage(); 172c2ef0b73SPoul-Henning Kamp i = ioctl(fd, MDIOCDETACH, &mdio); 17370d586c0SPoul-Henning Kamp if (i < 0) 174174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 17583da2a90SPoul-Henning Kamp } else 17683da2a90SPoul-Henning Kamp usage(); 177174b5e9aSPoul-Henning Kamp close (fd); 178174b5e9aSPoul-Henning Kamp return (0); 179174b5e9aSPoul-Henning Kamp } 180174b5e9aSPoul-Henning Kamp 181174b5e9aSPoul-Henning Kamp struct dl { 182174b5e9aSPoul-Henning Kamp int unit; 183174b5e9aSPoul-Henning Kamp SLIST_ENTRY(dl) slist; 184174b5e9aSPoul-Henning Kamp }; 185174b5e9aSPoul-Henning Kamp 186174b5e9aSPoul-Henning Kamp SLIST_HEAD(, dl) dlist = SLIST_HEAD_INITIALIZER(&dlist); 187174b5e9aSPoul-Henning Kamp 188174b5e9aSPoul-Henning Kamp int 189174b5e9aSPoul-Henning Kamp list(const int fd) 190174b5e9aSPoul-Henning Kamp { 191174b5e9aSPoul-Henning Kamp char *disklist, *p, *p2, *p3; 192174b5e9aSPoul-Henning Kamp int unit, dll; 193174b5e9aSPoul-Henning Kamp struct dl *dp, *di, *dn; 194174b5e9aSPoul-Henning Kamp 195174b5e9aSPoul-Henning Kamp if (sysctlbyname("kern.disks", NULL, &dll, NULL, NULL) == -1) 196174b5e9aSPoul-Henning Kamp err(1, "sysctlbyname: kern.disks"); 197174b5e9aSPoul-Henning Kamp if ( (disklist = malloc(dll)) == NULL) 198174b5e9aSPoul-Henning Kamp err(1, "malloc"); 199174b5e9aSPoul-Henning Kamp if (sysctlbyname("kern.disks", disklist, &dll, NULL, NULL) == -1) 200174b5e9aSPoul-Henning Kamp err(1, "sysctlbyname: kern.disks"); 201174b5e9aSPoul-Henning Kamp 202174b5e9aSPoul-Henning Kamp for (p = disklist; 203174b5e9aSPoul-Henning Kamp (p2 = strsep(&p, " ")) != NULL;) { 204174b5e9aSPoul-Henning Kamp if (strncmp(p2, MD_NAME, sizeof(MD_NAME) - 1) != 0) 205174b5e9aSPoul-Henning Kamp continue; 206174b5e9aSPoul-Henning Kamp p2 += 2; 207174b5e9aSPoul-Henning Kamp unit = strtoul(p2, &p3, 10); 208174b5e9aSPoul-Henning Kamp if (p2 == p3) 209174b5e9aSPoul-Henning Kamp continue; 210174b5e9aSPoul-Henning Kamp dp = calloc(sizeof *dp, 1); 211174b5e9aSPoul-Henning Kamp dp->unit = unit; 212174b5e9aSPoul-Henning Kamp dn = SLIST_FIRST(&dlist); 213174b5e9aSPoul-Henning Kamp if (dn == NULL || dn->unit > unit) { 214174b5e9aSPoul-Henning Kamp SLIST_INSERT_HEAD(&dlist, dp, slist); 215174b5e9aSPoul-Henning Kamp } else { 216174b5e9aSPoul-Henning Kamp SLIST_FOREACH(di, &dlist, slist) { 217174b5e9aSPoul-Henning Kamp dn = SLIST_NEXT(di, slist); 218174b5e9aSPoul-Henning Kamp if (dn == NULL || dn->unit > unit) { 219174b5e9aSPoul-Henning Kamp SLIST_INSERT_AFTER(di, dp, slist); 220174b5e9aSPoul-Henning Kamp break; 221174b5e9aSPoul-Henning Kamp } 222174b5e9aSPoul-Henning Kamp } 223174b5e9aSPoul-Henning Kamp } 224174b5e9aSPoul-Henning Kamp } 225174b5e9aSPoul-Henning Kamp SLIST_FOREACH(di, &dlist, slist) 226174b5e9aSPoul-Henning Kamp query(fd, di->unit); 227174b5e9aSPoul-Henning Kamp while (!SLIST_EMPTY(&dlist)) { 228174b5e9aSPoul-Henning Kamp di = SLIST_FIRST(&dlist); 229174b5e9aSPoul-Henning Kamp SLIST_REMOVE_HEAD(&dlist, slist); 230174b5e9aSPoul-Henning Kamp free(di); 231174b5e9aSPoul-Henning Kamp } 232174b5e9aSPoul-Henning Kamp free(disklist); 233174b5e9aSPoul-Henning Kamp return (0); 234174b5e9aSPoul-Henning Kamp } 235174b5e9aSPoul-Henning Kamp 236174b5e9aSPoul-Henning Kamp int 237174b5e9aSPoul-Henning Kamp query(const int fd, const int unit) 238174b5e9aSPoul-Henning Kamp { 239174b5e9aSPoul-Henning Kamp 240174b5e9aSPoul-Henning Kamp mdio.md_unit = unit; 241174b5e9aSPoul-Henning Kamp 242174b5e9aSPoul-Henning Kamp if (ioctl(fd, MDIOCQUERY, &mdio) < 0) 243174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 244174b5e9aSPoul-Henning Kamp 245174b5e9aSPoul-Henning Kamp switch (mdio.md_type) { 246174b5e9aSPoul-Henning Kamp case MD_MALLOC: 247174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tmalloc\t%d KBytes\n", MD_NAME, 248174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 249174b5e9aSPoul-Henning Kamp break; 250174b5e9aSPoul-Henning Kamp case MD_PRELOAD: 251174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tpreload\t%d KBytes\n", MD_NAME, 252174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 253174b5e9aSPoul-Henning Kamp break; 254174b5e9aSPoul-Henning Kamp case MD_SWAP: 255174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tswap\t%d KBytes\n", MD_NAME, 256174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 257174b5e9aSPoul-Henning Kamp break; 258174b5e9aSPoul-Henning Kamp case MD_VNODE: 259174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tvnode\t%d KBytes\n", MD_NAME, 260174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 261174b5e9aSPoul-Henning Kamp break; 262174b5e9aSPoul-Henning Kamp } 263174b5e9aSPoul-Henning Kamp 26470d586c0SPoul-Henning Kamp return (0); 26570d586c0SPoul-Henning Kamp } 26670d586c0SPoul-Henning Kamp 26757e9624eSPoul-Henning Kamp void 26857e9624eSPoul-Henning Kamp mdmaybeload(void) 26957e9624eSPoul-Henning Kamp { 27057e9624eSPoul-Henning Kamp struct module_stat mstat; 27157e9624eSPoul-Henning Kamp int fileid, modid; 27257e9624eSPoul-Henning Kamp char *name = "md"; 27357e9624eSPoul-Henning Kamp char *cp; 27457e9624eSPoul-Henning Kamp 27557e9624eSPoul-Henning Kamp /* scan files in kernel */ 27657e9624eSPoul-Henning Kamp mstat.version = sizeof(struct module_stat); 27757e9624eSPoul-Henning Kamp for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 27857e9624eSPoul-Henning Kamp /* scan modules in file */ 27957e9624eSPoul-Henning Kamp for (modid = kldfirstmod(fileid); modid > 0; 28057e9624eSPoul-Henning Kamp modid = modfnext(modid)) { 28157e9624eSPoul-Henning Kamp if (modstat(modid, &mstat) < 0) 28257e9624eSPoul-Henning Kamp continue; 28357e9624eSPoul-Henning Kamp /* strip bus name if present */ 28457e9624eSPoul-Henning Kamp if ((cp = strchr(mstat.name, '/')) != NULL) { 28557e9624eSPoul-Henning Kamp cp++; 28657e9624eSPoul-Henning Kamp } else { 28757e9624eSPoul-Henning Kamp cp = mstat.name; 28857e9624eSPoul-Henning Kamp } 28957e9624eSPoul-Henning Kamp /* already loaded? */ 29057e9624eSPoul-Henning Kamp if (!strcmp(name, cp)) 29157e9624eSPoul-Henning Kamp return; 29257e9624eSPoul-Henning Kamp } 29357e9624eSPoul-Henning Kamp } 29457e9624eSPoul-Henning Kamp /* not present, we should try to load it */ 29557e9624eSPoul-Henning Kamp kldload(name); 29657e9624eSPoul-Henning Kamp } 29757e9624eSPoul-Henning Kamp 298