vkernel - more crit section work to avoid pthread reentrancy.
[dragonfly.git] / sys / dev / virtual / disk / vdisk.c
CommitLineData
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 58struct 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
72static void vkd_io_thread(cothread_t cotd);
73static void vkd_io_intr(cothread_t cotd);
3448c124
MD
74static void vkd_doio(struct vkd_softc *sc, struct bio *bio);
75
e1002718
MD
76static d_strategy_t vkdstrategy;
77static d_open_t vkdopen;
d87174b3 78
e1002718
MD
79static 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
88static void
e1002718 89vkdinit(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 124SYSINIT(vkdisk, SI_SUB_DRIVERS, SI_ORDER_FIRST, vkdinit, NULL);
d87174b3
MD
125
126static int
e1002718 127vkdopen(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
152static int
e1002718 153vkdstrategy(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
171static
172void
9c2ed617 173vkd_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 */
197static
198void
199vkd_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
227static
228void
229vkd_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