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> 883f54a085SPoul-Henning Kamp 8957e9624eSPoul-Henning Kamp #define MD_MODVER 1 9057e9624eSPoul-Henning Kamp 91f2744793SSheldon Hearn #ifndef MD_NSECT 92f2744793SSheldon Hearn #define MD_NSECT (10000 * 2) 9333edfabeSPoul-Henning Kamp #endif 9433edfabeSPoul-Henning Kamp 95e087ce2dSPoul-Henning Kamp static MALLOC_DEFINE(M_MD, "MD disk", "Memory Disk"); 96e087ce2dSPoul-Henning Kamp static MALLOC_DEFINE(M_MDSECT, "MD sectors", "Memory Disk Sectors"); 9700a6a3c6SPoul-Henning Kamp 9871e4fff8SPoul-Henning Kamp static int md_debug; 9900a6a3c6SPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, mddebug, CTLFLAG_RW, &md_debug, 0, ""); 10000a6a3c6SPoul-Henning Kamp 10171e4fff8SPoul-Henning Kamp #if defined(MD_ROOT) && defined(MD_ROOT_SIZE) 10271e4fff8SPoul-Henning Kamp /* Image gets put here: */ 10371e4fff8SPoul-Henning Kamp static u_char mfs_root[MD_ROOT_SIZE*1024] = "MFS Filesystem goes here"; 10471e4fff8SPoul-Henning Kamp static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here"; 10571e4fff8SPoul-Henning Kamp #endif 10671e4fff8SPoul-Henning Kamp 10771e4fff8SPoul-Henning Kamp static int mdrootready; 1088f8def9eSPoul-Henning Kamp static int mdunits; 10957e9624eSPoul-Henning Kamp static dev_t status_dev = 0; 11057e9624eSPoul-Henning Kamp 1110cfaeeeeSPoul-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 15200a6a3c6SPoul-Henning Kamp struct md_s { 15300a6a3c6SPoul-Henning Kamp int unit; 1543f54a085SPoul-Henning Kamp LIST_ENTRY(md_s) list; 15500a6a3c6SPoul-Henning Kamp struct devstat stats; 1568177437dSPoul-Henning Kamp struct bio_queue_head bio_queue; 15700a6a3c6SPoul-Henning Kamp struct disk disk; 15800a6a3c6SPoul-Henning Kamp dev_t dev; 15995f1a897SPoul-Henning Kamp int busy; 1608f8def9eSPoul-Henning Kamp enum md_types type; 16100a6a3c6SPoul-Henning Kamp unsigned nsect; 162fe603109SMaxim Sobolev unsigned opencount; 1638f8def9eSPoul-Henning Kamp unsigned secsize; 1648f8def9eSPoul-Henning Kamp unsigned flags; 16595f1a897SPoul-Henning Kamp 16695f1a897SPoul-Henning Kamp /* MD_MALLOC related fields */ 16700a6a3c6SPoul-Henning Kamp u_char **secp; 16800a6a3c6SPoul-Henning Kamp 16995f1a897SPoul-Henning Kamp /* MD_PRELOAD related fields */ 17095f1a897SPoul-Henning Kamp u_char *pl_ptr; 17195f1a897SPoul-Henning Kamp unsigned pl_len; 17200a6a3c6SPoul-Henning Kamp 1738f8def9eSPoul-Henning Kamp /* MD_VNODE related fields */ 1748f8def9eSPoul-Henning Kamp struct vnode *vnode; 1758f8def9eSPoul-Henning Kamp struct ucred *cred; 1768f8def9eSPoul-Henning Kamp 177e0cebb40SDima Dorfman /* MD_SWAP related fields */ 1788f8def9eSPoul-Henning Kamp vm_object_t object; 1798f8def9eSPoul-Henning Kamp }; 18000a6a3c6SPoul-Henning Kamp 18100a6a3c6SPoul-Henning Kamp static int 182b40ce416SJulian Elischer mdopen(dev_t dev, int flag, int fmt, struct thread *td) 18300a6a3c6SPoul-Henning Kamp { 18400a6a3c6SPoul-Henning Kamp struct md_s *sc; 18500a6a3c6SPoul-Henning Kamp struct disklabel *dl; 18600a6a3c6SPoul-Henning Kamp 18700a6a3c6SPoul-Henning Kamp if (md_debug) 18800a6a3c6SPoul-Henning Kamp printf("mdopen(%s %x %x %p)\n", 189b40ce416SJulian Elischer devtoname(dev), flag, fmt, td->td_proc); 19000a6a3c6SPoul-Henning Kamp 19100a6a3c6SPoul-Henning Kamp sc = dev->si_drv1; 19200a6a3c6SPoul-Henning Kamp 19300a6a3c6SPoul-Henning Kamp dl = &sc->disk.d_label; 19400a6a3c6SPoul-Henning Kamp bzero(dl, sizeof(*dl)); 1958f8def9eSPoul-Henning Kamp dl->d_secsize = sc->secsize; 1960ac60323SPoul-Henning Kamp dl->d_nsectors = sc->nsect > 63 ? 63 : sc->nsect; 19700a6a3c6SPoul-Henning Kamp dl->d_ntracks = 1; 19895f1a897SPoul-Henning Kamp dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks; 19900a6a3c6SPoul-Henning Kamp dl->d_secperunit = sc->nsect; 20000a6a3c6SPoul-Henning Kamp dl->d_ncylinders = dl->d_secperunit / dl->d_secpercyl; 201fe603109SMaxim Sobolev sc->opencount++; 202fe603109SMaxim Sobolev return (0); 203fe603109SMaxim Sobolev } 204fe603109SMaxim Sobolev 205fe603109SMaxim Sobolev static int 206b40ce416SJulian Elischer mdclose(dev_t dev, int flags, int fmt, struct thread *td) 207fe603109SMaxim Sobolev { 208fe603109SMaxim Sobolev struct md_s *sc = dev->si_drv1; 209fe603109SMaxim Sobolev 210fe603109SMaxim Sobolev sc->opencount--; 21100a6a3c6SPoul-Henning Kamp return (0); 21200a6a3c6SPoul-Henning Kamp } 21300a6a3c6SPoul-Henning Kamp 21400a6a3c6SPoul-Henning Kamp static int 215b40ce416SJulian Elischer mdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 21600a6a3c6SPoul-Henning Kamp { 21700a6a3c6SPoul-Henning Kamp 21800a6a3c6SPoul-Henning Kamp if (md_debug) 21900a6a3c6SPoul-Henning Kamp printf("mdioctl(%s %lx %p %x %p)\n", 220b40ce416SJulian Elischer devtoname(dev), cmd, addr, flags, td); 22100a6a3c6SPoul-Henning Kamp 22200a6a3c6SPoul-Henning Kamp return (ENOIOCTL); 22300a6a3c6SPoul-Henning Kamp } 22400a6a3c6SPoul-Henning Kamp 225b4a4f93cSPoul-Henning Kamp static int 226b4a4f93cSPoul-Henning Kamp mdstart_malloc(struct md_s *sc, struct bio *bp) 22700a6a3c6SPoul-Henning Kamp { 2288f8def9eSPoul-Henning Kamp int i; 22900a6a3c6SPoul-Henning Kamp devstat_trans_flags dop; 23000a6a3c6SPoul-Henning Kamp u_char *secp, **secpp, *dst; 23100a6a3c6SPoul-Henning Kamp unsigned secno, nsec, secval, uc; 23200a6a3c6SPoul-Henning Kamp 2338177437dSPoul-Henning Kamp if (bp->bio_cmd == BIO_DELETE) 23400a6a3c6SPoul-Henning Kamp dop = DEVSTAT_NO_DATA; 2358177437dSPoul-Henning Kamp else if (bp->bio_cmd == BIO_READ) 23600a6a3c6SPoul-Henning Kamp dop = DEVSTAT_READ; 23700a6a3c6SPoul-Henning Kamp else 23800a6a3c6SPoul-Henning Kamp dop = DEVSTAT_WRITE; 23900a6a3c6SPoul-Henning Kamp 24096b6a55fSPoul-Henning Kamp nsec = bp->bio_bcount / sc->secsize; 2418177437dSPoul-Henning Kamp secno = bp->bio_pblkno; 2428177437dSPoul-Henning Kamp dst = bp->bio_data; 24300a6a3c6SPoul-Henning Kamp while (nsec--) { 24400a6a3c6SPoul-Henning Kamp secpp = &sc->secp[secno]; 24521c3015aSDoug Rabson if ((uintptr_t)*secpp > 255) { 24600a6a3c6SPoul-Henning Kamp secp = *secpp; 24700a6a3c6SPoul-Henning Kamp secval = 0; 24800a6a3c6SPoul-Henning Kamp } else { 24996b6a55fSPoul-Henning Kamp secp = NULL; 25021c3015aSDoug Rabson secval = (uintptr_t) *secpp; 25100a6a3c6SPoul-Henning Kamp } 25296b6a55fSPoul-Henning Kamp 25333edfabeSPoul-Henning Kamp if (md_debug > 2) 2548177437dSPoul-Henning Kamp printf("%x %p %p %d\n", 2558177437dSPoul-Henning Kamp bp->bio_flags, secpp, secp, secval); 25600a6a3c6SPoul-Henning Kamp 2578177437dSPoul-Henning Kamp if (bp->bio_cmd == BIO_DELETE) { 25896b6a55fSPoul-Henning Kamp if (!(sc->flags & MD_RESERVE) && secp != NULL) { 25900a6a3c6SPoul-Henning Kamp FREE(secp, M_MDSECT); 26000a6a3c6SPoul-Henning Kamp *secpp = 0; 26100a6a3c6SPoul-Henning Kamp } 2628177437dSPoul-Henning Kamp } else if (bp->bio_cmd == BIO_READ) { 26396b6a55fSPoul-Henning Kamp if (secp != NULL) { 26496b6a55fSPoul-Henning Kamp bcopy(secp, dst, sc->secsize); 26500a6a3c6SPoul-Henning Kamp } else if (secval) { 26696b6a55fSPoul-Henning Kamp for (i = 0; i < sc->secsize; i++) 26700a6a3c6SPoul-Henning Kamp dst[i] = secval; 26800a6a3c6SPoul-Henning Kamp } else { 26996b6a55fSPoul-Henning Kamp bzero(dst, sc->secsize); 27000a6a3c6SPoul-Henning Kamp } 27100a6a3c6SPoul-Henning Kamp } else { 2728f8def9eSPoul-Henning Kamp if (sc->flags & MD_COMPRESS) { 27300a6a3c6SPoul-Henning Kamp uc = dst[0]; 27496b6a55fSPoul-Henning Kamp for (i = 1; i < sc->secsize; i++) 27500a6a3c6SPoul-Henning Kamp if (dst[i] != uc) 27600a6a3c6SPoul-Henning Kamp break; 2778f8def9eSPoul-Henning Kamp } else { 2788f8def9eSPoul-Henning Kamp i = 0; 2798f8def9eSPoul-Henning Kamp uc = 0; 2808f8def9eSPoul-Henning Kamp } 28196b6a55fSPoul-Henning Kamp if (i == sc->secsize) { 28200a6a3c6SPoul-Henning Kamp if (secp) 28300a6a3c6SPoul-Henning Kamp FREE(secp, M_MDSECT); 28421c3015aSDoug Rabson *secpp = (u_char *)(uintptr_t)uc; 28500a6a3c6SPoul-Henning Kamp } else { 28696b6a55fSPoul-Henning Kamp if (secp == NULL) 28796b6a55fSPoul-Henning Kamp MALLOC(secp, u_char *, sc->secsize, M_MDSECT, M_WAITOK); 28896b6a55fSPoul-Henning Kamp bcopy(dst, secp, sc->secsize); 28900a6a3c6SPoul-Henning Kamp *secpp = secp; 29000a6a3c6SPoul-Henning Kamp } 29100a6a3c6SPoul-Henning Kamp } 29200a6a3c6SPoul-Henning Kamp secno++; 29396b6a55fSPoul-Henning Kamp dst += sc->secsize; 29400a6a3c6SPoul-Henning Kamp } 2958177437dSPoul-Henning Kamp bp->bio_resid = 0; 296b4a4f93cSPoul-Henning Kamp return (0); 29700a6a3c6SPoul-Henning Kamp } 29800a6a3c6SPoul-Henning Kamp 29971e4fff8SPoul-Henning Kamp 300b4a4f93cSPoul-Henning Kamp static int 301b4a4f93cSPoul-Henning Kamp mdstart_preload(struct md_s *sc, struct bio *bp) 30271e4fff8SPoul-Henning Kamp { 30371e4fff8SPoul-Henning Kamp devstat_trans_flags dop; 30471e4fff8SPoul-Henning Kamp 3058177437dSPoul-Henning Kamp if (bp->bio_cmd == BIO_DELETE) { 30671e4fff8SPoul-Henning Kamp dop = DEVSTAT_NO_DATA; 3078177437dSPoul-Henning Kamp } else if (bp->bio_cmd == BIO_READ) { 30871e4fff8SPoul-Henning Kamp dop = DEVSTAT_READ; 3098177437dSPoul-Henning Kamp bcopy(sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_data, bp->bio_bcount); 31071e4fff8SPoul-Henning Kamp } else { 31171e4fff8SPoul-Henning Kamp dop = DEVSTAT_WRITE; 3128177437dSPoul-Henning Kamp bcopy(bp->bio_data, sc->pl_ptr + (bp->bio_pblkno << DEV_BSHIFT), bp->bio_bcount); 31371e4fff8SPoul-Henning Kamp } 3148177437dSPoul-Henning Kamp bp->bio_resid = 0; 315b4a4f93cSPoul-Henning Kamp return (0); 31671e4fff8SPoul-Henning Kamp } 31771e4fff8SPoul-Henning Kamp 318b4a4f93cSPoul-Henning Kamp static int 319b4a4f93cSPoul-Henning Kamp mdstart_vnode(struct md_s *sc, struct bio *bp) 3208f8def9eSPoul-Henning Kamp { 3218f8def9eSPoul-Henning Kamp int error; 3228f8def9eSPoul-Henning Kamp struct uio auio; 3238f8def9eSPoul-Henning Kamp struct iovec aiov; 3248f8def9eSPoul-Henning Kamp struct mount *mp; 3258f8def9eSPoul-Henning Kamp 3268f8def9eSPoul-Henning Kamp /* 3278f8def9eSPoul-Henning Kamp * VNODE I/O 3288f8def9eSPoul-Henning Kamp * 3298f8def9eSPoul-Henning Kamp * If an error occurs, we set BIO_ERROR but we do not set 3308f8def9eSPoul-Henning Kamp * B_INVAL because (for a write anyway), the buffer is 3318f8def9eSPoul-Henning Kamp * still valid. 3328f8def9eSPoul-Henning Kamp */ 3338f8def9eSPoul-Henning Kamp 3348f8def9eSPoul-Henning Kamp bzero(&auio, sizeof(auio)); 3358f8def9eSPoul-Henning Kamp 3368f8def9eSPoul-Henning Kamp aiov.iov_base = bp->bio_data; 3378f8def9eSPoul-Henning Kamp aiov.iov_len = bp->bio_bcount; 3388f8def9eSPoul-Henning Kamp auio.uio_iov = &aiov; 3398f8def9eSPoul-Henning Kamp auio.uio_iovcnt = 1; 3408f8def9eSPoul-Henning Kamp auio.uio_offset = (vm_ooffset_t)bp->bio_pblkno * sc->secsize; 3418f8def9eSPoul-Henning Kamp auio.uio_segflg = UIO_SYSSPACE; 3428f8def9eSPoul-Henning Kamp if(bp->bio_cmd == BIO_READ) 3438f8def9eSPoul-Henning Kamp auio.uio_rw = UIO_READ; 3448f8def9eSPoul-Henning Kamp else 3458f8def9eSPoul-Henning Kamp auio.uio_rw = UIO_WRITE; 3468f8def9eSPoul-Henning Kamp auio.uio_resid = bp->bio_bcount; 347b40ce416SJulian Elischer auio.uio_td = curthread; 3487e76bb56SMatthew Dillon /* 3497e76bb56SMatthew Dillon * When reading set IO_DIRECT to try to avoid double-caching 3507e76bb56SMatthew Dillon * the data. When writing IO_DIRECT is not optimal, but we 3517e76bb56SMatthew Dillon * must set IO_NOWDRAIN to avoid a wdrain deadlock. 3527e76bb56SMatthew Dillon */ 3538f8def9eSPoul-Henning Kamp if (bp->bio_cmd == BIO_READ) { 354b40ce416SJulian Elischer vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread); 3557e76bb56SMatthew Dillon error = VOP_READ(sc->vnode, &auio, IO_DIRECT, sc->cred); 3568f8def9eSPoul-Henning Kamp } else { 3578f8def9eSPoul-Henning Kamp (void) vn_start_write(sc->vnode, &mp, V_WAIT); 358b40ce416SJulian Elischer vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread); 3597e76bb56SMatthew Dillon error = VOP_WRITE(sc->vnode, &auio, IO_NOWDRAIN, sc->cred); 3608f8def9eSPoul-Henning Kamp vn_finished_write(mp); 3618f8def9eSPoul-Henning Kamp } 362b40ce416SJulian Elischer VOP_UNLOCK(sc->vnode, 0, curthread); 3638f8def9eSPoul-Henning Kamp bp->bio_resid = auio.uio_resid; 364b4a4f93cSPoul-Henning Kamp return (error); 3658f8def9eSPoul-Henning Kamp } 3668f8def9eSPoul-Henning Kamp 367b4a4f93cSPoul-Henning Kamp static int 368b4a4f93cSPoul-Henning Kamp mdstart_swap(struct md_s *sc, struct bio *bp) 3698f8def9eSPoul-Henning Kamp { 3708f8def9eSPoul-Henning Kamp 3718f8def9eSPoul-Henning Kamp if ((bp->bio_cmd == BIO_DELETE) && (sc->flags & MD_RESERVE)) 3728f8def9eSPoul-Henning Kamp biodone(bp); 3738f8def9eSPoul-Henning Kamp else 3748f8def9eSPoul-Henning Kamp vm_pager_strategy(sc->object, bp); 375b4a4f93cSPoul-Henning Kamp return (-1); 3768f8def9eSPoul-Henning Kamp } 3778f8def9eSPoul-Henning Kamp 3788f8def9eSPoul-Henning Kamp static void 3798f8def9eSPoul-Henning Kamp mdstrategy(struct bio *bp) 38000a6a3c6SPoul-Henning Kamp { 38100a6a3c6SPoul-Henning Kamp struct md_s *sc; 382b4a4f93cSPoul-Henning Kamp int error; 38300a6a3c6SPoul-Henning Kamp 3848f8def9eSPoul-Henning Kamp if (md_debug > 1) 3850d2af521SKirk McKusick printf("mdstrategy(%p) %s %x, %lld, %ld, %p)\n", 3861ab0b5f9SBruce Evans (void *)bp, devtoname(bp->bio_dev), bp->bio_flags, 3871ab0b5f9SBruce Evans (long long)bp->bio_blkno, bp->bio_bcount / DEV_BSIZE, 3881ab0b5f9SBruce Evans (void *)bp->bio_data); 3898f8def9eSPoul-Henning Kamp 3908f8def9eSPoul-Henning Kamp sc = bp->bio_dev->si_drv1; 3918f8def9eSPoul-Henning Kamp 3928f8def9eSPoul-Henning Kamp /* XXX: LOCK(sc->lock) */ 3938f8def9eSPoul-Henning Kamp bioqdisksort(&sc->bio_queue, bp); 3948f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(sc->lock) */ 3958f8def9eSPoul-Henning Kamp 3968f8def9eSPoul-Henning Kamp if (atomic_cmpset_int(&sc->busy, 0, 1) == 0) 3978f8def9eSPoul-Henning Kamp return; 3988f8def9eSPoul-Henning Kamp 399b4a4f93cSPoul-Henning Kamp for (;;) { 400b4a4f93cSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 401b4a4f93cSPoul-Henning Kamp bp = bioq_first(&sc->bio_queue); 402b4a4f93cSPoul-Henning Kamp if (bp) 403b4a4f93cSPoul-Henning Kamp bioq_remove(&sc->bio_queue, bp); 404b4a4f93cSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 405b4a4f93cSPoul-Henning Kamp if (!bp) 406b4a4f93cSPoul-Henning Kamp break; 407b4a4f93cSPoul-Henning Kamp 408b4a4f93cSPoul-Henning Kamp 4098f8def9eSPoul-Henning Kamp switch (sc->type) { 4108f8def9eSPoul-Henning Kamp case MD_MALLOC: 411b4a4f93cSPoul-Henning Kamp devstat_start_transaction(&sc->stats); 412b4a4f93cSPoul-Henning Kamp error = mdstart_malloc(sc, bp); 4138f8def9eSPoul-Henning Kamp break; 4148f8def9eSPoul-Henning Kamp case MD_PRELOAD: 415b4a4f93cSPoul-Henning Kamp devstat_start_transaction(&sc->stats); 416b4a4f93cSPoul-Henning Kamp error = mdstart_preload(sc, bp); 4178f8def9eSPoul-Henning Kamp break; 4188f8def9eSPoul-Henning Kamp case MD_VNODE: 419b4a4f93cSPoul-Henning Kamp devstat_start_transaction(&sc->stats); 420b4a4f93cSPoul-Henning Kamp error = mdstart_vnode(sc, bp); 4218f8def9eSPoul-Henning Kamp break; 4228f8def9eSPoul-Henning Kamp case MD_SWAP: 423b4a4f93cSPoul-Henning Kamp error = mdstart_swap(sc, bp); 4248f8def9eSPoul-Henning Kamp break; 4258f8def9eSPoul-Henning Kamp default: 4268f8def9eSPoul-Henning Kamp panic("Impossible md(type)"); 4278f8def9eSPoul-Henning Kamp break; 4288f8def9eSPoul-Henning Kamp } 429b4a4f93cSPoul-Henning Kamp 430b4a4f93cSPoul-Henning Kamp if (error != -1) 431b4a4f93cSPoul-Henning Kamp biofinish(bp, &sc->stats, error); 432b4a4f93cSPoul-Henning Kamp } 4338f8def9eSPoul-Henning Kamp sc->busy = 0; 4348f8def9eSPoul-Henning Kamp } 4358f8def9eSPoul-Henning Kamp 4368f8def9eSPoul-Henning Kamp static struct md_s * 4378f8def9eSPoul-Henning Kamp mdfind(int unit) 4388f8def9eSPoul-Henning Kamp { 4398f8def9eSPoul-Henning Kamp struct md_s *sc; 4408f8def9eSPoul-Henning Kamp 4418f8def9eSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 4423f54a085SPoul-Henning Kamp LIST_FOREACH(sc, &md_softc_list, list) { 4433f54a085SPoul-Henning Kamp if (sc->unit == unit) 4448f8def9eSPoul-Henning Kamp break; 4458f8def9eSPoul-Henning Kamp } 4468f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 4478f8def9eSPoul-Henning Kamp return (sc); 4488f8def9eSPoul-Henning Kamp } 4498f8def9eSPoul-Henning Kamp 4508f8def9eSPoul-Henning Kamp static struct md_s * 4518f8def9eSPoul-Henning Kamp mdnew(int unit) 4528f8def9eSPoul-Henning Kamp { 4538f8def9eSPoul-Henning Kamp struct md_s *sc; 4548f8def9eSPoul-Henning Kamp int max = -1; 4558f8def9eSPoul-Henning Kamp 4568f8def9eSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 4578f8def9eSPoul-Henning Kamp LIST_FOREACH(sc, &md_softc_list, list) { 4588f8def9eSPoul-Henning Kamp if (sc->unit == unit) { 4598f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 4603f54a085SPoul-Henning Kamp return (NULL); 4613f54a085SPoul-Henning Kamp } 4628f8def9eSPoul-Henning Kamp if (sc->unit > max) 4638f8def9eSPoul-Henning Kamp max = sc->unit; 4648f8def9eSPoul-Henning Kamp } 4658f8def9eSPoul-Henning Kamp if (unit == -1) 4668f8def9eSPoul-Henning Kamp unit = max + 1; 4678f8def9eSPoul-Henning Kamp if (unit > DKMAXUNIT) 4688f8def9eSPoul-Henning Kamp return (NULL); 4697cc0979fSDavid Malone MALLOC(sc, struct md_s *, sizeof(*sc), M_MD, M_WAITOK | M_ZERO); 4703f54a085SPoul-Henning Kamp sc->unit = unit; 4718f8def9eSPoul-Henning Kamp LIST_INSERT_HEAD(&md_softc_list, sc, list); 4728f8def9eSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 4738f8def9eSPoul-Henning Kamp return (sc); 4748f8def9eSPoul-Henning Kamp } 4758f8def9eSPoul-Henning Kamp 4768f8def9eSPoul-Henning Kamp static void 4778f8def9eSPoul-Henning Kamp mdinit(struct md_s *sc) 4788f8def9eSPoul-Henning Kamp { 4798f8def9eSPoul-Henning Kamp 4808177437dSPoul-Henning Kamp bioq_init(&sc->bio_queue); 481174b5e9aSPoul-Henning Kamp devstat_add_entry(&sc->stats, MD_NAME, sc->unit, sc->secsize, 48295f1a897SPoul-Henning Kamp DEVSTAT_NO_ORDERED_TAGS, 48371e4fff8SPoul-Henning Kamp DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, 48471e4fff8SPoul-Henning Kamp DEVSTAT_PRIORITY_OTHER); 4850cfaeeeeSPoul-Henning Kamp sc->dev = disk_create(sc->unit, &sc->disk, 0, &md_cdevsw, &mddisk_cdevsw); 48695f1a897SPoul-Henning Kamp sc->dev->si_drv1 = sc; 48771e4fff8SPoul-Henning Kamp } 48871e4fff8SPoul-Henning Kamp 48996b6a55fSPoul-Henning Kamp /* 49096b6a55fSPoul-Henning Kamp * XXX: we should check that the range they feed us is mapped. 49196b6a55fSPoul-Henning Kamp * XXX: we should implement read-only. 49296b6a55fSPoul-Henning Kamp */ 49396b6a55fSPoul-Henning Kamp 494637f671aSPoul-Henning Kamp static int 495637f671aSPoul-Henning Kamp mdcreate_preload(struct md_ioctl *mdio) 49671e4fff8SPoul-Henning Kamp { 49771e4fff8SPoul-Henning Kamp struct md_s *sc; 49871e4fff8SPoul-Henning Kamp 499637f671aSPoul-Henning Kamp if (mdio->md_size == 0) 500637f671aSPoul-Henning Kamp return (EINVAL); 501637f671aSPoul-Henning Kamp if (mdio->md_options & ~(MD_AUTOUNIT)) 502637f671aSPoul-Henning Kamp return (EINVAL); 503637f671aSPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 5048f8def9eSPoul-Henning Kamp sc = mdnew(-1); 5058f8def9eSPoul-Henning Kamp if (sc == NULL) 506637f671aSPoul-Henning Kamp return (ENOMEM); 507637f671aSPoul-Henning Kamp mdio->md_unit = sc->unit; 508637f671aSPoul-Henning Kamp } else { 509637f671aSPoul-Henning Kamp sc = mdnew(mdio->md_unit); 510637f671aSPoul-Henning Kamp if (sc == NULL) 511637f671aSPoul-Henning Kamp return (EBUSY); 512637f671aSPoul-Henning Kamp } 51366c16191SPoul-Henning Kamp sc->type = MD_PRELOAD; 5148f8def9eSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 515637f671aSPoul-Henning Kamp sc->nsect = mdio->md_size; 51626a0ee75SDima Dorfman sc->flags = mdio->md_options & MD_FORCE; 51796b6a55fSPoul-Henning Kamp /* Cast to pointer size, then to pointer to avoid warning */ 518dc57d7c6SPeter Wemm sc->pl_ptr = (u_char *)(uintptr_t)mdio->md_base; 519637f671aSPoul-Henning Kamp sc->pl_len = (mdio->md_size << DEV_BSHIFT); 5208f8def9eSPoul-Henning Kamp mdinit(sc); 521637f671aSPoul-Henning Kamp return (0); 52295f1a897SPoul-Henning Kamp } 52395f1a897SPoul-Henning Kamp 524637f671aSPoul-Henning Kamp 5258f8def9eSPoul-Henning Kamp static int 5268f8def9eSPoul-Henning Kamp mdcreate_malloc(struct md_ioctl *mdio) 52795f1a897SPoul-Henning Kamp { 52895f1a897SPoul-Henning Kamp struct md_s *sc; 5298f8def9eSPoul-Henning Kamp unsigned u; 53095f1a897SPoul-Henning Kamp 5318f8def9eSPoul-Henning Kamp if (mdio->md_size == 0) 5328f8def9eSPoul-Henning Kamp return (EINVAL); 5338f8def9eSPoul-Henning Kamp if (mdio->md_options & ~(MD_AUTOUNIT | MD_COMPRESS | MD_RESERVE)) 5348f8def9eSPoul-Henning Kamp return (EINVAL); 5358f8def9eSPoul-Henning Kamp /* Compression doesn't make sense if we have reserved space */ 5368f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_RESERVE) 5378f8def9eSPoul-Henning Kamp mdio->md_options &= ~MD_COMPRESS; 5388f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 5398f8def9eSPoul-Henning Kamp sc = mdnew(-1); 5403f54a085SPoul-Henning Kamp if (sc == NULL) 5418f8def9eSPoul-Henning Kamp return (ENOMEM); 5428f8def9eSPoul-Henning Kamp mdio->md_unit = sc->unit; 5438f8def9eSPoul-Henning Kamp } else { 5448f8def9eSPoul-Henning Kamp sc = mdnew(mdio->md_unit); 5458f8def9eSPoul-Henning Kamp if (sc == NULL) 5468f8def9eSPoul-Henning Kamp return (EBUSY); 5478f8def9eSPoul-Henning Kamp } 54866c16191SPoul-Henning Kamp sc->type = MD_MALLOC; 5498f8def9eSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 5508f8def9eSPoul-Henning Kamp sc->nsect = mdio->md_size; 55126a0ee75SDima Dorfman sc->flags = mdio->md_options & (MD_COMPRESS | MD_FORCE); 5528f8def9eSPoul-Henning Kamp MALLOC(sc->secp, u_char **, sc->nsect * sizeof(u_char *), M_MD, M_WAITOK | M_ZERO); 55396b6a55fSPoul-Henning Kamp if (mdio->md_options & MD_RESERVE) { 5548f8def9eSPoul-Henning Kamp for (u = 0; u < sc->nsect; u++) 5558f8def9eSPoul-Henning Kamp MALLOC(sc->secp[u], u_char *, DEV_BSIZE, M_MDSECT, M_WAITOK | M_ZERO); 5568f8def9eSPoul-Henning Kamp } 557174b5e9aSPoul-Henning Kamp printf("%s%d: Malloc disk\n", MD_NAME, sc->unit); 5588f8def9eSPoul-Henning Kamp mdinit(sc); 5598f8def9eSPoul-Henning Kamp return (0); 56000a6a3c6SPoul-Henning Kamp } 56100a6a3c6SPoul-Henning Kamp 5623f54a085SPoul-Henning Kamp 5638f8def9eSPoul-Henning Kamp static int 5648f8def9eSPoul-Henning Kamp mdsetcred(struct md_s *sc, struct ucred *cred) 5658f8def9eSPoul-Henning Kamp { 5668f8def9eSPoul-Henning Kamp char *tmpbuf; 5678f8def9eSPoul-Henning Kamp int error = 0; 5688f8def9eSPoul-Henning Kamp 5693f54a085SPoul-Henning Kamp /* 5708f8def9eSPoul-Henning Kamp * Set credits in our softc 5713f54a085SPoul-Henning Kamp */ 5728f8def9eSPoul-Henning Kamp 5738f8def9eSPoul-Henning Kamp if (sc->cred) 5748f8def9eSPoul-Henning Kamp crfree(sc->cred); 575bd78ceceSJohn Baldwin sc->cred = crhold(cred); 5768f8def9eSPoul-Henning Kamp 5778f8def9eSPoul-Henning Kamp /* 5788f8def9eSPoul-Henning Kamp * Horrible kludge to establish credentials for NFS XXX. 5798f8def9eSPoul-Henning Kamp */ 5808f8def9eSPoul-Henning Kamp 5818f8def9eSPoul-Henning Kamp if (sc->vnode) { 5828f8def9eSPoul-Henning Kamp struct uio auio; 5838f8def9eSPoul-Henning Kamp struct iovec aiov; 5848f8def9eSPoul-Henning Kamp 5858f8def9eSPoul-Henning Kamp tmpbuf = malloc(sc->secsize, M_TEMP, M_WAITOK); 5868f8def9eSPoul-Henning Kamp bzero(&auio, sizeof(auio)); 5878f8def9eSPoul-Henning Kamp 5888f8def9eSPoul-Henning Kamp aiov.iov_base = tmpbuf; 5898f8def9eSPoul-Henning Kamp aiov.iov_len = sc->secsize; 5908f8def9eSPoul-Henning Kamp auio.uio_iov = &aiov; 5918f8def9eSPoul-Henning Kamp auio.uio_iovcnt = 1; 5928f8def9eSPoul-Henning Kamp auio.uio_offset = 0; 5938f8def9eSPoul-Henning Kamp auio.uio_rw = UIO_READ; 5948f8def9eSPoul-Henning Kamp auio.uio_segflg = UIO_SYSSPACE; 5958f8def9eSPoul-Henning Kamp auio.uio_resid = aiov.iov_len; 596b40ce416SJulian Elischer vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread); 5978f8def9eSPoul-Henning Kamp error = VOP_READ(sc->vnode, &auio, 0, sc->cred); 598b40ce416SJulian Elischer VOP_UNLOCK(sc->vnode, 0, curthread); 5998f8def9eSPoul-Henning Kamp free(tmpbuf, M_TEMP); 6008f8def9eSPoul-Henning Kamp } 6018f8def9eSPoul-Henning Kamp return (error); 6028f8def9eSPoul-Henning Kamp } 6038f8def9eSPoul-Henning Kamp 6048f8def9eSPoul-Henning Kamp static int 605b40ce416SJulian Elischer mdcreate_vnode(struct md_ioctl *mdio, struct thread *td) 6068f8def9eSPoul-Henning Kamp { 6078f8def9eSPoul-Henning Kamp struct md_s *sc; 6088f8def9eSPoul-Henning Kamp struct vattr vattr; 6098f8def9eSPoul-Henning Kamp struct nameidata nd; 6108f8def9eSPoul-Henning Kamp int error, flags; 6118f8def9eSPoul-Henning Kamp 6128f8def9eSPoul-Henning Kamp flags = FREAD|FWRITE; 613b40ce416SJulian Elischer NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, mdio->md_file, td); 6148f8def9eSPoul-Henning Kamp error = vn_open(&nd, &flags, 0); 6158f8def9eSPoul-Henning Kamp if (error) { 6168f8def9eSPoul-Henning Kamp if (error != EACCES && error != EPERM && error != EROFS) 6178f8def9eSPoul-Henning Kamp return (error); 6188f8def9eSPoul-Henning Kamp flags &= ~FWRITE; 619b40ce416SJulian Elischer NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, mdio->md_file, td); 6208f8def9eSPoul-Henning Kamp error = vn_open(&nd, &flags, 0); 6218f8def9eSPoul-Henning Kamp if (error) 6228f8def9eSPoul-Henning Kamp return (error); 6238f8def9eSPoul-Henning Kamp } 6248f8def9eSPoul-Henning Kamp NDFREE(&nd, NDF_ONLY_PNBUF); 6258f8def9eSPoul-Henning Kamp if (nd.ni_vp->v_type != VREG || 626a854ed98SJohn Baldwin (error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred, td))) { 627b40ce416SJulian Elischer VOP_UNLOCK(nd.ni_vp, 0, td); 628a854ed98SJohn Baldwin (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 6298f8def9eSPoul-Henning Kamp return (error ? error : EINVAL); 6308f8def9eSPoul-Henning Kamp } 631b40ce416SJulian Elischer VOP_UNLOCK(nd.ni_vp, 0, td); 6329589c256SPoul-Henning Kamp 6339589c256SPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 6349589c256SPoul-Henning Kamp sc = mdnew(-1); 6359589c256SPoul-Henning Kamp mdio->md_unit = sc->unit; 6369589c256SPoul-Henning Kamp } else { 6379589c256SPoul-Henning Kamp sc = mdnew(mdio->md_unit); 6389589c256SPoul-Henning Kamp } 6399589c256SPoul-Henning Kamp if (sc == NULL) { 6409589c256SPoul-Henning Kamp (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 6419589c256SPoul-Henning Kamp return (EBUSY); 6429589c256SPoul-Henning Kamp } 6439589c256SPoul-Henning Kamp 6449589c256SPoul-Henning Kamp sc->type = MD_VNODE; 6459589c256SPoul-Henning Kamp sc->flags = mdio->md_options & MD_FORCE; 6469589c256SPoul-Henning Kamp if (!(flags & FWRITE)) 6479589c256SPoul-Henning Kamp sc->flags |= MD_READONLY; 6488f8def9eSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 6498f8def9eSPoul-Henning Kamp sc->vnode = nd.ni_vp; 6508f8def9eSPoul-Henning Kamp 6518f8def9eSPoul-Henning Kamp /* 6528f8def9eSPoul-Henning Kamp * If the size is specified, override the file attributes. 6538f8def9eSPoul-Henning Kamp */ 6548f8def9eSPoul-Henning Kamp if (mdio->md_size) 6558f8def9eSPoul-Henning Kamp sc->nsect = mdio->md_size; 6568f8def9eSPoul-Henning Kamp else 6578f8def9eSPoul-Henning Kamp sc->nsect = vattr.va_size / sc->secsize; /* XXX: round up ? */ 6583d3c27feSThomas Moestl if (sc->nsect == 0) { 659a854ed98SJohn Baldwin (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 6603d3c27feSThomas Moestl return (EINVAL); 6613d3c27feSThomas Moestl } 662a854ed98SJohn Baldwin error = mdsetcred(sc, td->td_ucred); 6638f8def9eSPoul-Henning Kamp if (error) { 664a854ed98SJohn Baldwin (void) vn_close(nd.ni_vp, flags, td->td_ucred, td); 6658f8def9eSPoul-Henning Kamp return (error); 6668f8def9eSPoul-Henning Kamp } 6678f8def9eSPoul-Henning Kamp mdinit(sc); 6688f8def9eSPoul-Henning Kamp return (0); 6698f8def9eSPoul-Henning Kamp } 6708f8def9eSPoul-Henning Kamp 6718f8def9eSPoul-Henning Kamp static int 672b40ce416SJulian Elischer mddestroy(struct md_s *sc, struct thread *td) 6738f8def9eSPoul-Henning Kamp { 6748f8def9eSPoul-Henning Kamp unsigned u; 6758f8def9eSPoul-Henning Kamp 6760cddd8f0SMatthew Dillon GIANT_REQUIRED; 6770cddd8f0SMatthew Dillon 6781f4ee1aaSPoul-Henning Kamp if (sc->dev != NULL) { 6791f4ee1aaSPoul-Henning Kamp devstat_remove_entry(&sc->stats); 6808f8def9eSPoul-Henning Kamp disk_destroy(sc->dev); 6811f4ee1aaSPoul-Henning Kamp } 6828f8def9eSPoul-Henning Kamp if (sc->vnode != NULL) 6839d4b5945SMaxim Sobolev (void)vn_close(sc->vnode, sc->flags & MD_READONLY ? 684b40ce416SJulian Elischer FREAD : (FREAD|FWRITE), sc->cred, td); 6858f8def9eSPoul-Henning Kamp if (sc->cred != NULL) 6868f8def9eSPoul-Henning Kamp crfree(sc->cred); 6875a025167SDima Dorfman if (sc->object != NULL) { 6888f8def9eSPoul-Henning Kamp vm_pager_deallocate(sc->object); 6895a025167SDima Dorfman } 6908f8def9eSPoul-Henning Kamp if (sc->secp != NULL) { 69196b6a55fSPoul-Henning Kamp for (u = 0; u < sc->nsect; u++) 6928f8def9eSPoul-Henning Kamp if ((uintptr_t)sc->secp[u] > 255) 6938f8def9eSPoul-Henning Kamp FREE(sc->secp[u], M_MDSECT); 6948f8def9eSPoul-Henning Kamp FREE(sc->secp, M_MD); 6958f8def9eSPoul-Henning Kamp } 6961f4ee1aaSPoul-Henning Kamp 6971f4ee1aaSPoul-Henning Kamp /* XXX: LOCK(unique unit numbers) */ 6981f4ee1aaSPoul-Henning Kamp LIST_REMOVE(sc, list); 6991f4ee1aaSPoul-Henning Kamp /* XXX: UNLOCK(unique unit numbers) */ 7001f4ee1aaSPoul-Henning Kamp FREE(sc, M_MD); 7018f8def9eSPoul-Henning Kamp return (0); 7028f8def9eSPoul-Henning Kamp } 7038f8def9eSPoul-Henning Kamp 7048f8def9eSPoul-Henning Kamp static int 705b40ce416SJulian Elischer mdcreate_swap(struct md_ioctl *mdio, struct thread *td) 7068f8def9eSPoul-Henning Kamp { 7078f8def9eSPoul-Henning Kamp int error; 7088f8def9eSPoul-Henning Kamp struct md_s *sc; 7098f8def9eSPoul-Henning Kamp 7100cddd8f0SMatthew Dillon GIANT_REQUIRED; 7110cddd8f0SMatthew Dillon 7128f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_AUTOUNIT) { 7138f8def9eSPoul-Henning Kamp sc = mdnew(-1); 7148f8def9eSPoul-Henning Kamp mdio->md_unit = sc->unit; 7158f8def9eSPoul-Henning Kamp } else { 7168f8def9eSPoul-Henning Kamp sc = mdnew(mdio->md_unit); 7178f8def9eSPoul-Henning Kamp } 7188f8def9eSPoul-Henning Kamp if (sc == NULL) 7198f8def9eSPoul-Henning Kamp return (EBUSY); 7208f8def9eSPoul-Henning Kamp 7218f8def9eSPoul-Henning Kamp sc->type = MD_SWAP; 7228f8def9eSPoul-Henning Kamp 7238f8def9eSPoul-Henning Kamp /* 7248f8def9eSPoul-Henning Kamp * Range check. Disallow negative sizes or any size less then the 7258f8def9eSPoul-Henning Kamp * size of a page. Then round to a page. 7268f8def9eSPoul-Henning Kamp */ 7278f8def9eSPoul-Henning Kamp 7281f4ee1aaSPoul-Henning Kamp if (mdio->md_size == 0) { 729b40ce416SJulian Elischer mddestroy(sc, td); 7308f8def9eSPoul-Henning Kamp return (EDOM); 7311f4ee1aaSPoul-Henning Kamp } 7328f8def9eSPoul-Henning Kamp 7338f8def9eSPoul-Henning Kamp /* 7348f8def9eSPoul-Henning Kamp * Allocate an OBJT_SWAP object. 7358f8def9eSPoul-Henning Kamp * 7368f8def9eSPoul-Henning Kamp * sc_secsize is PAGE_SIZE'd 7378f8def9eSPoul-Henning Kamp * 7388f8def9eSPoul-Henning Kamp * mdio->size is in DEV_BSIZE'd chunks. 7398f8def9eSPoul-Henning Kamp * Note the truncation. 7408f8def9eSPoul-Henning Kamp */ 7418f8def9eSPoul-Henning Kamp 7428f8def9eSPoul-Henning Kamp sc->secsize = PAGE_SIZE; 7438f8def9eSPoul-Henning Kamp sc->nsect = mdio->md_size / (PAGE_SIZE / DEV_BSIZE); 7448f8def9eSPoul-Henning Kamp sc->object = vm_pager_allocate(OBJT_SWAP, NULL, sc->secsize * (vm_offset_t)sc->nsect, VM_PROT_DEFAULT, 0); 74526a0ee75SDima Dorfman sc->flags = mdio->md_options & MD_FORCE; 7468f8def9eSPoul-Henning Kamp if (mdio->md_options & MD_RESERVE) { 7478f8def9eSPoul-Henning Kamp if (swap_pager_reserve(sc->object, 0, sc->nsect) < 0) { 7488f8def9eSPoul-Henning Kamp vm_pager_deallocate(sc->object); 7498f8def9eSPoul-Henning Kamp sc->object = NULL; 750b40ce416SJulian Elischer mddestroy(sc, td); 7518f8def9eSPoul-Henning Kamp return (EDOM); 7528f8def9eSPoul-Henning Kamp } 7538f8def9eSPoul-Henning Kamp } 754a854ed98SJohn Baldwin error = mdsetcred(sc, td->td_ucred); 7558f8def9eSPoul-Henning Kamp if (error) 756b40ce416SJulian Elischer mddestroy(sc, td); 7578f8def9eSPoul-Henning Kamp else 7588f8def9eSPoul-Henning Kamp mdinit(sc); 7598f8def9eSPoul-Henning Kamp return (error); 7608f8def9eSPoul-Henning Kamp } 7618f8def9eSPoul-Henning Kamp 7628f8def9eSPoul-Henning Kamp static int 763b40ce416SJulian Elischer mddetach(int unit, struct thread *td) 7649d4b5945SMaxim Sobolev { 7659d4b5945SMaxim Sobolev struct md_s *sc; 7669d4b5945SMaxim Sobolev 7679d4b5945SMaxim Sobolev sc = mdfind(unit); 7689d4b5945SMaxim Sobolev if (sc == NULL) 7699d4b5945SMaxim Sobolev return (ENOENT); 7709d4b5945SMaxim Sobolev if (sc->opencount != 0 && !(sc->flags & MD_FORCE)) 7719d4b5945SMaxim Sobolev return (EBUSY); 7729d4b5945SMaxim Sobolev switch(sc->type) { 7739d4b5945SMaxim Sobolev case MD_VNODE: 7749d4b5945SMaxim Sobolev case MD_SWAP: 7759d4b5945SMaxim Sobolev case MD_MALLOC: 7769d4b5945SMaxim Sobolev case MD_PRELOAD: 777b40ce416SJulian Elischer return (mddestroy(sc, td)); 7789d4b5945SMaxim Sobolev default: 7799d4b5945SMaxim Sobolev return (EOPNOTSUPP); 7809d4b5945SMaxim Sobolev } 7819d4b5945SMaxim Sobolev } 7829d4b5945SMaxim Sobolev 7839d4b5945SMaxim Sobolev static int 784b40ce416SJulian Elischer mdctlioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) 7858f8def9eSPoul-Henning Kamp { 7868f8def9eSPoul-Henning Kamp struct md_ioctl *mdio; 7878f8def9eSPoul-Henning Kamp struct md_s *sc; 7888f8def9eSPoul-Henning Kamp 7898f8def9eSPoul-Henning Kamp if (md_debug) 7908f8def9eSPoul-Henning Kamp printf("mdctlioctl(%s %lx %p %x %p)\n", 791b40ce416SJulian Elischer devtoname(dev), cmd, addr, flags, td); 7928f8def9eSPoul-Henning Kamp 79353d745bcSDima Dorfman /* 79453d745bcSDima Dorfman * We assert the version number in the individual ioctl 79553d745bcSDima Dorfman * handlers instead of out here because (a) it is possible we 79653d745bcSDima Dorfman * may add another ioctl in the future which doesn't read an 79753d745bcSDima Dorfman * mdio, and (b) the correct return value for an unknown ioctl 79853d745bcSDima Dorfman * is ENOIOCTL, not EINVAL. 79953d745bcSDima Dorfman */ 8008f8def9eSPoul-Henning Kamp mdio = (struct md_ioctl *)addr; 8018f8def9eSPoul-Henning Kamp switch (cmd) { 8028f8def9eSPoul-Henning Kamp case MDIOCATTACH: 80353d745bcSDima Dorfman if (mdio->md_version != MDIOVERSION) 80453d745bcSDima Dorfman return (EINVAL); 8058f8def9eSPoul-Henning Kamp switch (mdio->md_type) { 8068f8def9eSPoul-Henning Kamp case MD_MALLOC: 8078f8def9eSPoul-Henning Kamp return (mdcreate_malloc(mdio)); 8088f8def9eSPoul-Henning Kamp case MD_PRELOAD: 809637f671aSPoul-Henning Kamp return (mdcreate_preload(mdio)); 8108f8def9eSPoul-Henning Kamp case MD_VNODE: 811b40ce416SJulian Elischer return (mdcreate_vnode(mdio, td)); 8128f8def9eSPoul-Henning Kamp case MD_SWAP: 813b40ce416SJulian Elischer return (mdcreate_swap(mdio, td)); 8148f8def9eSPoul-Henning Kamp default: 8158f8def9eSPoul-Henning Kamp return (EINVAL); 8168f8def9eSPoul-Henning Kamp } 8178f8def9eSPoul-Henning Kamp case MDIOCDETACH: 81853d745bcSDima Dorfman if (mdio->md_version != MDIOVERSION) 81953d745bcSDima Dorfman return (EINVAL); 8209d4b5945SMaxim Sobolev if (mdio->md_file != NULL || mdio->md_size != 0 || 8219d4b5945SMaxim Sobolev mdio->md_options != 0) 8228f8def9eSPoul-Henning Kamp return (EINVAL); 823b40ce416SJulian Elischer return (mddetach(mdio->md_unit, td)); 824174b5e9aSPoul-Henning Kamp case MDIOCQUERY: 82553d745bcSDima Dorfman if (mdio->md_version != MDIOVERSION) 82653d745bcSDima Dorfman return (EINVAL); 827174b5e9aSPoul-Henning Kamp sc = mdfind(mdio->md_unit); 828174b5e9aSPoul-Henning Kamp if (sc == NULL) 829174b5e9aSPoul-Henning Kamp return (ENOENT); 830174b5e9aSPoul-Henning Kamp mdio->md_type = sc->type; 831174b5e9aSPoul-Henning Kamp mdio->md_options = sc->flags; 832174b5e9aSPoul-Henning Kamp switch (sc->type) { 833174b5e9aSPoul-Henning Kamp case MD_MALLOC: 834174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect; 835174b5e9aSPoul-Henning Kamp break; 836174b5e9aSPoul-Henning Kamp case MD_PRELOAD: 837174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect; 838174b5e9aSPoul-Henning Kamp (u_char *)(uintptr_t)mdio->md_base = sc->pl_ptr; 839174b5e9aSPoul-Henning Kamp break; 840174b5e9aSPoul-Henning Kamp case MD_SWAP: 841174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect * (PAGE_SIZE / DEV_BSIZE); 842174b5e9aSPoul-Henning Kamp break; 843174b5e9aSPoul-Henning Kamp case MD_VNODE: 844174b5e9aSPoul-Henning Kamp mdio->md_size = sc->nsect; 845174b5e9aSPoul-Henning Kamp /* XXX fill this in */ 846174b5e9aSPoul-Henning Kamp mdio->md_file = NULL; 847174b5e9aSPoul-Henning Kamp break; 848174b5e9aSPoul-Henning Kamp } 849174b5e9aSPoul-Henning Kamp return (0); 8508f8def9eSPoul-Henning Kamp default: 8518f8def9eSPoul-Henning Kamp return (ENOIOCTL); 8528f8def9eSPoul-Henning Kamp }; 8538f8def9eSPoul-Henning Kamp return (ENOIOCTL); 8543f54a085SPoul-Henning Kamp } 8553f54a085SPoul-Henning Kamp 85600a6a3c6SPoul-Henning Kamp static void 857637f671aSPoul-Henning Kamp md_preloaded(u_char *image, unsigned length) 858637f671aSPoul-Henning Kamp { 859637f671aSPoul-Henning Kamp struct md_s *sc; 860637f671aSPoul-Henning Kamp 861637f671aSPoul-Henning Kamp sc = mdnew(-1); 862637f671aSPoul-Henning Kamp if (sc == NULL) 863637f671aSPoul-Henning Kamp return; 864637f671aSPoul-Henning Kamp sc->type = MD_PRELOAD; 865637f671aSPoul-Henning Kamp sc->secsize = DEV_BSIZE; 866637f671aSPoul-Henning Kamp sc->nsect = length / DEV_BSIZE; 867637f671aSPoul-Henning Kamp sc->pl_ptr = image; 868637f671aSPoul-Henning Kamp sc->pl_len = length; 869637f671aSPoul-Henning Kamp if (sc->unit == 0) 870637f671aSPoul-Henning Kamp mdrootready = 1; 871637f671aSPoul-Henning Kamp mdinit(sc); 872637f671aSPoul-Henning Kamp } 873637f671aSPoul-Henning Kamp 874637f671aSPoul-Henning Kamp static void 87500a6a3c6SPoul-Henning Kamp md_drvinit(void *unused) 87600a6a3c6SPoul-Henning Kamp { 87700a6a3c6SPoul-Henning Kamp 87895f1a897SPoul-Henning Kamp caddr_t mod; 87995f1a897SPoul-Henning Kamp caddr_t c; 88095f1a897SPoul-Henning Kamp u_char *ptr, *name, *type; 88195f1a897SPoul-Henning Kamp unsigned len; 88295f1a897SPoul-Henning Kamp 88371e4fff8SPoul-Henning Kamp #ifdef MD_ROOT_SIZE 884637f671aSPoul-Henning Kamp md_preloaded(mfs_root, MD_ROOT_SIZE*1024); 88571e4fff8SPoul-Henning Kamp #endif 88695f1a897SPoul-Henning Kamp mod = NULL; 88795f1a897SPoul-Henning Kamp while ((mod = preload_search_next_name(mod)) != NULL) { 88895f1a897SPoul-Henning Kamp name = (char *)preload_search_info(mod, MODINFO_NAME); 88995f1a897SPoul-Henning Kamp type = (char *)preload_search_info(mod, MODINFO_TYPE); 89095f1a897SPoul-Henning Kamp if (name == NULL) 89195f1a897SPoul-Henning Kamp continue; 89295f1a897SPoul-Henning Kamp if (type == NULL) 89395f1a897SPoul-Henning Kamp continue; 89471e4fff8SPoul-Henning Kamp if (strcmp(type, "md_image") && strcmp(type, "mfs_root")) 89595f1a897SPoul-Henning Kamp continue; 89695f1a897SPoul-Henning Kamp c = preload_search_info(mod, MODINFO_ADDR); 89795f1a897SPoul-Henning Kamp ptr = *(u_char **)c; 89895f1a897SPoul-Henning Kamp c = preload_search_info(mod, MODINFO_SIZE); 89995f1a897SPoul-Henning Kamp len = *(unsigned *)c; 900fe603109SMaxim Sobolev printf("%s%d: Preloaded image <%s> %d bytes at %p\n", 901fe603109SMaxim Sobolev MD_NAME, mdunits, name, len, ptr); 902637f671aSPoul-Henning Kamp md_preloaded(ptr, len); 90395f1a897SPoul-Henning Kamp } 90410b0e058SDima Dorfman status_dev = make_dev(&mdctl_cdevsw, 0xffff00ff, UID_ROOT, GID_WHEEL, 90510b0e058SDima Dorfman 0600, MDCTL_NAME); 90600a6a3c6SPoul-Henning Kamp } 90700a6a3c6SPoul-Henning Kamp 90857e9624eSPoul-Henning Kamp static int 90957e9624eSPoul-Henning Kamp md_modevent(module_t mod, int type, void *data) 91057e9624eSPoul-Henning Kamp { 9119d4b5945SMaxim Sobolev int error; 9129d4b5945SMaxim Sobolev struct md_s *sc; 9139d4b5945SMaxim Sobolev 91457e9624eSPoul-Henning Kamp switch (type) { 91557e9624eSPoul-Henning Kamp case MOD_LOAD: 91657e9624eSPoul-Henning Kamp md_drvinit(NULL); 91757e9624eSPoul-Henning Kamp break; 91857e9624eSPoul-Henning Kamp case MOD_UNLOAD: 9199d4b5945SMaxim Sobolev LIST_FOREACH(sc, &md_softc_list, list) { 920b40ce416SJulian Elischer error = mddetach(sc->unit, curthread); 9219d4b5945SMaxim Sobolev if (error != 0) 9229d4b5945SMaxim Sobolev return (error); 9239d4b5945SMaxim Sobolev } 92457e9624eSPoul-Henning Kamp if (status_dev) 92557e9624eSPoul-Henning Kamp destroy_dev(status_dev); 92657e9624eSPoul-Henning Kamp status_dev = 0; 92757e9624eSPoul-Henning Kamp break; 92857e9624eSPoul-Henning Kamp default: 92957e9624eSPoul-Henning Kamp break; 93057e9624eSPoul-Henning Kamp } 9319d4b5945SMaxim Sobolev return (0); 93257e9624eSPoul-Henning Kamp } 93357e9624eSPoul-Henning Kamp 93457e9624eSPoul-Henning Kamp static moduledata_t md_mod = { 93510b0e058SDima Dorfman MD_NAME, 93657e9624eSPoul-Henning Kamp md_modevent, 93757e9624eSPoul-Henning Kamp NULL 93857e9624eSPoul-Henning Kamp }; 93957e9624eSPoul-Henning Kamp DECLARE_MODULE(md, md_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR); 94057e9624eSPoul-Henning Kamp MODULE_VERSION(md, MD_MODVER); 94157e9624eSPoul-Henning Kamp 94200a6a3c6SPoul-Henning Kamp 94371e4fff8SPoul-Henning Kamp #ifdef MD_ROOT 94471e4fff8SPoul-Henning Kamp static void 94571e4fff8SPoul-Henning Kamp md_takeroot(void *junk) 94671e4fff8SPoul-Henning Kamp { 94771e4fff8SPoul-Henning Kamp if (mdrootready) 94871e4fff8SPoul-Henning Kamp rootdevnames[0] = "ufs:/dev/md0c"; 94971e4fff8SPoul-Henning Kamp } 95071e4fff8SPoul-Henning Kamp 95171e4fff8SPoul-Henning Kamp SYSINIT(md_root, SI_SUB_MOUNT_ROOT, SI_ORDER_FIRST, md_takeroot, NULL); 95271e4fff8SPoul-Henning Kamp #endif 953