1 1.64 msaitoh /* $NetBSD: rumpblk.c,v 1.64 2016/07/07 06:55:44 msaitoh Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2009 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Development of this software was supported by the 7 1.1 pooka * Finnish Cultural Foundation. 8 1.1 pooka * 9 1.1 pooka * Redistribution and use in source and binary forms, with or without 10 1.1 pooka * modification, are permitted provided that the following conditions 11 1.1 pooka * are met: 12 1.1 pooka * 1. Redistributions of source code must retain the above copyright 13 1.1 pooka * notice, this list of conditions and the following disclaimer. 14 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 pooka * notice, this list of conditions and the following disclaimer in the 16 1.1 pooka * documentation and/or other materials provided with the distribution. 17 1.1 pooka * 18 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 pooka * SUCH DAMAGE. 29 1.1 pooka */ 30 1.1 pooka 31 1.1 pooka /* 32 1.1 pooka * Block device emulation. Presents a block device interface and 33 1.1 pooka * uses rumpuser system calls to satisfy I/O requests. 34 1.16 pooka * 35 1.16 pooka * We provide fault injection. The driver can be made to fail 36 1.16 pooka * I/O occasionally. 37 1.1 pooka */ 38 1.1 pooka 39 1.1 pooka #include <sys/cdefs.h> 40 1.64 msaitoh __KERNEL_RCSID(0, "$NetBSD: rumpblk.c,v 1.64 2016/07/07 06:55:44 msaitoh Exp $"); 41 1.1 pooka 42 1.1 pooka #include <sys/param.h> 43 1.1 pooka #include <sys/buf.h> 44 1.1 pooka #include <sys/conf.h> 45 1.16 pooka #include <sys/condvar.h> 46 1.1 pooka #include <sys/disklabel.h> 47 1.18 pooka #include <sys/evcnt.h> 48 1.1 pooka #include <sys/fcntl.h> 49 1.1 pooka #include <sys/kmem.h> 50 1.1 pooka #include <sys/malloc.h> 51 1.16 pooka #include <sys/queue.h> 52 1.1 pooka #include <sys/stat.h> 53 1.47 tls #include <sys/cprng.h> 54 1.1 pooka 55 1.63 pooka #include <rump-sys/kern.h> 56 1.63 pooka #include <rump-sys/vfs.h> 57 1.63 pooka 58 1.1 pooka #include <rump/rumpuser.h> 59 1.1 pooka 60 1.16 pooka #if 0 61 1.16 pooka #define DPRINTF(x) printf x 62 1.16 pooka #else 63 1.16 pooka #define DPRINTF(x) 64 1.16 pooka #endif 65 1.16 pooka 66 1.1 pooka #define RUMPBLK_SIZE 16 67 1.1 pooka static struct rblkdev { 68 1.1 pooka char *rblk_path; 69 1.1 pooka int rblk_fd; 70 1.45 pooka int rblk_mode; 71 1.50 pooka 72 1.26 pooka uint64_t rblk_size; 73 1.27 pooka uint64_t rblk_hostoffset; 74 1.41 pooka uint64_t rblk_hostsize; 75 1.27 pooka int rblk_ftype; 76 1.16 pooka 77 1.31 pooka struct disklabel rblk_label; 78 1.1 pooka } minors[RUMPBLK_SIZE]; 79 1.1 pooka 80 1.20 pooka static struct evcnt ev_io_total; 81 1.20 pooka static struct evcnt ev_io_async; 82 1.20 pooka 83 1.20 pooka static struct evcnt ev_bwrite_total; 84 1.20 pooka static struct evcnt ev_bwrite_async; 85 1.20 pooka static struct evcnt ev_bread_total; 86 1.18 pooka 87 1.1 pooka dev_type_open(rumpblk_open); 88 1.1 pooka dev_type_close(rumpblk_close); 89 1.1 pooka dev_type_read(rumpblk_read); 90 1.1 pooka dev_type_write(rumpblk_write); 91 1.1 pooka dev_type_ioctl(rumpblk_ioctl); 92 1.1 pooka dev_type_strategy(rumpblk_strategy); 93 1.3 pooka dev_type_strategy(rumpblk_strategy_fail); 94 1.1 pooka dev_type_dump(rumpblk_dump); 95 1.1 pooka dev_type_size(rumpblk_size); 96 1.1 pooka 97 1.1 pooka static const struct bdevsw rumpblk_bdevsw = { 98 1.55 dholland .d_open = rumpblk_open, 99 1.55 dholland .d_close = rumpblk_close, 100 1.55 dholland .d_strategy = rumpblk_strategy, 101 1.55 dholland .d_ioctl = rumpblk_ioctl, 102 1.55 dholland .d_dump = nodump, 103 1.55 dholland .d_psize = nosize, 104 1.56 dholland .d_discard = nodiscard, 105 1.55 dholland .d_flag = D_DISK 106 1.1 pooka }; 107 1.1 pooka 108 1.3 pooka static const struct bdevsw rumpblk_bdevsw_fail = { 109 1.55 dholland .d_open = rumpblk_open, 110 1.55 dholland .d_close = rumpblk_close, 111 1.55 dholland .d_strategy = rumpblk_strategy_fail, 112 1.55 dholland .d_ioctl = rumpblk_ioctl, 113 1.55 dholland .d_dump = nodump, 114 1.55 dholland .d_psize = nosize, 115 1.56 dholland .d_discard = nodiscard, 116 1.55 dholland .d_flag = D_DISK 117 1.3 pooka }; 118 1.3 pooka 119 1.1 pooka static const struct cdevsw rumpblk_cdevsw = { 120 1.55 dholland .d_open = rumpblk_open, 121 1.55 dholland .d_close = rumpblk_close, 122 1.55 dholland .d_read = rumpblk_read, 123 1.55 dholland .d_write = rumpblk_write, 124 1.55 dholland .d_ioctl = rumpblk_ioctl, 125 1.55 dholland .d_stop = nostop, 126 1.55 dholland .d_tty = notty, 127 1.55 dholland .d_poll = nopoll, 128 1.55 dholland .d_mmap = nommap, 129 1.55 dholland .d_kqfilter = nokqfilter, 130 1.57 dholland .d_discard = nodiscard, 131 1.55 dholland .d_flag = D_DISK 132 1.1 pooka }; 133 1.1 pooka 134 1.45 pooka static int backend_open(struct rblkdev *, const char *); 135 1.45 pooka static int backend_close(struct rblkdev *); 136 1.45 pooka 137 1.3 pooka /* fail every n out of BLKFAIL_MAX */ 138 1.3 pooka #define BLKFAIL_MAX 10000 139 1.3 pooka static int blkfail; 140 1.3 pooka static unsigned randstate; 141 1.24 pooka static kmutex_t rumpblk_lock; 142 1.37 pooka static int sectshift = DEV_BSHIFT; 143 1.1 pooka 144 1.31 pooka static void 145 1.31 pooka makedefaultlabel(struct disklabel *lp, off_t size, int part) 146 1.31 pooka { 147 1.31 pooka int i; 148 1.31 pooka 149 1.31 pooka memset(lp, 0, sizeof(*lp)); 150 1.31 pooka 151 1.31 pooka lp->d_secperunit = size; 152 1.37 pooka lp->d_secsize = 1 << sectshift; 153 1.37 pooka lp->d_nsectors = size >> sectshift; 154 1.31 pooka lp->d_ntracks = 1; 155 1.31 pooka lp->d_ncylinders = 1; 156 1.31 pooka lp->d_secpercyl = lp->d_nsectors; 157 1.31 pooka 158 1.31 pooka /* oh dear oh dear */ 159 1.31 pooka strncpy(lp->d_typename, "rumpd", sizeof(lp->d_typename)); 160 1.31 pooka strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); 161 1.31 pooka 162 1.59 christos lp->d_type = DKTYPE_RUMPD; 163 1.31 pooka lp->d_rpm = 11; 164 1.31 pooka lp->d_interleave = 1; 165 1.31 pooka lp->d_flags = 0; 166 1.31 pooka 167 1.31 pooka /* XXX: RAW_PART handling? */ 168 1.31 pooka for (i = 0; i < part; i++) { 169 1.31 pooka lp->d_partitions[i].p_fstype = FS_UNUSED; 170 1.31 pooka } 171 1.37 pooka lp->d_partitions[part].p_size = size >> sectshift; 172 1.31 pooka lp->d_npartitions = part+1; 173 1.31 pooka /* XXX: file system type? */ 174 1.31 pooka 175 1.31 pooka lp->d_magic = DISKMAGIC; 176 1.31 pooka lp->d_magic2 = DISKMAGIC; 177 1.31 pooka lp->d_checksum = 0; /* XXX */ 178 1.31 pooka } 179 1.31 pooka 180 1.1 pooka int 181 1.8 cegger rumpblk_init(void) 182 1.1 pooka { 183 1.3 pooka char buf[64]; 184 1.38 pooka devmajor_t rumpblkmaj = RUMPBLK_DEVMAJOR; 185 1.19 pooka unsigned tmp; 186 1.53 pooka int i; 187 1.3 pooka 188 1.24 pooka mutex_init(&rumpblk_lock, MUTEX_DEFAULT, IPL_NONE); 189 1.24 pooka 190 1.52 pooka if (rumpuser_getparam("RUMP_BLKFAIL", buf, sizeof(buf)) == 0) { 191 1.3 pooka blkfail = strtoul(buf, NULL, 10); 192 1.3 pooka /* fail everything */ 193 1.3 pooka if (blkfail > BLKFAIL_MAX) 194 1.3 pooka blkfail = BLKFAIL_MAX; 195 1.52 pooka if (rumpuser_getparam("RUMP_BLKFAIL_SEED", 196 1.52 pooka buf, sizeof(buf)) == 0) { 197 1.3 pooka randstate = strtoul(buf, NULL, 10); 198 1.3 pooka } else { 199 1.47 tls randstate = cprng_fast32(); 200 1.3 pooka } 201 1.22 pooka printf("rumpblk: FAULT INJECTION ACTIVE! fail %d/%d. " 202 1.22 pooka "seed %u\n", blkfail, BLKFAIL_MAX, randstate); 203 1.3 pooka } else { 204 1.3 pooka blkfail = 0; 205 1.3 pooka } 206 1.1 pooka 207 1.52 pooka if (rumpuser_getparam("RUMP_BLKSECTSHIFT", buf, sizeof(buf)) == 0) { 208 1.37 pooka printf("rumpblk: "); 209 1.37 pooka tmp = strtoul(buf, NULL, 10); 210 1.37 pooka if (tmp >= DEV_BSHIFT) 211 1.37 pooka sectshift = tmp; 212 1.37 pooka else 213 1.37 pooka printf("RUMP_BLKSECTSHIFT must be least %d (now %d), ", 214 1.64 msaitoh DEV_BSHIFT, tmp); 215 1.37 pooka printf("using %d for sector shift (size %d)\n", 216 1.37 pooka sectshift, 1<<sectshift); 217 1.37 pooka } 218 1.19 pooka 219 1.16 pooka memset(minors, 0, sizeof(minors)); 220 1.16 pooka for (i = 0; i < RUMPBLK_SIZE; i++) { 221 1.46 pooka minors[i].rblk_fd = -1; 222 1.16 pooka } 223 1.16 pooka 224 1.20 pooka evcnt_attach_dynamic(&ev_io_total, EVCNT_TYPE_MISC, NULL, 225 1.39 pooka "rumpblk", "I/O reqs"); 226 1.20 pooka evcnt_attach_dynamic(&ev_io_async, EVCNT_TYPE_MISC, NULL, 227 1.39 pooka "rumpblk", "async I/O"); 228 1.20 pooka 229 1.20 pooka evcnt_attach_dynamic(&ev_bread_total, EVCNT_TYPE_MISC, NULL, 230 1.39 pooka "rumpblk", "bytes read"); 231 1.20 pooka evcnt_attach_dynamic(&ev_bwrite_total, EVCNT_TYPE_MISC, NULL, 232 1.39 pooka "rumpblk", "bytes written"); 233 1.20 pooka evcnt_attach_dynamic(&ev_bwrite_async, EVCNT_TYPE_MISC, NULL, 234 1.39 pooka "rumpblk", "bytes written async"); 235 1.20 pooka 236 1.3 pooka if (blkfail) { 237 1.38 pooka return devsw_attach("rumpblk", 238 1.38 pooka &rumpblk_bdevsw_fail, &rumpblkmaj, 239 1.38 pooka &rumpblk_cdevsw, &rumpblkmaj); 240 1.3 pooka } else { 241 1.38 pooka return devsw_attach("rumpblk", 242 1.38 pooka &rumpblk_bdevsw, &rumpblkmaj, 243 1.38 pooka &rumpblk_cdevsw, &rumpblkmaj); 244 1.3 pooka } 245 1.1 pooka } 246 1.1 pooka 247 1.1 pooka int 248 1.27 pooka rumpblk_register(const char *path, devminor_t *dmin, 249 1.27 pooka uint64_t offset, uint64_t size) 250 1.1 pooka { 251 1.27 pooka struct rblkdev *rblk; 252 1.24 pooka uint64_t flen; 253 1.1 pooka size_t len; 254 1.30 pooka int ftype, error, i; 255 1.24 pooka 256 1.27 pooka /* devices might not report correct size unless they're open */ 257 1.54 pooka if ((error = rumpuser_getfileinfo(path, &flen, &ftype)) != 0) 258 1.27 pooka return error; 259 1.27 pooka 260 1.24 pooka /* verify host file is of supported type */ 261 1.24 pooka if (!(ftype == RUMPUSER_FT_REG 262 1.24 pooka || ftype == RUMPUSER_FT_BLK 263 1.24 pooka || ftype == RUMPUSER_FT_CHR)) 264 1.24 pooka return EINVAL; 265 1.1 pooka 266 1.24 pooka mutex_enter(&rumpblk_lock); 267 1.24 pooka for (i = 0; i < RUMPBLK_SIZE; i++) { 268 1.24 pooka if (minors[i].rblk_path&&strcmp(minors[i].rblk_path, path)==0) { 269 1.24 pooka mutex_exit(&rumpblk_lock); 270 1.24 pooka *dmin = i; 271 1.24 pooka return 0; 272 1.24 pooka } 273 1.24 pooka } 274 1.1 pooka 275 1.1 pooka for (i = 0; i < RUMPBLK_SIZE; i++) 276 1.1 pooka if (minors[i].rblk_path == NULL) 277 1.1 pooka break; 278 1.24 pooka if (i == RUMPBLK_SIZE) { 279 1.24 pooka mutex_exit(&rumpblk_lock); 280 1.24 pooka return EBUSY; 281 1.24 pooka } 282 1.1 pooka 283 1.27 pooka rblk = &minors[i]; 284 1.45 pooka rblk->rblk_path = __UNCONST("taken"); 285 1.45 pooka mutex_exit(&rumpblk_lock); 286 1.45 pooka 287 1.1 pooka len = strlen(path); 288 1.27 pooka rblk->rblk_path = malloc(len + 1, M_TEMP, M_WAITOK); 289 1.27 pooka strcpy(rblk->rblk_path, path); 290 1.27 pooka rblk->rblk_hostoffset = offset; 291 1.33 pooka if (size != RUMPBLK_SIZENOTSET) { 292 1.27 pooka KASSERT(size + offset <= flen); 293 1.27 pooka rblk->rblk_size = size; 294 1.27 pooka } else { 295 1.27 pooka KASSERT(offset < flen); 296 1.27 pooka rblk->rblk_size = flen - offset; 297 1.27 pooka } 298 1.41 pooka rblk->rblk_hostsize = flen; 299 1.27 pooka rblk->rblk_ftype = ftype; 300 1.31 pooka makedefaultlabel(&rblk->rblk_label, rblk->rblk_size, i); 301 1.45 pooka 302 1.45 pooka if ((error = backend_open(rblk, path)) != 0) { 303 1.45 pooka memset(&rblk->rblk_label, 0, sizeof(rblk->rblk_label)); 304 1.45 pooka free(rblk->rblk_path, M_TEMP); 305 1.45 pooka rblk->rblk_path = NULL; 306 1.45 pooka return error; 307 1.45 pooka } 308 1.24 pooka 309 1.24 pooka *dmin = i; 310 1.24 pooka return 0; 311 1.1 pooka } 312 1.1 pooka 313 1.40 pooka /* 314 1.40 pooka * Unregister rumpblk. It's the callers responsibility to make 315 1.40 pooka * sure it's no longer in use. 316 1.40 pooka */ 317 1.40 pooka int 318 1.40 pooka rumpblk_deregister(const char *path) 319 1.40 pooka { 320 1.40 pooka struct rblkdev *rblk; 321 1.40 pooka int i; 322 1.40 pooka 323 1.40 pooka mutex_enter(&rumpblk_lock); 324 1.40 pooka for (i = 0; i < RUMPBLK_SIZE; i++) { 325 1.40 pooka if (minors[i].rblk_path&&strcmp(minors[i].rblk_path, path)==0) { 326 1.40 pooka break; 327 1.40 pooka } 328 1.40 pooka } 329 1.40 pooka mutex_exit(&rumpblk_lock); 330 1.40 pooka 331 1.40 pooka if (i == RUMPBLK_SIZE) 332 1.40 pooka return ENOENT; 333 1.40 pooka 334 1.40 pooka rblk = &minors[i]; 335 1.45 pooka backend_close(rblk); 336 1.40 pooka 337 1.40 pooka free(rblk->rblk_path, M_TEMP); 338 1.45 pooka memset(&rblk->rblk_label, 0, sizeof(rblk->rblk_label)); 339 1.40 pooka rblk->rblk_path = NULL; 340 1.40 pooka 341 1.40 pooka return 0; 342 1.40 pooka } 343 1.40 pooka 344 1.58 pooka /* 345 1.58 pooka * Release all backend resources, to be called only when the rump 346 1.58 pooka * kernel is being shut down. 347 1.58 pooka * This routine does not do a full "fini" since we're going down anyway. 348 1.58 pooka */ 349 1.58 pooka void 350 1.58 pooka rumpblk_fini(void) 351 1.58 pooka { 352 1.58 pooka int i; 353 1.58 pooka 354 1.58 pooka for (i = 0; i < RUMPBLK_SIZE; i++) { 355 1.58 pooka struct rblkdev *rblk; 356 1.58 pooka 357 1.58 pooka rblk = &minors[i]; 358 1.58 pooka if (rblk->rblk_fd != -1) 359 1.58 pooka backend_close(rblk); 360 1.58 pooka } 361 1.58 pooka } 362 1.58 pooka 363 1.45 pooka static int 364 1.45 pooka backend_open(struct rblkdev *rblk, const char *path) 365 1.1 pooka { 366 1.1 pooka int error, fd; 367 1.1 pooka 368 1.46 pooka KASSERT(rblk->rblk_fd == -1); 369 1.54 pooka error = rumpuser_open(path, 370 1.54 pooka RUMPUSER_OPEN_RDWR | RUMPUSER_OPEN_BIO, &fd); 371 1.45 pooka if (error) { 372 1.54 pooka error = rumpuser_open(path, 373 1.54 pooka RUMPUSER_OPEN_RDONLY | RUMPUSER_OPEN_BIO, &fd); 374 1.45 pooka if (error) 375 1.45 pooka return error; 376 1.45 pooka rblk->rblk_mode = FREAD; 377 1.45 pooka } else { 378 1.45 pooka rblk->rblk_mode = FREAD|FWRITE; 379 1.1 pooka } 380 1.1 pooka 381 1.50 pooka rblk->rblk_fd = fd; 382 1.16 pooka KASSERT(rblk->rblk_fd != -1); 383 1.1 pooka return 0; 384 1.1 pooka } 385 1.1 pooka 386 1.45 pooka static int 387 1.45 pooka backend_close(struct rblkdev *rblk) 388 1.1 pooka { 389 1.1 pooka 390 1.54 pooka rumpuser_close(rblk->rblk_fd); 391 1.1 pooka rblk->rblk_fd = -1; 392 1.45 pooka 393 1.45 pooka return 0; 394 1.45 pooka } 395 1.45 pooka 396 1.45 pooka int 397 1.45 pooka rumpblk_open(dev_t dev, int flag, int fmt, struct lwp *l) 398 1.45 pooka { 399 1.45 pooka struct rblkdev *rblk = &minors[minor(dev)]; 400 1.45 pooka 401 1.45 pooka if (rblk->rblk_fd == -1) 402 1.45 pooka return ENXIO; 403 1.45 pooka 404 1.45 pooka if (((flag & (FREAD|FWRITE)) & ~rblk->rblk_mode) != 0) { 405 1.45 pooka return EACCES; 406 1.45 pooka } 407 1.45 pooka 408 1.45 pooka return 0; 409 1.45 pooka } 410 1.45 pooka 411 1.45 pooka int 412 1.45 pooka rumpblk_close(dev_t dev, int flag, int fmt, struct lwp *l) 413 1.45 pooka { 414 1.1 pooka 415 1.1 pooka return 0; 416 1.1 pooka } 417 1.1 pooka 418 1.1 pooka int 419 1.1 pooka rumpblk_ioctl(dev_t dev, u_long xfer, void *addr, int flag, struct lwp *l) 420 1.1 pooka { 421 1.31 pooka devminor_t dmin = minor(dev); 422 1.31 pooka struct rblkdev *rblk = &minors[dmin]; 423 1.31 pooka struct partinfo *pi; 424 1.62 christos struct partition *dp; 425 1.31 pooka int error = 0; 426 1.31 pooka 427 1.31 pooka /* well, me should support a few more, but we don't for now */ 428 1.31 pooka switch (xfer) { 429 1.31 pooka case DIOCGDINFO: 430 1.31 pooka *(struct disklabel *)addr = rblk->rblk_label; 431 1.31 pooka break; 432 1.31 pooka 433 1.61 christos case DIOCGPARTINFO: 434 1.61 christos dp = &rblk->rblk_label.d_partitions[DISKPART(dmin)]; 435 1.31 pooka pi = addr; 436 1.61 christos pi->pi_offset = dp->p_offset; 437 1.61 christos pi->pi_size = dp->p_size; 438 1.61 christos pi->pi_secsize = rblk->rblk_label.d_secsize; 439 1.61 christos pi->pi_bsize = BLKDEV_IOSIZE; 440 1.61 christos pi->pi_fstype = dp->p_fstype; 441 1.61 christos pi->pi_fsize = dp->p_fsize; 442 1.61 christos pi->pi_frag = dp->p_frag; 443 1.61 christos pi->pi_cpg = dp->p_cpg; 444 1.31 pooka break; 445 1.32 pooka 446 1.32 pooka /* it's synced enough along the write path */ 447 1.32 pooka case DIOCCACHESYNC: 448 1.32 pooka break; 449 1.32 pooka 450 1.60 pooka case DIOCGMEDIASIZE: 451 1.60 pooka *(off_t *)addr = (off_t)rblk->rblk_size; 452 1.60 pooka break; 453 1.60 pooka 454 1.31 pooka default: 455 1.31 pooka error = ENOTTY; 456 1.31 pooka break; 457 1.1 pooka } 458 1.1 pooka 459 1.31 pooka return error; 460 1.1 pooka } 461 1.1 pooka 462 1.25 pooka static int 463 1.25 pooka do_physio(dev_t dev, struct uio *uio, int which) 464 1.25 pooka { 465 1.25 pooka void (*strat)(struct buf *); 466 1.25 pooka 467 1.25 pooka if (blkfail) 468 1.25 pooka strat = rumpblk_strategy_fail; 469 1.25 pooka else 470 1.25 pooka strat = rumpblk_strategy; 471 1.25 pooka 472 1.25 pooka return physio(strat, NULL, dev, which, minphys, uio); 473 1.25 pooka } 474 1.25 pooka 475 1.1 pooka int 476 1.1 pooka rumpblk_read(dev_t dev, struct uio *uio, int flags) 477 1.1 pooka { 478 1.1 pooka 479 1.25 pooka return do_physio(dev, uio, B_READ); 480 1.1 pooka } 481 1.1 pooka 482 1.1 pooka int 483 1.1 pooka rumpblk_write(dev_t dev, struct uio *uio, int flags) 484 1.1 pooka { 485 1.1 pooka 486 1.25 pooka return do_physio(dev, uio, B_WRITE); 487 1.1 pooka } 488 1.1 pooka 489 1.3 pooka static void 490 1.3 pooka dostrategy(struct buf *bp) 491 1.1 pooka { 492 1.1 pooka struct rblkdev *rblk = &minors[minor(bp->b_dev)]; 493 1.1 pooka off_t off; 494 1.21 pooka int async = bp->b_flags & B_ASYNC; 495 1.50 pooka int op; 496 1.1 pooka 497 1.44 pooka if (bp->b_bcount % (1<<sectshift) != 0) { 498 1.44 pooka rump_biodone(bp, 0, EINVAL); 499 1.44 pooka return; 500 1.44 pooka } 501 1.44 pooka 502 1.20 pooka /* collect statistics */ 503 1.20 pooka ev_io_total.ev_count++; 504 1.20 pooka if (async) 505 1.20 pooka ev_io_async.ev_count++; 506 1.20 pooka if (BUF_ISWRITE(bp)) { 507 1.20 pooka ev_bwrite_total.ev_count += bp->b_bcount; 508 1.20 pooka if (async) 509 1.20 pooka ev_bwrite_async.ev_count += bp->b_bcount; 510 1.20 pooka } else { 511 1.20 pooka ev_bread_total.ev_count++; 512 1.20 pooka } 513 1.20 pooka 514 1.44 pooka /* 515 1.44 pooka * b_blkno is always in terms of DEV_BSIZE, and since we need 516 1.44 pooka * to translate to a byte offset for the host read, this 517 1.44 pooka * calculation does not need sectshift. 518 1.44 pooka */ 519 1.44 pooka off = bp->b_blkno << DEV_BSHIFT; 520 1.44 pooka 521 1.11 pooka /* 522 1.11 pooka * Do bounds checking if we're working on a file. Otherwise 523 1.11 pooka * invalid file systems might attempt to read beyond EOF. This 524 1.11 pooka * is bad(tm) especially on mmapped images. This is essentially 525 1.11 pooka * the kernel bounds_check() routines. 526 1.11 pooka */ 527 1.27 pooka if (off + bp->b_bcount > rblk->rblk_size) { 528 1.11 pooka int64_t sz = rblk->rblk_size - off; 529 1.11 pooka 530 1.11 pooka /* EOF */ 531 1.11 pooka if (sz == 0) { 532 1.11 pooka rump_biodone(bp, 0, 0); 533 1.11 pooka return; 534 1.11 pooka } 535 1.11 pooka /* beyond EOF ==> error */ 536 1.11 pooka if (sz < 0) { 537 1.11 pooka rump_biodone(bp, 0, EINVAL); 538 1.11 pooka return; 539 1.11 pooka } 540 1.11 pooka 541 1.11 pooka /* truncate to device size */ 542 1.11 pooka bp->b_bcount = sz; 543 1.11 pooka } 544 1.11 pooka 545 1.34 pooka off += rblk->rblk_hostoffset; 546 1.1 pooka DPRINTF(("rumpblk_strategy: 0x%x bytes %s off 0x%" PRIx64 547 1.20 pooka " (0x%" PRIx64 " - 0x%" PRIx64 "), %ssync\n", 548 1.16 pooka bp->b_bcount, BUF_ISREAD(bp) ? "READ" : "WRITE", 549 1.20 pooka off, off, (off + bp->b_bcount), async ? "a" : "")); 550 1.1 pooka 551 1.50 pooka op = BUF_ISREAD(bp) ? RUMPUSER_BIO_READ : RUMPUSER_BIO_WRITE; 552 1.50 pooka if (BUF_ISWRITE(bp) && !async) 553 1.50 pooka op |= RUMPUSER_BIO_SYNC; 554 1.49 pooka 555 1.50 pooka rumpuser_bio(rblk->rblk_fd, op, bp->b_data, bp->b_bcount, off, 556 1.50 pooka rump_biodone, bp); 557 1.1 pooka } 558 1.3 pooka 559 1.3 pooka void 560 1.3 pooka rumpblk_strategy(struct buf *bp) 561 1.3 pooka { 562 1.3 pooka 563 1.3 pooka dostrategy(bp); 564 1.3 pooka } 565 1.3 pooka 566 1.3 pooka /* 567 1.4 pooka * Simple random number generator. This is private so that we can 568 1.4 pooka * very repeatedly control which blocks will fail. 569 1.4 pooka * 570 1.3 pooka * <mlelstv> pooka, rand() 571 1.3 pooka * <mlelstv> [paste] 572 1.3 pooka */ 573 1.3 pooka static unsigned 574 1.3 pooka gimmerand(void) 575 1.3 pooka { 576 1.3 pooka 577 1.3 pooka return (randstate = randstate * 1103515245 + 12345) % (0x80000000L); 578 1.3 pooka } 579 1.3 pooka 580 1.3 pooka /* 581 1.3 pooka * Block device with very simple fault injection. Fails every 582 1.3 pooka * n out of BLKFAIL_MAX I/O with EIO. n is determined by the env 583 1.3 pooka * variable RUMP_BLKFAIL. 584 1.3 pooka */ 585 1.3 pooka void 586 1.3 pooka rumpblk_strategy_fail(struct buf *bp) 587 1.3 pooka { 588 1.3 pooka 589 1.3 pooka if (gimmerand() % BLKFAIL_MAX >= blkfail) { 590 1.3 pooka dostrategy(bp); 591 1.3 pooka } else { 592 1.3 pooka printf("block fault injection: failing I/O on block %lld\n", 593 1.3 pooka (long long)bp->b_blkno); 594 1.3 pooka bp->b_error = EIO; 595 1.3 pooka biodone(bp); 596 1.3 pooka } 597 1.3 pooka } 598