| Commit | Line | Data |
|---|---|---|
| d87174b3 MD |
1 | /* |
| 2 | * Copyright (c) 2006 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@backplane.com> | |
| 6 | * | |
| 7 | * Redistribution and use in source and binary forms, with or without | |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| 10 | * | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in | |
| 15 | * the documentation and/or other materials provided with the | |
| 16 | * distribution. | |
| 17 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 18 | * contributors may be used to endorse or promote products derived | |
| 19 | * from this software without specific, prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 26 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 32 | * SUCH DAMAGE. | |
| 33 | * | |
| 9c2ed617 | 34 | * $DragonFly: src/sys/dev/virtual/disk/vdisk.c,v 1.8 2008/03/20 02:14:56 dillon Exp $ |
| d87174b3 MD |
35 | */ |
| 36 | ||
| 37 | /* | |
| 38 | * Virtual disk driver | |
| 39 | */ | |
| 40 | #include <sys/types.h> | |
| 41 | #include <sys/param.h> | |
| 42 | #include <sys/systm.h> | |
| 43 | #include <sys/kernel.h> | |
| 44 | #include <sys/malloc.h> | |
| 45 | #include <sys/conf.h> | |
| 3448c124 | 46 | #include <sys/bus.h> |
| d87174b3 MD |
47 | #include <sys/buf.h> |
| 48 | #include <sys/devicestat.h> | |
| d87174b3 | 49 | #include <sys/disk.h> |
| 9c2ed617 | 50 | #include <machine/cothread.h> |
| d87174b3 MD |
51 | #include <machine/md_var.h> |
| 52 | ||
| 53 | #include <sys/buf2.h> | |
| 54 | ||
| 55 | #include <sys/stat.h> | |
| 56 | #include <unistd.h> | |
| 57 | ||
| e1002718 | 58 | struct vkd_softc { |
| d87174b3 MD |
59 | struct bio_queue_head bio_queue; |
| 60 | struct devstat stats; | |
| 61 | struct disk disk; | |
| 9c2ed617 MD |
62 | cothread_t cotd; |
| 63 | TAILQ_HEAD(, bio) cotd_queue; | |
| 64 | TAILQ_HEAD(, bio) cotd_done; | |
| d87174b3 MD |
65 | cdev_t dev; |
| 66 | int unit; | |
| 67 | int fd; | |
| 68 | }; | |
| 69 | ||
| d87174b3 MD |
70 | #define CDEV_MAJOR 97 |
| 71 | ||
| 9c2ed617 MD |
72 | static void vkd_io_thread(cothread_t cotd); |
| 73 | static void vkd_io_intr(cothread_t cotd); | |
| 3448c124 MD |
74 | static void vkd_doio(struct vkd_softc *sc, struct bio *bio); |
| 75 | ||
| e1002718 MD |
76 | static d_strategy_t vkdstrategy; |
| 77 | static d_open_t vkdopen; | |
| d87174b3 | 78 | |
| e1002718 MD |
79 | static struct dev_ops vkd_ops = { |
| 80 | { "vkd", CDEV_MAJOR, D_DISK }, | |
| 81 | .d_open = vkdopen, | |
| d87174b3 MD |
82 | .d_close = nullclose, |
| 83 | .d_read = physread, | |
| 84 | .d_write = physwrite, | |
| e1002718 | 85 | .d_strategy = vkdstrategy, |
| d87174b3 MD |
86 | }; |
| 87 | ||
| 88 | static void | |
| e1002718 | 89 | vkdinit(void *dummy __unused) |
| d87174b3 | 90 | { |
| ee63ee00 | 91 | struct vkdisk_info *dsk; |
| e1002718 | 92 | struct vkd_softc *sc; |
| d87174b3 | 93 | struct stat st; |
| ee63ee00 SW |
94 | int i; |
| 95 | ||
| ee63ee00 | 96 | for (i = 0; i < DiskNum; i++) { |
| ee63ee00 SW |
97 | /* check that the 'bus device' has been initialized */ |
| 98 | dsk = &DiskInfo[i]; | |
| a72d8a9f | 99 | if (dsk == NULL || dsk->type != VKD_DISK) |
| ee63ee00 SW |
100 | continue; |
| 101 | if (dsk->fd < 0 || fstat(dsk->fd, &st) < 0) | |
| 102 | continue; | |
| 103 | ||
| 104 | /* and create a new device */ | |
| 105 | sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); | |
| 106 | sc->unit = dsk->unit; | |
| 107 | sc->fd = dsk->fd; | |
| 108 | bioq_init(&sc->bio_queue); | |
| 109 | devstat_add_entry(&sc->stats, "vkd", sc->unit, DEV_BSIZE, | |
| 110 | DEVSTAT_NO_ORDERED_TAGS, | |
| 111 | DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, | |
| 112 | DEVSTAT_PRIORITY_DISK); | |
| a688b15c | 113 | sc->dev = disk_create(sc->unit, &sc->disk, &vkd_ops); |
| ee63ee00 SW |
114 | sc->dev->si_drv1 = sc; |
| 115 | sc->dev->si_iosize_max = 256 * 1024; | |
| 9c2ed617 MD |
116 | |
| 117 | TAILQ_INIT(&sc->cotd_queue); | |
| 118 | TAILQ_INIT(&sc->cotd_done); | |
| 119 | sc->cotd = cothread_create(vkd_io_thread, vkd_io_intr, sc, | |
| 120 | "vkd"); | |
| ee63ee00 | 121 | } |
| d87174b3 MD |
122 | } |
| 123 | ||
| e1002718 | 124 | SYSINIT(vkdisk, SI_SUB_DRIVERS, SI_ORDER_FIRST, vkdinit, NULL); |
| d87174b3 MD |
125 | |
| 126 | static int | |
| e1002718 | 127 | vkdopen(struct dev_open_args *ap) |
| d87174b3 | 128 | { |
| e1002718 | 129 | struct vkd_softc *sc; |
| a688b15c | 130 | struct disk_info info; |
| d87174b3 MD |
131 | struct stat st; |
| 132 | cdev_t dev; | |
| 133 | ||
| 134 | dev = ap->a_head.a_dev; | |
| 135 | sc = dev->si_drv1; | |
| d87174b3 MD |
136 | if (fstat(sc->fd, &st) < 0 || st.st_size == 0) |
| 137 | return(ENXIO); | |
| 138 | ||
| a688b15c MD |
139 | bzero(&info, sizeof(info)); |
| 140 | info.d_media_blksize = DEV_BSIZE; | |
| 141 | info.d_media_blocks = st.st_size / info.d_media_blksize; | |
| 142 | ||
| 143 | info.d_nheads = 1; | |
| 144 | info.d_ncylinders = 1; | |
| 145 | info.d_secpertrack = info.d_media_blocks; | |
| 146 | info.d_secpercyl = info.d_secpertrack * info.d_nheads; | |
| 147 | ||
| 148 | disk_setdiskinfo(&sc->disk, &info); | |
| d87174b3 MD |
149 | return(0); |
| 150 | } | |
| 151 | ||
| 152 | static int | |
| e1002718 | 153 | vkdstrategy(struct dev_strategy_args *ap) |
| d87174b3 MD |
154 | { |
| 155 | struct bio *bio = ap->a_bio; | |
| e1002718 | 156 | struct vkd_softc *sc; |
| d87174b3 | 157 | cdev_t dev; |
| d87174b3 MD |
158 | |
| 159 | dev = ap->a_head.a_dev; | |
| 160 | sc = dev->si_drv1; | |
| 161 | ||
| 9c2ed617 | 162 | devstat_start_transaction(&sc->stats); |
| 94131955 | 163 | cothread_lock(sc->cotd, 0); |
| 9c2ed617 MD |
164 | TAILQ_INSERT_TAIL(&sc->cotd_queue, bio, bio_act); |
| 165 | cothread_signal(sc->cotd); | |
| 94131955 | 166 | cothread_unlock(sc->cotd, 0); |
| 9c2ed617 | 167 | |
| d87174b3 MD |
168 | return(0); |
| 169 | } | |
| 170 | ||
| 3448c124 MD |
171 | static |
| 172 | void | |
| 9c2ed617 | 173 | vkd_io_intr(cothread_t cotd) |
| 3448c124 | 174 | { |
| 3448c124 | 175 | struct vkd_softc *sc; |
| 9c2ed617 MD |
176 | struct bio *bio; |
| 177 | ||
| 178 | sc = cotd->arg; | |
| 3448c124 | 179 | |
| 94131955 | 180 | cothread_lock(cotd, 0); |
| 9c2ed617 MD |
181 | while (!TAILQ_EMPTY(&sc->cotd_done)) { |
| 182 | bio = TAILQ_FIRST(&sc->cotd_done); | |
| 183 | TAILQ_REMOVE(&sc->cotd_done, bio, bio_act); | |
| 184 | devstat_end_transaction_buf(&sc->stats, bio->bio_buf); | |
| 185 | biodone(bio); | |
| 186 | } | |
| 94131955 | 187 | cothread_unlock(sc->cotd, 0); |
| 9c2ed617 | 188 | } |
| 3448c124 | 189 | |
| 9c2ed617 MD |
190 | /* |
| 191 | * WARNING! This runs as a cothread and has no access to mycpu nor can it | |
| 192 | * make vkernel-specific calls other then cothread_*() calls. | |
| 65905e94 MD |
193 | * |
| 194 | * WARNING! A signal can occur and be discarded prior to our initial | |
| 195 | * call to cothread_lock(). Process pending I/O before waiting. | |
| 9c2ed617 MD |
196 | */ |
| 197 | static | |
| 198 | void | |
| 199 | vkd_io_thread(cothread_t cotd) | |
| 200 | { | |
| 201 | struct bio *bio; | |
| 202 | struct vkd_softc *sc = cotd->arg; | |
| 203 | int count; | |
| 3448c124 | 204 | |
| 94131955 | 205 | cothread_lock(cotd, 1); |
| 3448c124 | 206 | for (;;) { |
| 9c2ed617 MD |
207 | count = 0; |
| 208 | while ((bio = TAILQ_FIRST(&sc->cotd_queue)) != NULL) { | |
| 209 | TAILQ_REMOVE(&sc->cotd_queue, bio, bio_act); | |
| 94131955 | 210 | cothread_unlock(cotd, 1); |
| 3448c124 | 211 | vkd_doio(sc, bio); |
| 94131955 | 212 | cothread_lock(cotd, 1); |
| 9c2ed617 MD |
213 | TAILQ_INSERT_TAIL(&sc->cotd_done, bio, bio_act); |
| 214 | if (++count == 8) { | |
| 215 | cothread_intr(cotd); | |
| 216 | count = 0; | |
| 217 | } | |
| 3448c124 | 218 | } |
| 9c2ed617 MD |
219 | if (count) |
| 220 | cothread_intr(cotd); | |
| 65905e94 | 221 | cothread_wait(cotd); /* interlocks cothread lock */ |
| 3448c124 | 222 | } |
| 9c2ed617 | 223 | /* NOT REACHED */ |
| 94131955 | 224 | cothread_unlock(cotd, 1); |
| 3448c124 MD |
225 | } |
| 226 | ||
| 227 | static | |
| 228 | void | |
| 229 | vkd_doio(struct vkd_softc *sc, struct bio *bio) | |
| 230 | { | |
| 231 | struct buf *bp = bio->bio_buf; | |
| 232 | int n; | |
| 233 | ||
| 3448c124 MD |
234 | switch(bp->b_cmd) { |
| 235 | case BUF_CMD_READ: | |
| 236 | n = pread(sc->fd, bp->b_data, bp->b_bcount, bio->bio_offset); | |
| 237 | break; | |
| 238 | case BUF_CMD_WRITE: | |
| 239 | /* XXX HANDLE SHORT WRITE XXX */ | |
| 240 | n = pwrite(sc->fd, bp->b_data, bp->b_bcount, bio->bio_offset); | |
| 241 | break; | |
| 8c9c78e2 MD |
242 | case BUF_CMD_FLUSH: |
| 243 | if (fsync(sc->fd) < 0) | |
| 244 | n = -1; | |
| 245 | else | |
| 246 | n = bp->b_bcount; | |
| 247 | break; | |
| 3448c124 MD |
248 | default: |
| 249 | panic("vkd: bad b_cmd %d", bp->b_cmd); | |
| 250 | break; /* not reached */ | |
| 251 | } | |
| 252 | if (n != bp->b_bcount) { | |
| 253 | bp->b_error = EIO; | |
| 254 | bp->b_flags |= B_ERROR; | |
| 255 | } | |
| 3448c124 | 256 | bp->b_resid = bp->b_bcount - n; |
| 3448c124 MD |
257 | } |
| 258 |