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); 283fa96e66SDima Dorfman void mdmaybeload(void); 29174b5e9aSPoul-Henning Kamp int query(const int, const int); 303fa96e66SDima Dorfman void usage(void); 3170d586c0SPoul-Henning Kamp 3270d586c0SPoul-Henning Kamp struct md_ioctl mdio; 3370d586c0SPoul-Henning Kamp 34174b5e9aSPoul-Henning Kamp enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; 3570d586c0SPoul-Henning Kamp 36f79c46d3SRobert Watson int nflag; 37f79c46d3SRobert Watson 38c2ef0b73SPoul-Henning Kamp void 39c2ef0b73SPoul-Henning Kamp usage() 40c2ef0b73SPoul-Henning Kamp { 41d3974088SDag-Erling Smørgrav fprintf(stderr, "usage:\n"); 42f79c46d3SRobert Watson fprintf(stderr, "\tmdconfig -a -t type [-n] [-o [no]option]... [ -f file] [-s size] [-S sectorsize] [-u unit]\n"); 438f8def9eSPoul-Henning Kamp fprintf(stderr, "\tmdconfig -d -u unit\n"); 44f79c46d3SRobert Watson fprintf(stderr, "\tmdconfig -l [-n] [-u unit]\n"); 45c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n"); 463f6f9216SPoul-Henning Kamp fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n"); 47c2ef0b73SPoul-Henning Kamp fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%dk (kB), %%dm (MB) or %%dg (GB)\n"); 48c2ef0b73SPoul-Henning Kamp exit(1); 49c2ef0b73SPoul-Henning Kamp } 50c2ef0b73SPoul-Henning Kamp 5170d586c0SPoul-Henning Kamp int 5270d586c0SPoul-Henning Kamp main(int argc, char **argv) 5370d586c0SPoul-Henning Kamp { 5470d586c0SPoul-Henning Kamp int ch, fd, i; 55c2ef0b73SPoul-Henning Kamp char *p; 56c2ef0b73SPoul-Henning Kamp int cmdline = 0; 5770d586c0SPoul-Henning Kamp 5870d586c0SPoul-Henning Kamp for (;;) { 59f79c46d3SRobert Watson ch = getopt(argc, argv, "ab:df:lno:s:S:t:u:x:y:"); 6070d586c0SPoul-Henning Kamp if (ch == -1) 6170d586c0SPoul-Henning Kamp break; 6270d586c0SPoul-Henning Kamp switch (ch) { 6370d586c0SPoul-Henning Kamp case 'a': 64c2ef0b73SPoul-Henning Kamp if (cmdline != 0) 65c2ef0b73SPoul-Henning Kamp usage(); 6670d586c0SPoul-Henning Kamp action = ATTACH; 67c2ef0b73SPoul-Henning Kamp cmdline = 1; 6870d586c0SPoul-Henning Kamp break; 6970d586c0SPoul-Henning Kamp case 'd': 70c2ef0b73SPoul-Henning Kamp if (cmdline != 0) 71c2ef0b73SPoul-Henning Kamp usage(); 7270d586c0SPoul-Henning Kamp action = DETACH; 738f8def9eSPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT; 748f8def9eSPoul-Henning Kamp cmdline = 3; 75c2ef0b73SPoul-Henning Kamp break; 76174b5e9aSPoul-Henning Kamp case 'l': 77174b5e9aSPoul-Henning Kamp if (cmdline != 0) 78174b5e9aSPoul-Henning Kamp usage(); 79174b5e9aSPoul-Henning Kamp action = LIST; 80174b5e9aSPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT; 81174b5e9aSPoul-Henning Kamp cmdline = 3; 82174b5e9aSPoul-Henning Kamp break; 83f79c46d3SRobert Watson case 'n': 84f79c46d3SRobert Watson nflag = 1; 85f79c46d3SRobert Watson break; 86c2ef0b73SPoul-Henning Kamp case 't': 87c2ef0b73SPoul-Henning Kamp if (cmdline != 1) 88c2ef0b73SPoul-Henning Kamp usage(); 89c2ef0b73SPoul-Henning Kamp if (!strcmp(optarg, "malloc")) { 90c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_MALLOC; 91c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; 92c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "preload")) { 93c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_PRELOAD; 94c2ef0b73SPoul-Henning Kamp mdio.md_options = 0; 95c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "vnode")) { 96c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_VNODE; 97c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 98c2ef0b73SPoul-Henning Kamp } else if (!strcmp(optarg, "swap")) { 99c2ef0b73SPoul-Henning Kamp mdio.md_type = MD_SWAP; 100c2ef0b73SPoul-Henning Kamp mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 101c2ef0b73SPoul-Henning Kamp } else { 102c2ef0b73SPoul-Henning Kamp usage(); 103c2ef0b73SPoul-Henning Kamp } 104c2ef0b73SPoul-Henning Kamp cmdline=2; 10570d586c0SPoul-Henning Kamp break; 10670d586c0SPoul-Henning Kamp case 'f': 107ed23a390SMaxim Sobolev if (cmdline != 1 && cmdline != 2) 108c2ef0b73SPoul-Henning Kamp usage(); 109ed23a390SMaxim Sobolev if (cmdline == 1) { 110ed23a390SMaxim Sobolev /* Imply ``-t vnode'' */ 111ed23a390SMaxim Sobolev mdio.md_type = MD_VNODE; 112ed23a390SMaxim Sobolev mdio.md_options = MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS; 113252bcf45SYaroslav Tykhiy cmdline = 2; 114ed23a390SMaxim Sobolev } 1153b42f2f3SPoul-Henning Kamp mdio.md_file = optarg; 116e869d377SPoul-Henning Kamp fd = open(optarg, O_RDONLY); 117e869d377SPoul-Henning Kamp if (fd < 0) 118e869d377SPoul-Henning Kamp err(1, "could not open %s", optarg); 119e869d377SPoul-Henning Kamp close(fd); 12070d586c0SPoul-Henning Kamp break; 12170d586c0SPoul-Henning Kamp case 'o': 122c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 123c2ef0b73SPoul-Henning Kamp usage(); 1247a6b2b64SPoul-Henning Kamp if (!strcmp(optarg, "async")) 1257a6b2b64SPoul-Henning Kamp mdio.md_options |= MD_ASYNC; 1267a6b2b64SPoul-Henning Kamp else if (!strcmp(optarg, "noasync")) 1277a6b2b64SPoul-Henning Kamp mdio.md_options &= ~MD_ASYNC; 1287a6b2b64SPoul-Henning Kamp else if (!strcmp(optarg, "cluster")) 12970d586c0SPoul-Henning Kamp mdio.md_options |= MD_CLUSTER; 13070d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "nocluster")) 13170d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_CLUSTER; 132c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "compress")) 133c2ef0b73SPoul-Henning Kamp mdio.md_options |= MD_COMPRESS; 134c2ef0b73SPoul-Henning Kamp else if (!strcmp(optarg, "nocompress")) 135c2ef0b73SPoul-Henning Kamp mdio.md_options &= ~MD_COMPRESS; 13626a0ee75SDima Dorfman else if (!strcmp(optarg, "force")) 13726a0ee75SDima Dorfman mdio.md_options |= MD_FORCE; 13826a0ee75SDima Dorfman else if (!strcmp(optarg, "noforce")) 13926a0ee75SDima Dorfman mdio.md_options &= ~MD_FORCE; 140d31ba625SJohn-Mark Gurney else if (!strcmp(optarg, "readonly")) 141d31ba625SJohn-Mark Gurney mdio.md_options |= MD_READONLY; 142d31ba625SJohn-Mark Gurney else if (!strcmp(optarg, "noreadonly")) 143d31ba625SJohn-Mark Gurney mdio.md_options &= ~MD_READONLY; 14470d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "reserve")) 14570d586c0SPoul-Henning Kamp mdio.md_options |= MD_RESERVE; 14670d586c0SPoul-Henning Kamp else if (!strcmp(optarg, "noreserve")) 14770d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_RESERVE; 14870d586c0SPoul-Henning Kamp else 149d31ba625SJohn-Mark Gurney errx(1, "Unknown option: %s.", optarg); 15070d586c0SPoul-Henning Kamp break; 151ebe789d6SPoul-Henning Kamp case 'S': 152ebe789d6SPoul-Henning Kamp if (cmdline != 2) 153ebe789d6SPoul-Henning Kamp usage(); 154ebe789d6SPoul-Henning Kamp mdio.md_secsize = strtoul(optarg, &p, 0); 155ebe789d6SPoul-Henning Kamp break; 15670d586c0SPoul-Henning Kamp case 's': 157c2ef0b73SPoul-Henning Kamp if (cmdline != 2) 158c2ef0b73SPoul-Henning Kamp usage(); 159c2ef0b73SPoul-Henning Kamp mdio.md_size = strtoul(optarg, &p, 0); 160c2ef0b73SPoul-Henning Kamp if (p == NULL || *p == '\0') 161c2ef0b73SPoul-Henning Kamp ; 162c2ef0b73SPoul-Henning Kamp else if (*p == 'k' || *p == 'K') 163c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 / DEV_BSIZE); 164c2ef0b73SPoul-Henning Kamp else if (*p == 'm' || *p == 'M') 165c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 * 1024 / DEV_BSIZE); 166c2ef0b73SPoul-Henning Kamp else if (*p == 'g' || *p == 'G') 167c2ef0b73SPoul-Henning Kamp mdio.md_size *= (1024 * 1024 * 1024 / DEV_BSIZE); 16870d586c0SPoul-Henning Kamp else 169c2ef0b73SPoul-Henning Kamp errx(1, "Unknown suffix on -s argument"); 17070d586c0SPoul-Henning Kamp break; 17170d586c0SPoul-Henning Kamp case 'u': 1728f8def9eSPoul-Henning Kamp if (cmdline != 2 && cmdline != 3) 173c2ef0b73SPoul-Henning Kamp usage(); 174fb1023d6SPoul-Henning Kamp if (!strncmp(optarg, "/dev/", 5)) 175fb1023d6SPoul-Henning Kamp optarg += 5; 176174b5e9aSPoul-Henning Kamp if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) 17778baea25SDima Dorfman optarg += sizeof(MD_NAME) - 1; 1782885b421SDima Dorfman mdio.md_unit = strtoul(optarg, &p, 0); 1798a50130bSAlexander Kabaev if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0') 1802885b421SDima Dorfman errx(1, "bad unit: %s", optarg); 18170d586c0SPoul-Henning Kamp mdio.md_options &= ~MD_AUTOUNIT; 18270d586c0SPoul-Henning Kamp break; 1834e8bfe14SPoul-Henning Kamp case 'x': 1844e8bfe14SPoul-Henning Kamp if (cmdline != 2) 1854e8bfe14SPoul-Henning Kamp usage(); 1864e8bfe14SPoul-Henning Kamp mdio.md_fwsectors = strtoul(optarg, &p, 0); 1874e8bfe14SPoul-Henning Kamp break; 1884e8bfe14SPoul-Henning Kamp case 'y': 1894e8bfe14SPoul-Henning Kamp if (cmdline != 2) 1904e8bfe14SPoul-Henning Kamp usage(); 1914e8bfe14SPoul-Henning Kamp mdio.md_fwheads = strtoul(optarg, &p, 0); 1924e8bfe14SPoul-Henning Kamp break; 19370d586c0SPoul-Henning Kamp default: 194c2ef0b73SPoul-Henning Kamp usage(); 19570d586c0SPoul-Henning Kamp } 19670d586c0SPoul-Henning Kamp } 19753d745bcSDima Dorfman mdio.md_version = MDIOVERSION; 19870d586c0SPoul-Henning Kamp 19957e9624eSPoul-Henning Kamp mdmaybeload(); 200174b5e9aSPoul-Henning Kamp fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 20170d586c0SPoul-Henning Kamp if (fd < 0) 202174b5e9aSPoul-Henning Kamp err(1, "open(/dev/%s)", MDCTL_NAME); 2032885b421SDima Dorfman if (cmdline == 2 2042885b421SDima Dorfman && (mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP)) 2052885b421SDima Dorfman if (mdio.md_size == 0) 2062885b421SDima Dorfman errx(1, "must specify -s for -t malloc or -t swap"); 207252bcf45SYaroslav Tykhiy if (cmdline == 2 && mdio.md_type == MD_VNODE) 208252bcf45SYaroslav Tykhiy if (mdio.md_file == NULL) 209252bcf45SYaroslav Tykhiy errx(1, "must specify -f for -t vnode"); 210174b5e9aSPoul-Henning Kamp if (action == LIST) { 211174b5e9aSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 212174b5e9aSPoul-Henning Kamp list(fd); 213174b5e9aSPoul-Henning Kamp else 214174b5e9aSPoul-Henning Kamp query(fd, mdio.md_unit); 215174b5e9aSPoul-Henning Kamp } else if (action == ATTACH) { 216252bcf45SYaroslav Tykhiy if (cmdline < 2) 217252bcf45SYaroslav Tykhiy usage(); 21870d586c0SPoul-Henning Kamp i = ioctl(fd, MDIOCATTACH, &mdio); 219174b5e9aSPoul-Henning Kamp if (i < 0) 220174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 22183da2a90SPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 222f79c46d3SRobert Watson printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit); 22383da2a90SPoul-Henning Kamp } else if (action == DETACH) { 2248f8def9eSPoul-Henning Kamp if (mdio.md_options & MD_AUTOUNIT) 2258f8def9eSPoul-Henning Kamp usage(); 226c2ef0b73SPoul-Henning Kamp i = ioctl(fd, MDIOCDETACH, &mdio); 22770d586c0SPoul-Henning Kamp if (i < 0) 228174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 22983da2a90SPoul-Henning Kamp } else 23083da2a90SPoul-Henning Kamp usage(); 231174b5e9aSPoul-Henning Kamp close (fd); 232174b5e9aSPoul-Henning Kamp return (0); 233174b5e9aSPoul-Henning Kamp } 234174b5e9aSPoul-Henning Kamp 235174b5e9aSPoul-Henning Kamp struct dl { 236174b5e9aSPoul-Henning Kamp int unit; 237174b5e9aSPoul-Henning Kamp SLIST_ENTRY(dl) slist; 238174b5e9aSPoul-Henning Kamp }; 239174b5e9aSPoul-Henning Kamp 240174b5e9aSPoul-Henning Kamp SLIST_HEAD(, dl) dlist = SLIST_HEAD_INITIALIZER(&dlist); 241174b5e9aSPoul-Henning Kamp 242174b5e9aSPoul-Henning Kamp int 243174b5e9aSPoul-Henning Kamp list(const int fd) 244174b5e9aSPoul-Henning Kamp { 245c894b25aSDima Dorfman int unit; 246174b5e9aSPoul-Henning Kamp 247e39eff98SPoul-Henning Kamp if (ioctl(fd, MDIOCLIST, &mdio) < 0) 248e39eff98SPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 249e39eff98SPoul-Henning Kamp for (unit = 0; unit < mdio.md_pad[0] && unit < MDNPAD - 1; unit++) { 250f79c46d3SRobert Watson printf("%s%s%d", unit > 0 ? " " : "", 251f79c46d3SRobert Watson nflag ? "" : MD_NAME, mdio.md_pad[unit + 1]); 252174b5e9aSPoul-Henning Kamp } 253e39eff98SPoul-Henning Kamp if (mdio.md_pad[0] - unit > 0) 254e39eff98SPoul-Henning Kamp printf(" ... %d more", mdio.md_pad[0] - unit); 255e39eff98SPoul-Henning Kamp printf("\n"); 256174b5e9aSPoul-Henning Kamp return (0); 257174b5e9aSPoul-Henning Kamp } 258174b5e9aSPoul-Henning Kamp 259174b5e9aSPoul-Henning Kamp int 260174b5e9aSPoul-Henning Kamp query(const int fd, const int unit) 261174b5e9aSPoul-Henning Kamp { 262174b5e9aSPoul-Henning Kamp 26353d745bcSDima Dorfman mdio.md_version = MDIOVERSION; 264174b5e9aSPoul-Henning Kamp mdio.md_unit = unit; 265174b5e9aSPoul-Henning Kamp 266174b5e9aSPoul-Henning Kamp if (ioctl(fd, MDIOCQUERY, &mdio) < 0) 267174b5e9aSPoul-Henning Kamp err(1, "ioctl(/dev/%s)", MDCTL_NAME); 268174b5e9aSPoul-Henning Kamp 269174b5e9aSPoul-Henning Kamp switch (mdio.md_type) { 270174b5e9aSPoul-Henning Kamp case MD_MALLOC: 271174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tmalloc\t%d KBytes\n", MD_NAME, 272174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 273174b5e9aSPoul-Henning Kamp break; 274174b5e9aSPoul-Henning Kamp case MD_PRELOAD: 275174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tpreload\t%d KBytes\n", MD_NAME, 276174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 277174b5e9aSPoul-Henning Kamp break; 278174b5e9aSPoul-Henning Kamp case MD_SWAP: 279174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tswap\t%d KBytes\n", MD_NAME, 280174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 281174b5e9aSPoul-Henning Kamp break; 282174b5e9aSPoul-Henning Kamp case MD_VNODE: 283174b5e9aSPoul-Henning Kamp (void)printf("%s%d\tvnode\t%d KBytes\n", MD_NAME, 284174b5e9aSPoul-Henning Kamp mdio.md_unit, mdio.md_size / 2); 285174b5e9aSPoul-Henning Kamp break; 286174b5e9aSPoul-Henning Kamp } 287174b5e9aSPoul-Henning Kamp 28870d586c0SPoul-Henning Kamp return (0); 28970d586c0SPoul-Henning Kamp } 29070d586c0SPoul-Henning Kamp 29157e9624eSPoul-Henning Kamp void 29257e9624eSPoul-Henning Kamp mdmaybeload(void) 29357e9624eSPoul-Henning Kamp { 29457e9624eSPoul-Henning Kamp struct module_stat mstat; 29557e9624eSPoul-Henning Kamp int fileid, modid; 29610b0e058SDima Dorfman const char *name; 29757e9624eSPoul-Henning Kamp char *cp; 29857e9624eSPoul-Henning Kamp 299a246f097SJohn-Mark Gurney name = MD_MODNAME; 30057e9624eSPoul-Henning Kamp /* scan files in kernel */ 30157e9624eSPoul-Henning Kamp mstat.version = sizeof(struct module_stat); 30257e9624eSPoul-Henning Kamp for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 30357e9624eSPoul-Henning Kamp /* scan modules in file */ 30457e9624eSPoul-Henning Kamp for (modid = kldfirstmod(fileid); modid > 0; 30557e9624eSPoul-Henning Kamp modid = modfnext(modid)) { 30657e9624eSPoul-Henning Kamp if (modstat(modid, &mstat) < 0) 30757e9624eSPoul-Henning Kamp continue; 30857e9624eSPoul-Henning Kamp /* strip bus name if present */ 30957e9624eSPoul-Henning Kamp if ((cp = strchr(mstat.name, '/')) != NULL) { 31057e9624eSPoul-Henning Kamp cp++; 31157e9624eSPoul-Henning Kamp } else { 31257e9624eSPoul-Henning Kamp cp = mstat.name; 31357e9624eSPoul-Henning Kamp } 31457e9624eSPoul-Henning Kamp /* already loaded? */ 31557e9624eSPoul-Henning Kamp if (!strcmp(name, cp)) 31657e9624eSPoul-Henning Kamp return; 31757e9624eSPoul-Henning Kamp } 31857e9624eSPoul-Henning Kamp } 31957e9624eSPoul-Henning Kamp /* not present, we should try to load it */ 32057e9624eSPoul-Henning Kamp kldload(name); 32157e9624eSPoul-Henning Kamp } 32257e9624eSPoul-Henning Kamp 323