100a6a3c6SPoul-Henning Kamp /* 200a6a3c6SPoul-Henning Kamp * ---------------------------------------------------------------------------- 300a6a3c6SPoul-Henning Kamp * "THE BEER-WARE LICENSE" (Revision 42): 400a6a3c6SPoul-Henning Kamp * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 500a6a3c6SPoul-Henning Kamp * can do whatever you want with this stuff. If we meet some day, and you think 600a6a3c6SPoul-Henning Kamp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 700a6a3c6SPoul-Henning Kamp * ---------------------------------------------------------------------------- 800a6a3c6SPoul-Henning Kamp * 900a6a3c6SPoul-Henning Kamp * $FreeBSD$ 1000a6a3c6SPoul-Henning Kamp * 1100a6a3c6SPoul-Henning Kamp */ 1200a6a3c6SPoul-Henning Kamp 13637f671aSPoul-Henning Kamp /* 14637f671aSPoul-Henning Kamp * The following functions are based in the vn(4) driver: mdstart_swap(), 15637f671aSPoul-Henning Kamp * mdstart_vnode(), mdcreate_swap(), mdcreate_vnode() and mddestroy(), 16637f671aSPoul-Henning Kamp * and as such under the following copyright: 17637f671aSPoul-Henning Kamp * 18637f671aSPoul-Henning Kamp * Copyright (c) 1988 University of Utah. 19637f671aSPoul-Henning Kamp * Copyright (c) 1990, 1993 20637f671aSPoul-Henning Kamp * The Regents of the University of California. All rights reserved. 21637f671aSPoul-Henning Kamp * 22637f671aSPoul-Henning Kamp * This code is derived from software contributed to Berkeley by 23637f671aSPoul-Henning Kamp * the Systems Programming Group of the University of Utah Computer 24637f671aSPoul-Henning Kamp * Science Department. 25637f671aSPoul-Henning Kamp * 26637f671aSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 27637f671aSPoul-Henning Kamp * modification, are permitted provided that the following conditions 28637f671aSPoul-Henning Kamp * are met: 29637f671aSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 30637f671aSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 31637f671aSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 32637f671aSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 33637f671aSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 34637f671aSPoul-Henning Kamp * 3. All advertising materials mentioning features or use of this software 35637f671aSPoul-Henning Kamp * must display the following acknowledgement: 36637f671aSPoul-Henning Kamp * This product includes software developed by the University of 37637f671aSPoul-Henning Kamp * California, Berkeley and its contributors. 38637f671aSPoul-Henning Kamp * 4. Neither the name of the University nor the names of its contributors 39637f671aSPoul-Henning Kamp * may be used to endorse or promote products derived from this software 40637f671aSPoul-Henning Kamp * without specific prior written permission. 41637f671aSPoul-Henning Kamp * 42637f671aSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 43637f671aSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44637f671aSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45637f671aSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 46637f671aSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47637f671aSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48637f671aSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49637f671aSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50637f671aSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51637f671aSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52637f671aSPoul-Henning Kamp * SUCH DAMAGE. 53637f671aSPoul-Henning Kamp * 54637f671aSPoul-Henning Kamp * from: Utah Hdr: vn.c 1.13 94/04/02 55637f671aSPoul-Henning Kamp * 56637f671aSPoul-Henning Kamp * from: @(#)vn.c 8.6 (Berkeley) 4/1/94 57637f671aSPoul-Henning Kamp * From: src/sys/dev/vn/vn.c,v 1.122 2000/12/16 16:06:03 58637f671aSPoul-Henning Kamp */ 59637f671aSPoul-Henning Kamp 603f54a085SPoul-Henning Kamp #include "opt_md.h" 6171e4fff8SPoul-Henning Kamp 6200a6a3c6SPoul-Henning Kamp #include <sys/param.h> 6300a6a3c6SPoul-Henning Kamp #include <sys/systm.h> 649626b608SPoul-Henning Kamp #include <sys/bio.h> 6500a6a3c6SPoul-Henning Kamp #include <sys/conf.h> 6600a6a3c6SPoul-Henning Kamp #include <sys/devicestat.h> 6727068b01SBrian Feldman #include <sys/disk.h> 688f8def9eSPoul-Henning Kamp #include <sys/fcntl.h> 69fb919e4dSMark Murray #include <sys/kernel.h> 70fb919e4dSMark Murray #include <sys/linker.h> 71fb919e4dSMark Murray #include <sys/lock.h> 72fb919e4dSMark Murray #include <sys/malloc.h> 73fb919e4dSMark Murray #include <sys/mdioctl.h> 749dceb26bSJohn Baldwin #include <sys/mutex.h> 75fb919e4dSMark Murray #include <sys/namei.h> 768f8def9eSPoul-Henning Kamp #include <sys/proc.h> 77fb919e4dSMark Murray #include <sys/queue.h> 78fb919e4dSMark Murray #include <sys/sysctl.h> 79fb919e4dSMark Murray #include <sys/vnode.h> 80fb919e4dSMark Murray 818f8def9eSPoul-Henning Kamp #include <machine/atomic.h> 828f8def9eSPoul-Henning Kamp 838f8def9eSPoul-Henning Kamp #include <vm/vm.h> 848f8def9eSPoul-Henning Kamp #include <vm/vm_object.h> 858f8def9eSPoul-Henning Kamp #include <vm/vm_page.h> 868f8def9eSPoul-Henning Kamp #include <vm/vm_pager.h> 878f8def9eSPoul-Henning Kamp #include <vm/swap_pager.h> 88f43b2bacSPoul-Henning Kamp #include <vm/uma.h> 893f54a085SPoul-Henning Kamp 9057e9624eSPoul-Henning Kamp #define MD_MODVER 1 9157e9624eSPoul-Henning Kamp 92f2744793SSheldon Hearn #ifndef MD_NSECT 93f2744793SSheldon Hearn #define MD_NSECT (10000 * 2) 9433edfabeSPoul-Henning Kamp #endif 9533edfabeSPoul-Henning Kamp 96e087ce2dSPoul-Henning Kamp static MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk"); 97e087ce2dSPoul-Henning Kamp static MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors"); 9800a6a3c6SPoul-Henning Kamp 9971e4fff8SPoul-Henning Kamp static int md_debug; 10000a6a3c6SPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, ""); 10100a6a3c6SPoul-Henning Kamp 10271e4fff8SPoul-Henning Kamp #if defined(MD_ROOT) && defined(MD_ROOT_SIZE) 10371e4fff8SPoul-Henning Kamp /* Image gets put here: */ 10471e4fff8SPoul-Henning Kamp static u_char mfs_root[MD_ROOT_SIZE*1024] = "MFS Filesystem goes here"; 10571e4fff8SPoul-Henning Kamp static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here"; 10671e4fff8SPoul-Henning Kamp #endif 10771e4fff8SPoul-Henning Kamp 10871e4fff8SPoul-Henning Kamp static int mdrootready; 1098f8def9eSPoul-Henning Kamp static int mdunits; 11057e9624eSPoul-Henning Kamp static dev_t status_dev = 0; 11157e9624eSPoul-Henning Kamp 11200a6a3c6SPoul-Henning Kamp #define CDEV_MAJOR 95 11300a6a3c6SPoul-Henning Kamp 11400a6a3c6SPoul-Henning Kamp static d_strategy_t mdstrategy; 11500a6a3c6SPoul-Henning Kamp static d_open_t mdopen; 116fe603109SMaxim Sobolev static d_close_t mdclose; 1178f8def9eSPoul-Henning Kamp static d_ioctl_t mdioctl, mdctlioctl; 11800a6a3c6SPoul-Henning Kamp 11900a6a3c6SPoul-Henning Kamp static struct cdevsw md_cdevsw = { 12000a6a3c6SPoul-Henning Kamp /* open */ mdopen, 121fe603109SMaxim Sobolev /* close */ mdclose, 12200a6a3c6SPoul-Henning Kamp /* read */ physread, 12300a6a3c6SPoul-Henning Kamp /* write */ physwrite, 12400a6a3c6SPoul-Henning Kamp /* ioctl */ mdioctl, 12500a6a3c6SPoul-Henning Kamp /* poll */ nopoll, 12600a6a3c6SPoul-Henning Kamp /* mmap */ nommap, 12700a6a3c6SPoul-Henning Kamp /* strategy */ mdstrategy, 128174b5e9aSPoul-Henning Kamp /* name */ MD_NAME, 12900a6a3c6SPoul-Henning Kamp /* maj */ CDEV_MAJOR, 13000a6a3c6SPoul-Henning Kamp /* dump */ nodump, 13100a6a3c6SPoul-Henning Kamp /* psize */ nopsize, 13271e4fff8SPoul-Henning Kamp /* flags */ D_DISK | D_CANFREE | D_MEMDISK, 1338f8def9eSPoul-Henning Kamp }; 1348f8def9eSPoul-Henning Kamp 1358f8def9eSPoul-Henning Kamp static struct cdevsw mdctl_cdevsw = { 1368f8def9eSPoul-Henning Kamp /* open */ nullopen, 1378f8def9eSPoul-Henning Kamp /* close */ nullclose, 1388f8def9eSPoul-Henning Kamp /* read */ noread, 1398f8def9eSPoul-Henning Kamp /* write */ nowrite, 1408f8def9eSPoul-Henning Kamp /* ioctl */ mdctlioctl, 1418f8def9eSPoul-Henning Kamp /* poll */ nopoll, 1428f8def9eSPoul-Henning Kamp /* mmap */ nommap, 1438f8def9eSPoul-Henning Kamp /* strategy */ nostrategy, 144174b5e9aSPoul-Henning Kamp /* name */ MD_NAME, 1458f8def9eSPoul-Henning Kamp /* maj */ CDEV_MAJOR 14600a6a3c6SPoul-Henning Kamp }; 14700a6a3c6SPoul-Henning Kamp 1480cfaeeeeSPoul-Henning Kamp static struct cdevsw mddisk_cdevsw; 1490cfaeeeeSPoul-Henning Kamp 1503f54a085SPoul-Henning Kamp static LIST_HEAD(, md_s) md_softc_list = LIST_HEAD_INITIALIZER(&md_softc_list); 1513f54a085SPoul-Henning Kamp 152c6517568SPoul-Henning Kamp #define NINDIR (PAGE_SIZE / sizeof(uintptr_t)) 153c6517568SPoul-Henning Kamp #define NMASK (NINDIR-1) 154c6517568SPoul-Henning Kamp static int nshift; 155c6517568SPoul-Henning Kamp 156c6517568SPoul-Henning Kamp struct indir { 157c6517568SPoul-Henning Kamp uintptr_t *array; 158c6517568SPoul-Henning Kamp uint total; 159c6517568SPoul-Henning Kamp uint used; 160c6517568SPoul-Henning Kamp uint shift; 161c6517568SPoul-Henning Kamp }; 162c6517568SPoul-Henning Kamp 16300a6a3c6SPoul-Henning Kamp struct md_s { 16400a6a3c6SPoul-Henning Kamp int unit; 1653f54a085SPoul-Henning Kamp LIST_ENTRY(md_s) list; 16600a6a3c6SPoul-Henning Kamp struct devstat stats; 1678177437dSPoul-Henning Kamp struct bio_queue_head bio_queue; 16800a6a3c6SPoul-Henning Kamp struct disk disk; 16900a6a3c6SPoul-Henning Kamp dev_t dev; 17095f1a897SPoul-Henning Kamp int busy; 1718f8def9eSPoul-Henning Kamp enum md_types type; 17200a6a3c6SPoul-Henning Kamp unsigned nsect; 173fe603109SMaxim Sobolev unsigned opencount; 1748f8def9eSPoul-Henning Kamp unsigned secsize; 1758f8def9eSPoul-Henning Kamp unsigned flags; 176f43b2bacSPoul-Henning Kamp char name[20]; 17795f1a897SPoul-Henning Kamp 17895f1a897SPoul-Henning Kamp /* MD_MALLOC related fields */ 179c6517568SPoul-Henning Kamp struct indir *indir; 180f43b2bacSPoul-Henning Kamp uma_zone_t uma; 18100a6a3c6SPoul-Henning Kamp 18295f1a897SPoul-Henning Kamp /* MD_PRELOAD related fields */ 18395f1a897SPoul-Henning Kamp u_char *pl_ptr; 18495f1a897SPoul-Henning Kamp unsigned pl_len; 18500a6a3c6SPoul-Henning Kamp 1868f8def9eSPoul-Henning Kamp /* MD_VNODE related fields */ 1878f8def9eSPoul-Henning Kamp struct vnode *vnode; 1888f8def9eSPoul-Henning Kamp struct ucred *cred; 1898f8def9eSPoul-Henning Kamp 190e0cebb40SDima Dorfman /* MD_SWAP related fields */ 1918f8def9eSPoul-Henning Kamp vm_object_t object; 1928f8def9eSPoul-Henning Kamp }; 19300a6a3c6SPoul-Henning Kamp 194c6517568SPoul-Henning Kamp static int mddestroy(struct md_s *sc, struct thread *td); 195c6517568SPoul-Henning Kamp 196c6517568SPoul-Henning Kamp static struct indir * 197c6517568SPoul-Henning Kamp new_indir(uint shift) 198c6517568SPoul-Henning Kamp { 199c6517568SPoul-Henning Kamp struct indir *ip; 200c6517568SPoul-Henning Kamp 201c6517568SPoul-Henning Kamp ip = malloc(sizeof *ip, M_MD, M_NOWAIT | M_ZERO); 202c6517568SPoul-Henning Kamp if (ip == NULL) 203c6517568SPoul-Henning Kamp return(NULL); 204c6517568SPoul-Henning Kamp ip->array = malloc(sizeof(uintptr_t) * NINDIR, 205c6517568SPoul-Henning Kamp M_MDSECT, M_NOWAIT | M_ZERO); 206c6517568SPoul-Henning Kamp if (ip->array == NULL) { 207c6517568SPoul-Henning Kamp free(ip, M_MD); 208c6517568SPoul-Henning Kamp return(NULL); 209c6517568SPoul-Henning Kamp } 210c6517568SPoul-Henning Kamp ip->total = NINDIR; 211c6517568SPoul-Henning Kamp ip->shift = shift; 212c6517568SPoul-Henning Kamp return(ip); 213c6517568SPoul-Henning Kamp } 214c6517568SPoul-Henning Kamp 215c6517568SPoul-Henning Kamp static void 216c6517568SPoul-Henning Kamp del_indir(struct indir *ip) 217c6517568SPoul-Henning Kamp { 218c6517568SPoul-Henning Kamp 219f43b2bacSPoul-Henning Kamp free(ip->array, M_MDSECT); 220c6517568SPoul-Henning Kamp free(ip, M_MD); 221c6517568SPoul-Henning Kamp } 222c6517568SPoul-Henning Kamp 223f43b2bacSPoul-Henning Kamp static void 224f43b2bacSPoul-Henning Kamp destroy_indir(struct md_s *sc, struct indir *ip) 225f43b2bacSPoul-Henning Kamp { 226f43b2bacSPoul-Henning Kamp int i; 227f43b2bacSPoul-Henning Kamp 228f43b2bacSPoul-Henning Kamp for (i = 0; i < NINDIR; i++) { 229f43b2bacSPoul-Henning Kamp if (!ip->array[i]) 230f43b2bacSPoul-Henning Kamp continue; 231f43b2bacSPoul-Henning Kamp if (ip->shift) 232f43b2bacSPoul-Henning Kamp destroy_indir(sc, (struct indir*)(ip->array[i])); 233f43b2bacSPoul-Henning Kamp else if (ip->array[i] > 255) 234f43b2bacSPoul-Henning Kamp uma_zfree(sc->uma, (void *)(ip->array[i])); 235f43b2bacSPoul-Henning Kamp } 236f43b2bacSPoul-Henning Kamp del_indir(ip); 237f43b2bacSPoul-Henning Kamp } 238f43b2bacSPoul-Henning Kamp 239f43b2bacSPoul-Henning Kamp 240c6517568SPoul-Henning Kamp /* 241c6517568SPoul-Henning Kamp * This function does the math and alloctes the top level "indir" structure 242c6517568SPoul-Henning Kamp * for a device of "size" sectors. 243c6517568SPoul-Henning Kamp */ 244c6517568SPoul-Henning Kamp 245c6517568SPoul-Henning Kamp static struct indir * 246c6517568SPoul-Henning Kamp dimension(off_t size) 247c6517568SPoul-Henning Kamp { 248c6517568SPoul-Henning Kamp off_t rcnt; 249c6517568SPoul-Henning Kamp struct indir *ip; 250c6517568SPoul-Henning Kamp int i, layer; 251c6517568SPoul-Henning Kamp 252c6517568SPoul-Henning Kamp rcnt = size; 253c6517568SPoul-Henning Kamp layer = 0; 254c6517568SPoul-Henning Kamp while (rcnt > NINDIR) { 255c6517568SPoul-Henning Kamp rcnt /= NINDIR; 256c6517568SPoul-Henning Kamp layer++; 257c6517568SPoul-Henning Kamp } 258c6517568SPoul-Henning Kamp /* figure out log2(NINDIR) */ 259c6517568SPoul-Henning Kamp for (i = NINDIR, nshift = -1; i; nshift++) 260c6517568SPoul-Henning Kamp i >>= 1; 261c6517568SPoul-Henning Kamp 262c6517568SPoul-Henning Kamp /* 263c6517568SPoul-Henning Kamp * XXX: the top layer is probably not fully populated, so we allocate 264c6517568SPoul-Henning Kamp * too much space for ip->array in new_indir() here. 265c6517568SPoul-Henning Kamp */ 266c6517568SPoul-Henning Kamp ip = new_indir(layer * nshift); 267c6517568SPoul-Henning Kamp return (ip); 268c6517568SPoul-Henning Kamp } 269c6517568SPoul-Henning Kamp 270c6517568SPoul-Henning Kamp /* 271c6517568SPoul-Henning Kamp * Read a given sector 272c6517568SPoul-Henning Kamp */ 273c6517568SPoul-Henning Kamp 274c6517568SPoul-Henning Kamp static uintptr_t 275c6517568SPoul-Henning Kamp s_read(struct indir *ip, off_t offset) 276c6517568SPoul-Henning Kamp { 277c6517568SPoul-Henning Kamp struct indir *cip; 278c6517568SPoul-Henning Kamp int idx; 279c6517568SPoul-Henning Kamp uintptr_t up; 280c6517568SPoul-Henning Kamp 281c6517568SPoul-Henning Kamp if (md_debug > 1) 282c6517568SPoul-Henning Kamp printf("s_read(%lld)\n", offset); 283c6517568SPoul-Henning Kamp up = 0; 284c6517568SPoul-Henning Kamp for (cip = ip; cip != NULL;) { 285c6517568SPoul-Henning Kamp if (cip->shift) { 286c6517568SPoul-Henning Kamp idx = (offset >> cip->shift) & NMASK; 287c6517568SPoul-Henning Kamp up = cip->array[idx]; 288c6517568SPoul-Henning Kamp cip = (struct indir *)up; 289c6517568SPoul-Henning Kamp continue; 290c6517568SPoul-Henning Kamp } 291c6517568SPoul-Henning Kamp idx = offset & NMASK; 292c6517568SPoul-Henning Kamp return(cip->array[idx]); 293c6517568SPoul-Henning Kamp } 294c6517568SPoul-Henning Kamp return (0); 295c6517568SPoul-Henning Kamp } 296c6517568SPoul-Henning Kamp 297c6517568SPoul-Henning Kamp /* 298c6517568SPoul-Henning Kamp * Write a given sector, prune the tree if the value is 0 299c6517568SPoul-Henning Kamp */ 300c6517568SPoul-Henning Kamp 301c6517568SPoul-Henning Kamp static int 302fde2a2e4SPoul-Henning Kamp s_write(struct indir *ip, off_t offset, uintptr_t ptr) 303c6517568SPoul-Henning Kamp { 304c6517568SPoul-Henning Kamp struct indir *cip, *lip[10]; 305c6517568SPoul-Henning Kamp int idx, li; 306c6517568SPoul-Henning Kamp uintptr_t up; 307c6517568SPoul-Henning Kamp 308c6517568SPoul-Henning Kamp if (md_debug > 1) 309fde2a2e4SPoul-Henning Kamp printf("s_write(%lld, %p)\n", offset, (void *)ptr); 310c6517568SPoul-Henning Kamp up = 0; 311c6517568SPoul-Henning Kamp li = 0; 312c6517568SPoul-Henning Kamp cip = ip; 313c6517568SPoul-Henning Kamp for (;;) { 314c6517568SPoul-Henning Kamp lip[li++] = cip; 315c6517568SPoul-Henning Kamp if (cip->shift) { 316c6517568SPoul-Henning Kamp idx = (offset >> cip->shift) & NMASK; 317c6517568SPoul-Henning Kamp up = cip->array[idx]; 318c6517568SPoul-Henning Kamp if (up != 0) { 319c6517568SPoul-Henning Kamp cip = (struct indir *)up; 320c6517568SPoul-Henning Kamp continue; 321c6517568SPoul-Henning Kamp } 322c6517568SPoul-Henning Kamp /* Allocate branch */ 323c6517568SPoul-Henning Kamp cip->array[idx] = 324c6517568SPoul-Henning Kamp (uintptr_t)new_indir(cip->shift - nshift); 325c6517568SPoul-Henning Kamp if (cip->array[idx] == 0) 326c6517568SPoul-Henning Kamp return(ENOMEM); 327c6517568SPoul-Henning Kamp cip->used++; 328c6517568SPoul-Henning Kamp up = cip->array[idx]; 329c6517568SPoul-Henning Kamp cip = (struct indir *)up; 330c6517568SPoul-Henning Kamp continue; 331c6517568SPoul-Henning Kamp } 332c6517568SPoul-Henning Kamp /* leafnode */ 333c6517568SPoul-Henning Kamp idx = offset & NMASK; 334c6517568SPoul-Henning Kamp up = cip->array[idx]; 335c6517568SPoul-Henning Kamp if (up != 0) 336c6517568SPoul-Henning Kamp cip->used--; 337c6517568SPoul-Henning Kamp cip->array[idx] = ptr; 338c6517568SPoul-Henning Kamp if (ptr != 0) 339c6517568SPoul-Henning Kamp cip->used++; 340c6517568SPoul-Henning Kamp break; 341c6517568SPoul-Henning Kamp } 342c6517568SPoul-Henning Kamp if (cip->used != 0 || li == 1) 343c6517568SPoul-Henning Kamp return (0); 344c6517568SPoul-Henning Kamp li--; 345c6517568SPoul-Henning Kamp while (cip->used == 0 && cip != ip) { 346c6517568SPoul-Henning Kamp li--; 347c6517568SPoul-Henning Kamp idx = (offset >> lip[li]->shift) & NMASK; 348c6517568SPoul-Henning Kamp up = lip[li]->array[idx]; 349c6517568SPoul-Henning Kamp KASSERT(up == (uintptr_t)cip, ("md screwed up")); 350c6517568SPoul-Henning Kamp del_indir(cip); 351c6517568SPoul-Henning Kamp lip[li]->array[idx] = NULL; 352c6517568SPoul-Henning Kamp lip[li]->used--; 353c6517568SPoul-Henning Kamp cip = lip[li]; 354c6517568SPoul-Henning Kamp } 355c6517568SPoul-Henning Kamp return (0); 356c6517568SPoul-Henning Kamp } 357c6517568SPoul-Henning Kamp 35800a6a3c6SPoul-Henning Kamp static int 359b40ce416SJulian Elischer mdopen(dev_t dev, int flag, int fmt, struct thread *td) 36000a6a3c6SPoul-Henning Kamp { 36100a6a3c6SPoul-Henning Kamp struct md_s *sc; 36200a6a3c6SPoul-Henning Kamp struct disklabel *dl; 36300a6a3c6SPoul-Henning Kamp 36400a6a3c6SPoul-Henning Kamp if (md_debug) 365c6517568SPoul-Henning Kamp printf("mdopen(%p %x %x %p)\n", 366c6517568SPoul-Henning Kamp devtoname(dev), flag, fmt, td); 36700a6a3c6SPoul-Henning Kamp 36800a6a3c6SPoul-Henning Kamp sc = dev->si_drv1; 36900a6a3c6SPoul-Henning Kamp 37000a6a3c6SPoul-Henning Kamp dl = &sc->disk.d_label; 37100a6a3c6SPoul-Henning Kamp bzero(dl, sizeof(*dl)); 3728f8def9eSPoul-Henning Kamp dl->d_secsize = sc->secsize; 3730ac60323SPoul-Henning Kamp dl->d_nsectors = sc->nsect > 63 ? 63 : sc->nsect; 37400a6a3c6SPoul-Henning Kamp dl->d_ntracks = 1; 37595f1a897SPoul-Henning Kamp dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 37600a6a3c6SPoul-Henning Kamp dl->d_secperunit = sc->nsect; 37700a6a3c6SPoul-Henning Kamp dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl; 378fe603109SMaxim Sobolev sc->opencount++; 379fe603109SMaxim Sobolev return (0); 380fe603109SMaxim Sobolev } 381fe603109SMaxim Sobolev 382fe603109SMaxim Sobolev static int 383b40ce416SJulian Elischer mdclose(dev_t dev, int flags, int fmt, struct thread *td) 384fe603109SMaxim Sobolev { 385fe603109SMaxim Sobolev struct md_s *sc = dev->si_drv1; 386fe603109SMaxim Sobolev 387fe603109SMaxim Sobolev sc->opencount--; 38800a6a3c6SPoul-Henning Kamp return (0); 38900a6a3c6SPoul-Henning Kamp } 39000a6a3c6SPoul-Henning Kamp 39100a6a3c6SPoul-Henning Kamp static int 392b40ce416SJulian Elischer mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 39300a6a3c6SPoul-Henning Kamp { 39400a6a3c6SPoul-Henning Kamp 39500a6a3c6SPoul-Henning Kamp if (md_debug) 39600a6a3c6SPoul-Henning Kamp printf("mdioctl(%s %lx %p %x %p)\n", 397b40ce416SJulian Elischer devtoname(dev), cmd, addr, flags, td); 39800a6a3c6SPoul-Henning Kamp 39900a6a3c6SPoul-Henning Kamp return (ENOIOCTL); 40000a6a3c6SPoul-Henning Kamp } 40100a6a3c6SPoul-Henning Kamp 402b4a4f93cSPoul-Henning Kamp static int 403b4a4f93cSPoul-Henning Kamp mdstart_malloc(struct md_s *sc, struct bio *bp) 40400a6a3c6SPoul-Henning Kamp { 405c6517568SPoul-Henning Kamp int i, error; 406c6517568SPoul-Henning Kamp u_char *dst; 407c6517568SPoul-Henning Kamp unsigned secno, nsec, uc; 408c6517568SPoul-Henning Kamp uintptr_t sp, osp; 40900a6a3c6SPoul-Henning Kamp 41096b6a55fSPoul-Henning Kamp nsec = bp->bio_bcount / sc->secsize; 4118177437dSPoul-Henning Kamp secno = bp->bio_pblkno; 4128177437dSPoul-Henning Kamp dst = bp->bio_data; 413c6517568SPoul-Henning Kamp error = 0; 41400a6a3c6SPoul-Henning Kamp while (nsec--) { 415fde2a2e4SPoul-Henning Kamp osp = s_read(sc->indir, secno); 4168177437dSPoul-Henning Kamp if (bp->bio_cmd == BIO_DELETE) { 417fde2a2e4SPoul-Henning Kamp if (osp != 0) 418fde2a2e4SPoul-Henning Kamp error = s_write(sc->indir, secno, 0); 4198177437dSPoul-Henning Kamp } else if (bp->bio_cmd == BIO_READ) { 420fde2a2e4SPoul-Henning Kamp if (osp == 0) 42196b6a55fSPoul-Henning Kamp bzero(dst, sc->secsize); 422fde2a2e4SPoul-Henning Kamp else if (osp <= 255) 423c6517568SPoul-Henning Kamp for (i = 0; i < sc->secsize; i++) 424fde2a2e4SPoul-Henning Kamp dst[i] = osp; 425c6517568SPoul-Henning Kamp else 426fde2a2e4SPoul-Henning Kamp bcopy((void *)osp, dst, sc->secsize); 427fde2a2e4SPoul-Henning Kamp osp = 0; 428c6517568SPoul-Henning Kamp } else if (bp->bio_cmd == BIO_WRITE) { 4298f8def9eSPoul-Henning Kamp if (sc->flags & MD_COMPRESS) { 43000a6a3c6SPoul-Henning Kamp uc = dst[0]; 43196b6a55fSPoul-Henning Kamp for (i = 1; i < sc->secsize; i++) 43200a6a3c6SPoul-Henning Kamp if (dst[i] != uc) 43300a6a3c6SPoul-Henning Kamp break; 4348f8def9eSPoul-Henning Kamp } else { 4358f8def9eSPoul-Henning Kamp i = 0; 4368f8def9eSPoul-Henning Kamp uc = 0; 4378f8def9eSPoul-Henning Kamp } 43896b6a55fSPoul-Henning Kamp if (i == sc->secsize) { 439fde2a2e4SPoul-Henning Kamp if (osp != uc) 440fde2a2e4SPoul-Henning Kamp error = s_write(sc->indir, secno, uc); 44100a6a3c6SPoul-Henning Kamp } else { 442fde2a2e4SPoul-Henning Kamp if (osp <= 255) { 443f43b2bacSPoul-Henning Kamp sp = (uintptr_t) uma_zalloc( 444f43b2bacSPoul-Henning Kamp sc->uma, M_NOWAIT); 445c6517568SPoul-Henning Kamp if (sp == 0) { 446fde2a2e4SPoul-Henning Kamp error = ENOSPC; 447fde2a2e4SPoul-Henning Kamp break; 448fde2a2e4SPoul-Henning Kamp } 449fde2a2e4SPoul-Henning Kamp error = s_write(sc->indir, secno, sp); 450c6517568SPoul-Henning Kamp } else { 451fde2a2e4SPoul-Henning Kamp bcopy(dst, (void *)osp, sc->secsize); 452fde2a2e4SPoul-Henning Kamp osp = 0; 45300a6a3c6SPoul-Henning Kamp } 45400a6a3c6SPoul-Henning Kamp } 455c6517568SPoul-Henning Kamp } else { 456c6517568SPoul-Henning Kamp error = EOPNOTSUPP; 457c6517568SPoul-Henning Kamp } 458c6517568SPoul-Henning Kamp if (osp > 255) 459f43b2bacSPoul-Henning Kamp uma_zfree(sc->uma, (void*)osp); 460c6517568SPoul-Henning Kamp if (error) 461c6517568SPoul-Henning Kamp break; 46200a6a3c6SPoul-Henning Kamp secno++; 46396b6a55fSPoul-Henning Kamp dst += sc->secsize; 46400a6a3c6SPoul-Henning Kamp } 4658177437dSPoul-Henning Kamp bp->bio_resid = 0; 466c6517568SPoul-Henning Kamp return (error); 46700a6a3c6SPoul-Henning Kamp } 46800a6a3c6SPoul-Henning Kamp 46971e4fff8SPoul-Henning Kamp 470b4a4f93cSPoul-Henning Kamp static int 471b4a4f93cSPoul-Henning Kamp mdstart_preload(struct md_s *sc, struct bio *bp) 47271e4fff8SPoul-Henning Kamp { 47371e4fff8SPoul-Henning Kamp 4748177437dSPoul-Henning Kamp if (bp->bio_cmd == BIO_DELETE) { 4758177437dSPoul-Henning Kamp } else if (bp->bio_cmd == BIO_READ) { 4768177437dSPoul-Henning Kamp bcopy(sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_data, bp->bio_bcount); 47771e4fff8SPoul-Henning Kamp } else { 4788177437dSPoul-Henning Kamp bcopy(bp->bio_data, sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_bcount); 47971e4fff8SPoul-Henning Kamp } 4808177437dSPoul-Henning Kamp bp->bio_resid = 0; 481b4a4f93cSPoul-Henning Kamp return (0); 48271e4fff8SPoul-Henning Kamp } 48371e4fff8SPoul-Henning Kamp 484b4a4f93cSPoul-Henning Kamp static int 485b4a4f93cSPoul-Henning Kamp mdstart_vnode(struct md_s *sc, struct bio *bp) 4868f8def9eSPoul-Henning Kamp { 4878f8def9eSPoul-Henning Kamp int error; 4888f8def9eSPoul-Henning Kamp struct uio auio; 4898f8def9eSPoul-Henning Kamp struct iovec aiov; 4908f8def9eSPoul-Henning Kamp struct mount *mp; 4918f8def9eSPoul-Henning Kamp 4928f8def9eSPoul-Henning Kamp /* 4938f8def9eSPoul-Henning Kamp * VNODE I/O 4948f8def9eSPoul-Henning Kamp * 4958f8def9eSPoul-Henning Kamp * If an error occurs, we set BIO_ERROR but we do not set 4968f8def9eSPoul-Henning Kamp * B_INVAL because (for a write anyway), the buffer is 4978f8def9eSPoul-Henning Kamp * still valid. 4988f8def9eSPoul-Henning Kamp */ 4998f8def9eSPoul-Henning Kamp 5008f8def9eSPoul-Henning Kamp bzero(&auio, sizeof(auio)); 5018f8def9eSPoul-Henning Kamp 5028f8def9eSPoul-Henning Kamp aiov.iov_base = bp->bio_data; 5038f8def9eSPoul-Henning Kamp aiov.iov_len = bp->bio_bcount; 5048f8def9eSPoul-Henning Kamp auio.uio_iov = &aiov; 5058f8def9eSPoul-Henning Kamp auio.uio_iovcnt = 1; 5068f8def9eSPoul-Henning Kamp auio.uio_offset = (vm_ooffset_t)bp->bio_pblkno * sc->secsize; 5078f8def9eSPoul-Henning Kamp auio.uio_segflg = UIO_SYSSPACE; 5088f8def9eSPoul-Henning Kamp if(bp->bio_cmd == BIO_READ) 5098f8def9eSPoul-Henning Kamp auio.uio_rw = UIO_READ; 5108f8def9eSPoul-Henning Kamp else 5118f8def9eSPoul-Henning Kamp auio.uio_rw = UIO_WRITE; 5128f8def9eSPoul-Henning Kamp auio.uio_resid = bp->bio_bcount; 513b40ce416SJulian Elischer auio.uio_td = curthread; 5147e76bb56SMatthew Dillon /* 5157e76bb56SMatthew Dillon * When reading set IO_DIRECT to try to avoid double-caching 5167e76bb56SMatthew Dillon * the data. When writing IO_DIRECT is not optimal, but we 5177e76bb56SMatthew Dillon * must set IO_NOWDRAIN to avoid a wdrain deadlock. 5187e76bb56SMatthew Dillon */ 5198f8def9eSPoul-Henning Kamp if (bp->bio_cmd == BIO_READ) { 520b40ce416SJulian Elischer vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread); 5217e76bb56SMatthew Dillon error = VOP_READ(sc->vnode, &auio, IO_DIRECT, sc->cred); 5228f8def9eSPoul-Henning Kamp } else { 5238f8def9eSPoul-Henning Kamp (void) vn_start_write(sc->vnode, &mp, V_WAIT); 524b40ce416SJulian Elischer vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread); 5257e76bb56SMatthew Dillon error = VOP_WRITE(sc->vnode, &auio, IO_NOWDRAIN, sc->cred); 5268f8def9eSPoul-Henning Kamp vn_finished_write(mp); 5278f8def9eSPoul-Henning Kamp } 528b40ce416SJulian Elischer VOP_UNLOCK(sc->vnode, 0, curthread); 5298f8def9eSPoul-Henning Kamp bp->bio_resid = auio.uio_resid; 530b4a4f93cSPoul-Henning Kamp return (error); 5318f8def9eSPoul-Henning Kamp } 5328f8def9eSPoul-Henning Kamp 533b4a4f93cSPoul-Henning Kamp static int 534b4a4f93cSPoul-Henning Kamp mdstart_swap(struct md_s *sc, struct bio *bp) 5358f8def9eSPoul-Henning Kamp { 5368f8def9eSPoul-Henning Kamp 5378f8def9eSPoul-Henning Kamp if ((bp->bio_cmd == BIO_DELETE) && (sc->flags & MD_RESERVE)) 5388f8def9eSPoul-Henning Kamp biodone(bp); 5398f8def9eSPoul-Henning Kamp else 5408f8def9eSPoul-Henning Kamp vm_pager_strategy(sc->object, bp); 541b4a4f93cSPoul-Henning Kamp return (-1); 5428f8def9eSPoul-Henning Kamp } 5438f8def9eSPoul-Henning Kamp 5448f8def9eSPoul-Henning Kamp static void 5458f8def9eSPoul-Henning Kamp mdstrategy(struct bio *bp) 54600a6a3c6SPoul-Henning Kamp { 54700a6a3c6SPoul-Henning Kamp struct md_s *sc; 548b4a4f93cSPoul-Henning Kamp int error; 54900a6a3c6SPoul-Henning Kamp 5508f8def9eSPoul-Henning Kamp if (md_debug > 1) 5510d2af521SKirk McKusick printf("mdstrategy(%p) %s %x, %lld, %ld, %p)\n", 5521ab0b5f9SBruce Evans (void *)bp, devtoname(bp->bio_dev), bp->bio_flags, 5531ab0b5f9SBruce Evans (long long)bp->bio_blkno, bp->bio_bcount / DEV_BSIZE, 5541ab0b5f9SBruce Evans (void *)bp->bio_data); 5558f8def9eSPoul-Henning Kamp 5568f8def9eSPoul-Henning Kamp sc = bp->bio_dev->si_drv1; 5578f8def9eSPoul-Henning Kamp 5588f8def9eSPoul-Henning Kamp /* XXX: LOCK(sc->lock) */ 5598f8def9eSPoul-Henning Kamp bioqdisksort(&sc->bio_queue, bp); 5608f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(sc->lock) */ 5618f8def9eSPoul-Henning Kamp 5628f8def9eSPoul-Henning Kamp if (atomic_cmpset_int(&sc->busy, 0, 1) == 0) 5638f8def9eSPoul-Henning Kamp return; 5648f8def9eSPoul-Henning Kamp 565b4a4f93cSPoul-Henning Kamp for (;;) { 566b4a4f93cSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 567b4a4f93cSPoul-Henning Kamp bp = bioq_first(&sc->bio_queue); 568b4a4f93cSPoul-Henning Kamp if (bp) 569b4a4f93cSPoul-Henning Kamp bioq_remove(&sc->bio_queue, bp); 570b4a4f93cSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 571b4a4f93cSPoul-Henning Kamp if (!bp) 572b4a4f93cSPoul-Henning Kamp break; 573b4a4f93cSPoul-Henning Kamp 574b4a4f93cSPoul-Henning Kamp 5758f8def9eSPoul-Henning Kamp switch (sc->type) { 5768f8def9eSPoul-Henning Kamp case MD_MALLOC: 577b4a4f93cSPoul-Henning Kamp devstat_start_transaction(&sc->stats); 578b4a4f93cSPoul-Henning Kamp error = mdstart_malloc(sc, bp); 5798f8def9eSPoul-Henning Kamp break; 5808f8def9eSPoul-Henning Kamp case MD_PRELOAD: 581b4a4f93cSPoul-Henning Kamp devstat_start_transaction(&sc->stats); 582b4a4f93cSPoul-Henning Kamp error = mdstart_preload(sc, bp); 5838f8def9eSPoul-Henning Kamp break; 5848f8def9eSPoul-Henning Kamp case MD_VNODE: 585b4a4f93cSPoul-Henning Kamp devstat_start_transaction(&sc->stats); 586b4a4f93cSPoul-Henning Kamp error = mdstart_vnode(sc, bp); 5878f8def9eSPoul-Henning Kamp break; 5888f8def9eSPoul-Henning Kamp case MD_SWAP: 589b4a4f93cSPoul-Henning Kamp error = mdstart_swap(sc, bp); 5908f8def9eSPoul-Henning Kamp break; 5918f8def9eSPoul-Henning Kamp default: 5928f8def9eSPoul-Henning Kamp panic("Impossible md(type)"); 5938f8def9eSPoul-Henning Kamp break; 5948f8def9eSPoul-Henning Kamp } 595b4a4f93cSPoul-Henning Kamp 596b4a4f93cSPoul-Henning Kamp if (error != -1) 597b4a4f93cSPoul-Henning Kamp biofinish(bp, &sc->stats, error); 598b4a4f93cSPoul-Henning Kamp } 5998f8def9eSPoul-Henning Kamp sc->busy = 0; 6008f8def9eSPoul-Henning Kamp } 6018f8def9eSPoul-Henning Kamp 6028f8def9eSPoul-Henning Kamp static struct md_s * 6038f8def9eSPoul-Henning Kamp mdfind(int unit) 6048f8def9eSPoul-Henning Kamp { 6058f8def9eSPoul-Henning Kamp struct md_s *sc; 6068f8def9eSPoul-Henning Kamp 6078f8def9eSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 6083f54a085SPoul-Henning Kamp LIST_FOREACH(sc, &md_softc_list, list) { 6093f54a085SPoul-Henning Kamp if (sc->unit == unit) 6108f8def9eSPoul-Henning Kamp break; 6118f8def9eSPoul-Henning Kamp } 6128f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 6138f8def9eSPoul-Henning Kamp return (sc); 6148f8def9eSPoul-Henning Kamp } 6158f8def9eSPoul-Henning Kamp 6168f8def9eSPoul-Henning Kamp static struct md_s * 6178f8def9eSPoul-Henning Kamp mdnew(int unit) 6188f8def9eSPoul-Henning Kamp { 6198f8def9eSPoul-Henning Kamp struct md_s *sc; 6208f8def9eSPoul-Henning Kamp int max = -1; 6218f8def9eSPoul-Henning Kamp 6228f8def9eSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 6238f8def9eSPoul-Henning Kamp LIST_FOREACH(sc, &md_softc_list, list) { 6248f8def9eSPoul-Henning Kamp if (sc->unit == unit) { 6258f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 6263f54a085SPoul-Henning Kamp return (NULL); 6273f54a085SPoul-Henning Kamp } 6288f8def9eSPoul-Henning Kamp if (sc->unit > max) 6298f8def9eSPoul-Henning Kamp max = sc->unit; 6308f8def9eSPoul-Henning Kamp } 6318f8def9eSPoul-Henning Kamp if (unit == -1) 6328f8def9eSPoul-Henning Kamp unit = max + 1; 6338f8def9eSPoul-Henning Kamp if (unit > DKMAXUNIT) 6348f8def9eSPoul-Henning Kamp return (NULL); 635c6517568SPoul-Henning Kamp sc = (struct md_s *)malloc(sizeof *sc, M_MD, M_WAITOK | M_ZERO); 6363f54a085SPoul-Henning Kamp sc->unit = unit; 637f43b2bacSPoul-Henning Kamp sprintf(sc->name, "md%d", unit); 6388f8def9eSPoul-Henning Kamp LIST_INSERT_HEAD(&md_softc_list, sc, list); 6398f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 6408f8def9eSPoul-Henning Kamp return (sc); 6418f8def9eSPoul-Henning Kamp } 6428f8def9eSPoul-Henning Kamp 6438f8def9eSPoul-Henning Kamp static void 6448f8def9eSPoul-Henning Kamp mdinit(struct md_s *sc) 6458f8def9eSPoul-Henning Kamp { 6468f8def9eSPoul-Henning Kamp 6478177437dSPoul-Henning Kamp bioq_init(&sc->bio_queue); 648174b5e9aSPoul-Henning Kamp devstat_add_entry(&sc->stats, MD_NAME, sc->unit, sc->secsize, 64995f1a897SPoul-Henning Kamp DEVSTAT_NO_ORDERED_TAGS, 65071e4fff8SPoul-Henning Kamp DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, 65171e4fff8SPoul-Henning Kamp DEVSTAT_PRIORITY_OTHER); 6520cfaeeeeSPoul-Henning Kamp sc->dev = disk_create(sc->unit, &sc->disk, 0, &md_cdevsw, &mddisk_cdevsw); 65395f1a897SPoul-Henning Kamp sc->dev->si_drv1 = sc; 65471e4fff8SPoul-Henning Kamp } 65571e4fff8SPoul-Henning Kamp 65696b6a55fSPoul-Henning Kamp /* 65796b6a55fSPoul-Henning Kamp * XXX: we should check that the range they feed us is mapped. 65896b6a55fSPoul-Henning Kamp * XXX: we should implement read-only. 65996b6a55fSPoul-Henning Kamp */ 66096b6a55fSPoul-Henning Kamp 661637f671aSPoul-Henning Kamp static int 662637f671aSPoul-Henning Kamp mdcreate_preload(struct md_ioctl *mdio) 66371e4fff8SPoul-Henning Kamp { 66471e4fff8SPoul-Henning Kamp struct md_s *sc; 66571e4fff8SPoul-Henning Kamp 666637f671aSPoul-Henning Kamp if (mdio->md_size == 0) 667637f671aSPoul-Henning Kamp return (EINVAL); 668637f671aSPoul-Henning Kamp if (mdio->md_options & ~(MD_AUTOUNIT)) 669637f671aSPoul-Henning Kamp return (EINVAL); 670637f671aSPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 6718f8def9eSPoul-Henning Kamp sc = mdnew(-1); 6728f8def9eSPoul-Henning Kamp if (sc == NULL) 673637f671aSPoul-Henning Kamp return (ENOMEM); 674637f671aSPoul-Henning Kamp mdio->md_unit = sc->unit; 675637f671aSPoul-Henning Kamp } else { 676637f671aSPoul-Henning Kamp sc = mdnew(mdio->md_unit); 677637f671aSPoul-Henning Kamp if (sc == NULL) 678637f671aSPoul-Henning Kamp return (EBUSY); 679637f671aSPoul-Henning Kamp } 68066c16191SPoul-Henning Kamp sc->type = MD_PRELOAD; 6818f8def9eSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 682637f671aSPoul-Henning Kamp sc->nsect = mdio->md_size; 68326a0ee75SDima Dorfman sc->flags = mdio->md_options & MD_FORCE; 68496b6a55fSPoul-Henning Kamp /* Cast to pointer size, then to pointer to avoid warning */ 685dc57d7c6SPeter Wemm sc->pl_ptr = (u_char *)(uintptr_t)mdio->md_base; 686637f671aSPoul-Henning Kamp sc->pl_len = (mdio->md_size << DEV_BSHIFT); 6878f8def9eSPoul-Henning Kamp mdinit(sc); 688637f671aSPoul-Henning Kamp return (0); 68995f1a897SPoul-Henning Kamp } 69095f1a897SPoul-Henning Kamp 691637f671aSPoul-Henning Kamp 6928f8def9eSPoul-Henning Kamp static int 6938f8def9eSPoul-Henning Kamp mdcreate_malloc(struct md_ioctl *mdio) 69495f1a897SPoul-Henning Kamp { 69595f1a897SPoul-Henning Kamp struct md_s *sc; 696c6517568SPoul-Henning Kamp off_t u; 697c6517568SPoul-Henning Kamp uintptr_t sp; 698c6517568SPoul-Henning Kamp int error; 69995f1a897SPoul-Henning Kamp 700c6517568SPoul-Henning Kamp error = 0; 7018f8def9eSPoul-Henning Kamp if (mdio->md_size == 0) 7028f8def9eSPoul-Henning Kamp return (EINVAL); 7038f8def9eSPoul-Henning Kamp if (mdio->md_options & ~(MD_AUTOUNIT | MD_COMPRESS | MD_RESERVE)) 7048f8def9eSPoul-Henning Kamp return (EINVAL); 7058f8def9eSPoul-Henning Kamp /* Compression doesn't make sense if we have reserved space */ 7068f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_RESERVE) 7078f8def9eSPoul-Henning Kamp mdio->md_options &= ~MD_COMPRESS; 7088f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 7098f8def9eSPoul-Henning Kamp sc = mdnew(-1); 7103f54a085SPoul-Henning Kamp if (sc == NULL) 7118f8def9eSPoul-Henning Kamp return (ENOMEM); 7128f8def9eSPoul-Henning Kamp mdio->md_unit = sc->unit; 7138f8def9eSPoul-Henning Kamp } else { 7148f8def9eSPoul-Henning Kamp sc = mdnew(mdio->md_unit); 7158f8def9eSPoul-Henning Kamp if (sc == NULL) 7168f8def9eSPoul-Henning Kamp return (EBUSY); 7178f8def9eSPoul-Henning Kamp } 71866c16191SPoul-Henning Kamp sc->type = MD_MALLOC; 7198f8def9eSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 7208f8def9eSPoul-Henning Kamp sc->nsect = mdio->md_size; 72126a0ee75SDima Dorfman sc->flags = mdio->md_options & (MD_COMPRESS | MD_FORCE); 722c6517568SPoul-Henning Kamp sc->indir = dimension(sc->nsect); 723f43b2bacSPoul-Henning Kamp sc->uma = uma_zcreate(sc->name, sc->secsize, 724f43b2bacSPoul-Henning Kamp NULL, NULL, NULL, NULL, 0x1ff, 0); 72596b6a55fSPoul-Henning Kamp if (mdio->md_options & MD_RESERVE) { 726c6517568SPoul-Henning Kamp for (u = 0; u < sc->nsect; u++) { 727f43b2bacSPoul-Henning Kamp sp = (uintptr_t) uma_zalloc(sc->uma, M_NOWAIT | M_ZERO); 728c6517568SPoul-Henning Kamp if (sp != 0) 729fde2a2e4SPoul-Henning Kamp error = s_write(sc->indir, u, sp); 730c6517568SPoul-Henning Kamp else 731c6517568SPoul-Henning Kamp error = ENOMEM; 732c6517568SPoul-Henning Kamp if (error) 733c6517568SPoul-Henning Kamp break; 7348f8def9eSPoul-Henning Kamp } 735c6517568SPoul-Henning Kamp } 736c6517568SPoul-Henning Kamp if (!error) { 737174b5e9aSPoul-Henning Kamp printf("%s%d: Malloc disk\n", MD_NAME, sc->unit); 7388f8def9eSPoul-Henning Kamp mdinit(sc); 739c6517568SPoul-Henning Kamp } else 740c6517568SPoul-Henning Kamp mddestroy(sc, NULL); 741c6517568SPoul-Henning Kamp return (error); 74200a6a3c6SPoul-Henning Kamp } 74300a6a3c6SPoul-Henning Kamp 7443f54a085SPoul-Henning Kamp 7458f8def9eSPoul-Henning Kamp static int 7468f8def9eSPoul-Henning Kamp mdsetcred(struct md_s *sc, struct ucred *cred) 7478f8def9eSPoul-Henning Kamp { 7488f8def9eSPoul-Henning Kamp char *tmpbuf; 7498f8def9eSPoul-Henning Kamp int error = 0; 7508f8def9eSPoul-Henning Kamp 7513f54a085SPoul-Henning Kamp /* 7528f8def9eSPoul-Henning Kamp * Set credits in our softc 7533f54a085SPoul-Henning Kamp */ 7548f8def9eSPoul-Henning Kamp 7558f8def9eSPoul-Henning Kamp if (sc->cred) 7568f8def9eSPoul-Henning Kamp crfree(sc->cred); 757bd78ceceSJohn Baldwin sc->cred = crhold(cred); 7588f8def9eSPoul-Henning Kamp 7598f8def9eSPoul-Henning Kamp /* 7608f8def9eSPoul-Henning Kamp * Horrible kludge to establish credentials for NFS XXX. 7618f8def9eSPoul-Henning Kamp */ 7628f8def9eSPoul-Henning Kamp 7638f8def9eSPoul-Henning Kamp if (sc->vnode) { 7648f8def9eSPoul-Henning Kamp struct uio auio; 7658f8def9eSPoul-Henning Kamp struct iovec aiov; 7668f8def9eSPoul-Henning Kamp 7678f8def9eSPoul-Henning Kamp tmpbuf = malloc(sc->secsize, M_TEMP, M_WAITOK); 7688f8def9eSPoul-Henning Kamp bzero(&auio, sizeof(auio)); 7698f8def9eSPoul-Henning Kamp 7708f8def9eSPoul-Henning Kamp aiov.iov_base = tmpbuf; 7718f8def9eSPoul-Henning Kamp aiov.iov_len = sc->secsize; 7728f8def9eSPoul-Henning Kamp auio.uio_iov = &aiov; 7738f8def9eSPoul-Henning Kamp auio.uio_iovcnt = 1; 7748f8def9eSPoul-Henning Kamp auio.uio_offset = 0; 7758f8def9eSPoul-Henning Kamp auio.uio_rw = UIO_READ; 7768f8def9eSPoul-Henning Kamp auio.uio_segflg = UIO_SYSSPACE; 7778f8def9eSPoul-Henning Kamp auio.uio_resid = aiov.iov_len; 778b40ce416SJulian Elischer vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread); 7798f8def9eSPoul-Henning Kamp error = VOP_READ(sc->vnode, &auio, 0, sc->cred); 780b40ce416SJulian Elischer VOP_UNLOCK(sc->vnode, 0, curthread); 7818f8def9eSPoul-Henning Kamp free(tmpbuf, M_TEMP); 7828f8def9eSPoul-Henning Kamp } 7838f8def9eSPoul-Henning Kamp return (error); 7848f8def9eSPoul-Henning Kamp } 7858f8def9eSPoul-Henning Kamp 7868f8def9eSPoul-Henning Kamp static int 787b40ce416SJulian Elischer mdcreate_vnode(struct md_ioctl *mdio, struct thread *td) 7888f8def9eSPoul-Henning Kamp { 7898f8def9eSPoul-Henning Kamp struct md_s *sc; 7908f8def9eSPoul-Henning Kamp struct vattr vattr; 7918f8def9eSPoul-Henning Kamp struct nameidata nd; 7928f8def9eSPoul-Henning Kamp int error, flags; 7938f8def9eSPoul-Henning Kamp 7948f8def9eSPoul-Henning Kamp flags = FREAD|FWRITE; 795b40ce416SJulian Elischer NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, mdio->md_file, td); 7968f8def9eSPoul-Henning Kamp error = vn_open(&nd, &flags, 0); 7978f8def9eSPoul-Henning Kamp if (error) { 7988f8def9eSPoul-Henning Kamp if (error != EACCES && error != EPERM && error != EROFS) 7998f8def9eSPoul-Henning Kamp return (error); 8008f8def9eSPoul-Henning Kamp flags &= ~FWRITE; 801b40ce416SJulian Elischer NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, mdio->md_file, td); 8028f8def9eSPoul-Henning Kamp error = vn_open(&nd, &flags, 0); 8038f8def9eSPoul-Henning Kamp if (error) 8048f8def9eSPoul-Henning Kamp return (error); 8058f8def9eSPoul-Henning Kamp } 8068f8def9eSPoul-Henning Kamp NDFREE(&nd, NDF_ONLY_PNBUF); 8078f8def9eSPoul-Henning Kamp if (nd.ni_vp->v_type != VREG || 808a854ed98SJohn Baldwin (error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred, td))) { 809b40ce416SJulian Elischer VOP_UNLOCK(nd.ni_vp, 0, td); 810a854ed98SJohn Baldwin (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 8118f8def9eSPoul-Henning Kamp return (error ? error : EINVAL); 8128f8def9eSPoul-Henning Kamp } 813b40ce416SJulian Elischer VOP_UNLOCK(nd.ni_vp, 0, td); 8149589c256SPoul-Henning Kamp 8159589c256SPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 8169589c256SPoul-Henning Kamp sc = mdnew(-1); 8179589c256SPoul-Henning Kamp mdio->md_unit = sc->unit; 8189589c256SPoul-Henning Kamp } else { 8199589c256SPoul-Henning Kamp sc = mdnew(mdio->md_unit); 8209589c256SPoul-Henning Kamp } 8219589c256SPoul-Henning Kamp if (sc == NULL) { 8229589c256SPoul-Henning Kamp (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 8239589c256SPoul-Henning Kamp return (EBUSY); 8249589c256SPoul-Henning Kamp } 8259589c256SPoul-Henning Kamp 8269589c256SPoul-Henning Kamp sc->type = MD_VNODE; 8279589c256SPoul-Henning Kamp sc->flags = mdio->md_options & MD_FORCE; 8289589c256SPoul-Henning Kamp if (!(flags & FWRITE)) 8299589c256SPoul-Henning Kamp sc->flags |= MD_READONLY; 8308f8def9eSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 8318f8def9eSPoul-Henning Kamp sc->vnode = nd.ni_vp; 8328f8def9eSPoul-Henning Kamp 8338f8def9eSPoul-Henning Kamp /* 8348f8def9eSPoul-Henning Kamp * If the size is specified, override the file attributes. 8358f8def9eSPoul-Henning Kamp */ 8368f8def9eSPoul-Henning Kamp if (mdio->md_size) 8378f8def9eSPoul-Henning Kamp sc->nsect = mdio->md_size; 8388f8def9eSPoul-Henning Kamp else 8398f8def9eSPoul-Henning Kamp sc->nsect = vattr.va_size / sc->secsize; /* XXX: round up ? */ 8403d3c27feSThomas Moestl if (sc->nsect == 0) { 841a854ed98SJohn Baldwin (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 8423d3c27feSThomas Moestl return (EINVAL); 8433d3c27feSThomas Moestl } 844a854ed98SJohn Baldwin error = mdsetcred(sc, td->td_ucred); 8458f8def9eSPoul-Henning Kamp if (error) { 846a854ed98SJohn Baldwin (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 8478f8def9eSPoul-Henning Kamp return (error); 8488f8def9eSPoul-Henning Kamp } 8498f8def9eSPoul-Henning Kamp mdinit(sc); 8508f8def9eSPoul-Henning Kamp return (0); 8518f8def9eSPoul-Henning Kamp } 8528f8def9eSPoul-Henning Kamp 8538f8def9eSPoul-Henning Kamp static int 854b40ce416SJulian Elischer mddestroy(struct md_s *sc, struct thread *td) 8558f8def9eSPoul-Henning Kamp { 8568f8def9eSPoul-Henning Kamp 8570cddd8f0SMatthew Dillon GIANT_REQUIRED; 8580cddd8f0SMatthew Dillon 8591f4ee1aaSPoul-Henning Kamp if (sc->dev != NULL) { 8601f4ee1aaSPoul-Henning Kamp devstat_remove_entry(&sc->stats); 8618f8def9eSPoul-Henning Kamp disk_destroy(sc->dev); 8621f4ee1aaSPoul-Henning Kamp } 8638f8def9eSPoul-Henning Kamp if (sc->vnode != NULL) 8649d4b5945SMaxim Sobolev (void)vn_close(sc->vnode, sc->flags & MD_READONLY ? 865b40ce416SJulian Elischer FREAD : (FREAD|FWRITE), sc->cred, td); 8668f8def9eSPoul-Henning Kamp if (sc->cred != NULL) 8678f8def9eSPoul-Henning Kamp crfree(sc->cred); 8685a025167SDima Dorfman if (sc->object != NULL) { 8698f8def9eSPoul-Henning Kamp vm_pager_deallocate(sc->object); 8705a025167SDima Dorfman } 871f43b2bacSPoul-Henning Kamp if (sc->indir) 872f43b2bacSPoul-Henning Kamp destroy_indir(sc, sc->indir); 873f43b2bacSPoul-Henning Kamp if (sc->uma) 874f43b2bacSPoul-Henning Kamp uma_zdestroy(sc->uma); 8751f4ee1aaSPoul-Henning Kamp 8761f4ee1aaSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 8771f4ee1aaSPoul-Henning Kamp LIST_REMOVE(sc, list); 8781f4ee1aaSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 879c6517568SPoul-Henning Kamp free(sc, M_MD); 8808f8def9eSPoul-Henning Kamp return (0); 8818f8def9eSPoul-Henning Kamp } 8828f8def9eSPoul-Henning Kamp 8838f8def9eSPoul-Henning Kamp static int 884b40ce416SJulian Elischer mdcreate_swap(struct md_ioctl *mdio, struct thread *td) 8858f8def9eSPoul-Henning Kamp { 8868f8def9eSPoul-Henning Kamp int error; 8878f8def9eSPoul-Henning Kamp struct md_s *sc; 8888f8def9eSPoul-Henning Kamp 8890cddd8f0SMatthew Dillon GIANT_REQUIRED; 8900cddd8f0SMatthew Dillon 8918f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 8928f8def9eSPoul-Henning Kamp sc = mdnew(-1); 8938f8def9eSPoul-Henning Kamp mdio->md_unit = sc->unit; 8948f8def9eSPoul-Henning Kamp } else { 8958f8def9eSPoul-Henning Kamp sc = mdnew(mdio->md_unit); 8968f8def9eSPoul-Henning Kamp } 8978f8def9eSPoul-Henning Kamp if (sc == NULL) 8988f8def9eSPoul-Henning Kamp return (EBUSY); 8998f8def9eSPoul-Henning Kamp 9008f8def9eSPoul-Henning Kamp sc->type = MD_SWAP; 9018f8def9eSPoul-Henning Kamp 9028f8def9eSPoul-Henning Kamp /* 9038f8def9eSPoul-Henning Kamp * Range check. Disallow negative sizes or any size less then the 9048f8def9eSPoul-Henning Kamp * size of a page. Then round to a page. 9058f8def9eSPoul-Henning Kamp */ 9068f8def9eSPoul-Henning Kamp 9071f4ee1aaSPoul-Henning Kamp if (mdio->md_size == 0) { 908b40ce416SJulian Elischer mddestroy(sc, td); 9098f8def9eSPoul-Henning Kamp return (EDOM); 9101f4ee1aaSPoul-Henning Kamp } 9118f8def9eSPoul-Henning Kamp 9128f8def9eSPoul-Henning Kamp /* 9138f8def9eSPoul-Henning Kamp * Allocate an OBJT_SWAP object. 9148f8def9eSPoul-Henning Kamp * 9158f8def9eSPoul-Henning Kamp * sc_secsize is PAGE_SIZE'd 9168f8def9eSPoul-Henning Kamp * 9178f8def9eSPoul-Henning Kamp * mdio->size is in DEV_BSIZE'd chunks. 9188f8def9eSPoul-Henning Kamp * Note the truncation. 9198f8def9eSPoul-Henning Kamp */ 9208f8def9eSPoul-Henning Kamp 9218f8def9eSPoul-Henning Kamp sc->secsize = PAGE_SIZE; 9228f8def9eSPoul-Henning Kamp sc->nsect = mdio->md_size / (PAGE_SIZE / DEV_BSIZE); 9238f8def9eSPoul-Henning Kamp sc->object = vm_pager_allocate(OBJT_SWAP, NULL, sc->secsize * (vm_offset_t)sc->nsect, VM_PROT_DEFAULT, 0); 92426a0ee75SDima Dorfman sc->flags = mdio->md_options & MD_FORCE; 9258f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_RESERVE) { 9268f8def9eSPoul-Henning Kamp if (swap_pager_reserve(sc->object, 0, sc->nsect) < 0) { 9278f8def9eSPoul-Henning Kamp vm_pager_deallocate(sc->object); 9288f8def9eSPoul-Henning Kamp sc->object = NULL; 929b40ce416SJulian Elischer mddestroy(sc, td); 9308f8def9eSPoul-Henning Kamp return (EDOM); 9318f8def9eSPoul-Henning Kamp } 9328f8def9eSPoul-Henning Kamp } 933a854ed98SJohn Baldwin error = mdsetcred(sc, td->td_ucred); 9348f8def9eSPoul-Henning Kamp if (error) 935b40ce416SJulian Elischer mddestroy(sc, td); 9368f8def9eSPoul-Henning Kamp else 9378f8def9eSPoul-Henning Kamp mdinit(sc); 9388f8def9eSPoul-Henning Kamp return (error); 9398f8def9eSPoul-Henning Kamp } 9408f8def9eSPoul-Henning Kamp 9418f8def9eSPoul-Henning Kamp static int 942b40ce416SJulian Elischer mddetach(int unit, struct thread *td) 9439d4b5945SMaxim Sobolev { 9449d4b5945SMaxim Sobolev struct md_s *sc; 9459d4b5945SMaxim Sobolev 9469d4b5945SMaxim Sobolev sc = mdfind(unit); 9479d4b5945SMaxim Sobolev if (sc == NULL) 9489d4b5945SMaxim Sobolev return (ENOENT); 9499d4b5945SMaxim Sobolev if (sc->opencount != 0 && !(sc->flags & MD_FORCE)) 9509d4b5945SMaxim Sobolev return (EBUSY); 9519d4b5945SMaxim Sobolev switch(sc->type) { 9529d4b5945SMaxim Sobolev case MD_VNODE: 9539d4b5945SMaxim Sobolev case MD_SWAP: 9549d4b5945SMaxim Sobolev case MD_MALLOC: 9559d4b5945SMaxim Sobolev case MD_PRELOAD: 956b40ce416SJulian Elischer return (mddestroy(sc, td)); 9579d4b5945SMaxim Sobolev default: 9589d4b5945SMaxim Sobolev return (EOPNOTSUPP); 9599d4b5945SMaxim Sobolev } 9609d4b5945SMaxim Sobolev } 9619d4b5945SMaxim Sobolev 9629d4b5945SMaxim Sobolev static int 963b40ce416SJulian Elischer mdctlioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 9648f8def9eSPoul-Henning Kamp { 9658f8def9eSPoul-Henning Kamp struct md_ioctl *mdio; 9668f8def9eSPoul-Henning Kamp struct md_s *sc; 9678f8def9eSPoul-Henning Kamp 9688f8def9eSPoul-Henning Kamp if (md_debug) 9698f8def9eSPoul-Henning Kamp printf("mdctlioctl(%s %lx %p %x %p)\n", 970b40ce416SJulian Elischer devtoname(dev), cmd, addr, flags, td); 9718f8def9eSPoul-Henning Kamp 97253d745bcSDima Dorfman /* 97353d745bcSDima Dorfman * We assert the version number in the individual ioctl 97453d745bcSDima Dorfman * handlers instead of out here because (a) it is possible we 97553d745bcSDima Dorfman * may add another ioctl in the future which doesn't read an 97653d745bcSDima Dorfman * mdio, and (b) the correct return value for an unknown ioctl 97753d745bcSDima Dorfman * is ENOIOCTL, not EINVAL. 97853d745bcSDima Dorfman */ 9798f8def9eSPoul-Henning Kamp mdio = (struct md_ioctl *)addr; 9808f8def9eSPoul-Henning Kamp switch (cmd) { 9818f8def9eSPoul-Henning Kamp case MDIOCATTACH: 98253d745bcSDima Dorfman if (mdio->md_version != MDIOVERSION) 98353d745bcSDima Dorfman return (EINVAL); 9848f8def9eSPoul-Henning Kamp switch (mdio->md_type) { 9858f8def9eSPoul-Henning Kamp case MD_MALLOC: 9868f8def9eSPoul-Henning Kamp return (mdcreate_malloc(mdio)); 9878f8def9eSPoul-Henning Kamp case MD_PRELOAD: 988637f671aSPoul-Henning Kamp return (mdcreate_preload(mdio)); 9898f8def9eSPoul-Henning Kamp case MD_VNODE: 990b40ce416SJulian Elischer return (mdcreate_vnode(mdio, td)); 9918f8def9eSPoul-Henning Kamp case MD_SWAP: 992b40ce416SJulian Elischer return (mdcreate_swap(mdio, td)); 9938f8def9eSPoul-Henning Kamp default: 9948f8def9eSPoul-Henning Kamp return (EINVAL); 9958f8def9eSPoul-Henning Kamp } 9968f8def9eSPoul-Henning Kamp case MDIOCDETACH: 99753d745bcSDima Dorfman if (mdio->md_version != MDIOVERSION) 99853d745bcSDima Dorfman return (EINVAL); 9999d4b5945SMaxim Sobolev if (mdio->md_file != NULL || mdio->md_size != 0 || 10009d4b5945SMaxim Sobolev mdio->md_options != 0) 10018f8def9eSPoul-Henning Kamp return (EINVAL); 1002b40ce416SJulian Elischer return (mddetach(mdio->md_unit, td)); 1003174b5e9aSPoul-Henning Kamp case MDIOCQUERY: 100453d745bcSDima Dorfman if (mdio->md_version != MDIOVERSION) 100553d745bcSDima Dorfman return (EINVAL); 1006174b5e9aSPoul-Henning Kamp sc = mdfind(mdio->md_unit); 1007174b5e9aSPoul-Henning Kamp if (sc == NULL) 1008174b5e9aSPoul-Henning Kamp return (ENOENT); 1009174b5e9aSPoul-Henning Kamp mdio->md_type = sc->type; 1010174b5e9aSPoul-Henning Kamp mdio->md_options = sc->flags; 1011174b5e9aSPoul-Henning Kamp switch (sc->type) { 1012174b5e9aSPoul-Henning Kamp case MD_MALLOC: 1013174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect; 1014174b5e9aSPoul-Henning Kamp break; 1015174b5e9aSPoul-Henning Kamp case MD_PRELOAD: 1016174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect; 1017174b5e9aSPoul-Henning Kamp (u_char *)(uintptr_t)mdio->md_base = sc->pl_ptr; 1018174b5e9aSPoul-Henning Kamp break; 1019174b5e9aSPoul-Henning Kamp case MD_SWAP: 1020174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect * (PAGE_SIZE / DEV_BSIZE); 1021174b5e9aSPoul-Henning Kamp break; 1022174b5e9aSPoul-Henning Kamp case MD_VNODE: 1023174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect; 1024174b5e9aSPoul-Henning Kamp /* XXX fill this in */ 1025174b5e9aSPoul-Henning Kamp mdio->md_file = NULL; 1026174b5e9aSPoul-Henning Kamp break; 1027174b5e9aSPoul-Henning Kamp } 1028174b5e9aSPoul-Henning Kamp return (0); 10298f8def9eSPoul-Henning Kamp default: 10308f8def9eSPoul-Henning Kamp return (ENOIOCTL); 10318f8def9eSPoul-Henning Kamp }; 10328f8def9eSPoul-Henning Kamp return (ENOIOCTL); 10333f54a085SPoul-Henning Kamp } 10343f54a085SPoul-Henning Kamp 103500a6a3c6SPoul-Henning Kamp static void 1036637f671aSPoul-Henning Kamp md_preloaded(u_char *image, unsigned length) 1037637f671aSPoul-Henning Kamp { 1038637f671aSPoul-Henning Kamp struct md_s *sc; 1039637f671aSPoul-Henning Kamp 1040637f671aSPoul-Henning Kamp sc = mdnew(-1); 1041637f671aSPoul-Henning Kamp if (sc == NULL) 1042637f671aSPoul-Henning Kamp return; 1043637f671aSPoul-Henning Kamp sc->type = MD_PRELOAD; 1044637f671aSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 1045637f671aSPoul-Henning Kamp sc->nsect = length / DEV_BSIZE; 1046637f671aSPoul-Henning Kamp sc->pl_ptr = image; 1047637f671aSPoul-Henning Kamp sc->pl_len = length; 1048637f671aSPoul-Henning Kamp if (sc->unit == 0) 1049637f671aSPoul-Henning Kamp mdrootready = 1; 1050637f671aSPoul-Henning Kamp mdinit(sc); 1051637f671aSPoul-Henning Kamp } 1052637f671aSPoul-Henning Kamp 1053637f671aSPoul-Henning Kamp static void 105400a6a3c6SPoul-Henning Kamp md_drvinit(void *unused) 105500a6a3c6SPoul-Henning Kamp { 105600a6a3c6SPoul-Henning Kamp 105795f1a897SPoul-Henning Kamp caddr_t mod; 105895f1a897SPoul-Henning Kamp caddr_t c; 105995f1a897SPoul-Henning Kamp u_char *ptr, *name, *type; 106095f1a897SPoul-Henning Kamp unsigned len; 106195f1a897SPoul-Henning Kamp 106271e4fff8SPoul-Henning Kamp #ifdef MD_ROOT_SIZE 1063637f671aSPoul-Henning Kamp md_preloaded(mfs_root, MD_ROOT_SIZE*1024); 106471e4fff8SPoul-Henning Kamp #endif 106595f1a897SPoul-Henning Kamp mod = NULL; 106695f1a897SPoul-Henning Kamp while ((mod = preload_search_next_name(mod)) != NULL) { 106795f1a897SPoul-Henning Kamp name = (char *)preload_search_info(mod, MODINFO_NAME); 106895f1a897SPoul-Henning Kamp type = (char *)preload_search_info(mod, MODINFO_TYPE); 106995f1a897SPoul-Henning Kamp if (name == NULL) 107095f1a897SPoul-Henning Kamp continue; 107195f1a897SPoul-Henning Kamp if (type == NULL) 107295f1a897SPoul-Henning Kamp continue; 107371e4fff8SPoul-Henning Kamp if (strcmp(type, "md_image") && strcmp(type, "mfs_root")) 107495f1a897SPoul-Henning Kamp continue; 107595f1a897SPoul-Henning Kamp c = preload_search_info(mod, MODINFO_ADDR); 107695f1a897SPoul-Henning Kamp ptr = *(u_char **)c; 107795f1a897SPoul-Henning Kamp c = preload_search_info(mod, MODINFO_SIZE); 107895f1a897SPoul-Henning Kamp len = *(unsigned *)c; 1079fe603109SMaxim Sobolev printf("%s%d: Preloaded image <%s> %d bytes at %p\n", 1080fe603109SMaxim Sobolev MD_NAME, mdunits, name, len, ptr); 1081637f671aSPoul-Henning Kamp md_preloaded(ptr, len); 108295f1a897SPoul-Henning Kamp } 108310b0e058SDima Dorfman status_dev = make_dev(&mdctl_cdevsw, 0xffff00ff, UID_ROOT, GID_WHEEL, 108410b0e058SDima Dorfman 0600, MDCTL_NAME); 108500a6a3c6SPoul-Henning Kamp } 108600a6a3c6SPoul-Henning Kamp 108757e9624eSPoul-Henning Kamp static int 108857e9624eSPoul-Henning Kamp md_modevent(module_t mod, int type, void *data) 108957e9624eSPoul-Henning Kamp { 10909d4b5945SMaxim Sobolev int error; 10919d4b5945SMaxim Sobolev struct md_s *sc; 10929d4b5945SMaxim Sobolev 109357e9624eSPoul-Henning Kamp switch (type) { 109457e9624eSPoul-Henning Kamp case MOD_LOAD: 109557e9624eSPoul-Henning Kamp md_drvinit(NULL); 109657e9624eSPoul-Henning Kamp break; 109757e9624eSPoul-Henning Kamp case MOD_UNLOAD: 10989d4b5945SMaxim Sobolev LIST_FOREACH(sc, &md_softc_list, list) { 1099b40ce416SJulian Elischer error = mddetach(sc->unit, curthread); 11009d4b5945SMaxim Sobolev if (error != 0) 11019d4b5945SMaxim Sobolev return (error); 11029d4b5945SMaxim Sobolev } 110357e9624eSPoul-Henning Kamp if (status_dev) 110457e9624eSPoul-Henning Kamp destroy_dev(status_dev); 110557e9624eSPoul-Henning Kamp status_dev = 0; 110657e9624eSPoul-Henning Kamp break; 110757e9624eSPoul-Henning Kamp default: 110857e9624eSPoul-Henning Kamp break; 110957e9624eSPoul-Henning Kamp } 11109d4b5945SMaxim Sobolev return (0); 111157e9624eSPoul-Henning Kamp } 111257e9624eSPoul-Henning Kamp 111357e9624eSPoul-Henning Kamp static moduledata_t md_mod = { 111410b0e058SDima Dorfman MD_NAME, 111557e9624eSPoul-Henning Kamp md_modevent, 111657e9624eSPoul-Henning Kamp NULL 111757e9624eSPoul-Henning Kamp }; 111857e9624eSPoul-Henning Kamp DECLARE_MODULE(md, md_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR); 111957e9624eSPoul-Henning Kamp MODULE_VERSION(md, MD_MODVER); 112057e9624eSPoul-Henning Kamp 112100a6a3c6SPoul-Henning Kamp 112271e4fff8SPoul-Henning Kamp #ifdef MD_ROOT 112371e4fff8SPoul-Henning Kamp static void 112471e4fff8SPoul-Henning Kamp md_takeroot(void *junk) 112571e4fff8SPoul-Henning Kamp { 112671e4fff8SPoul-Henning Kamp if (mdrootready) 112771e4fff8SPoul-Henning Kamp rootdevnames[0] = "ufs:/dev/md0c"; 112871e4fff8SPoul-Henning Kamp } 112971e4fff8SPoul-Henning Kamp 113071e4fff8SPoul-Henning Kamp SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL); 113171e4fff8SPoul-Henning Kamp #endif 1132