]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/block_if.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / block_if.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2013  Peter Grehan <grehan@freebsd.org>
5  * All rights reserved.
6  * Copyright 2020 Joyent, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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 the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #ifndef WITHOUT_CAPSICUM
37 #include <sys/capsicum.h>
38 #endif
39 #include <sys/queue.h>
40 #include <sys/errno.h>
41 #include <sys/stat.h>
42 #include <sys/ioctl.h>
43 #include <sys/disk.h>
44
45 #include <assert.h>
46 #ifndef WITHOUT_CAPSICUM
47 #include <capsicum_helpers.h>
48 #endif
49 #include <err.h>
50 #include <fcntl.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <pthread.h>
55 #include <pthread_np.h>
56 #include <signal.h>
57 #include <sysexits.h>
58 #include <unistd.h>
59
60 #include <machine/atomic.h>
61 #include <machine/vmm_snapshot.h>
62
63 #include "bhyverun.h"
64 #include "debug.h"
65 #include "mevent.h"
66 #include "block_if.h"
67
68 #define BLOCKIF_SIG     0xb109b109
69
70 #define BLOCKIF_NUMTHR  8
71 #define BLOCKIF_MAXREQ  (BLOCKIF_RING_MAX + BLOCKIF_NUMTHR)
72
73 enum blockop {
74         BOP_READ,
75         BOP_WRITE,
76         BOP_FLUSH,
77         BOP_DELETE
78 };
79
80 enum blockstat {
81         BST_FREE,
82         BST_BLOCK,
83         BST_PEND,
84         BST_BUSY,
85         BST_DONE
86 };
87
88 struct blockif_elem {
89         TAILQ_ENTRY(blockif_elem) be_link;
90         struct blockif_req  *be_req;
91         enum blockop         be_op;
92         enum blockstat       be_status;
93         pthread_t            be_tid;
94         off_t                be_block;
95 };
96
97 struct blockif_ctxt {
98         int                     bc_magic;
99         int                     bc_fd;
100         int                     bc_ischr;
101         int                     bc_isgeom;
102         int                     bc_candelete;
103         int                     bc_rdonly;
104         off_t                   bc_size;
105         int                     bc_sectsz;
106         int                     bc_psectsz;
107         int                     bc_psectoff;
108         int                     bc_closing;
109         int                     bc_paused;
110         int                     bc_work_count;
111         pthread_t               bc_btid[BLOCKIF_NUMTHR];
112         pthread_mutex_t         bc_mtx;
113         pthread_cond_t          bc_cond;
114         pthread_cond_t          bc_paused_cond;
115         pthread_cond_t          bc_work_done_cond;
116
117         /* Request elements and free/pending/busy queues */
118         TAILQ_HEAD(, blockif_elem) bc_freeq;       
119         TAILQ_HEAD(, blockif_elem) bc_pendq;
120         TAILQ_HEAD(, blockif_elem) bc_busyq;
121         struct blockif_elem     bc_reqs[BLOCKIF_MAXREQ];
122 };
123
124 static pthread_once_t blockif_once = PTHREAD_ONCE_INIT;
125
126 struct blockif_sig_elem {
127         pthread_mutex_t                 bse_mtx;
128         pthread_cond_t                  bse_cond;
129         int                             bse_pending;
130         struct blockif_sig_elem         *bse_next;
131 };
132
133 static struct blockif_sig_elem *blockif_bse_head;
134
135 static int
136 blockif_enqueue(struct blockif_ctxt *bc, struct blockif_req *breq,
137                 enum blockop op)
138 {
139         struct blockif_elem *be, *tbe;
140         off_t off;
141         int i;
142
143         be = TAILQ_FIRST(&bc->bc_freeq);
144         assert(be != NULL);
145         assert(be->be_status == BST_FREE);
146         TAILQ_REMOVE(&bc->bc_freeq, be, be_link);
147         be->be_req = breq;
148         be->be_op = op;
149         switch (op) {
150         case BOP_READ:
151         case BOP_WRITE:
152         case BOP_DELETE:
153                 off = breq->br_offset;
154                 for (i = 0; i < breq->br_iovcnt; i++)
155                         off += breq->br_iov[i].iov_len;
156                 break;
157         default:
158                 off = OFF_MAX;
159         }
160         be->be_block = off;
161         TAILQ_FOREACH(tbe, &bc->bc_pendq, be_link) {
162                 if (tbe->be_block == breq->br_offset)
163                         break;
164         }
165         if (tbe == NULL) {
166                 TAILQ_FOREACH(tbe, &bc->bc_busyq, be_link) {
167                         if (tbe->be_block == breq->br_offset)
168                                 break;
169                 }
170         }
171         if (tbe == NULL)
172                 be->be_status = BST_PEND;
173         else
174                 be->be_status = BST_BLOCK;
175         TAILQ_INSERT_TAIL(&bc->bc_pendq, be, be_link);
176         return (be->be_status == BST_PEND);
177 }
178
179 static int
180 blockif_dequeue(struct blockif_ctxt *bc, pthread_t t, struct blockif_elem **bep)
181 {
182         struct blockif_elem *be;
183
184         TAILQ_FOREACH(be, &bc->bc_pendq, be_link) {
185                 if (be->be_status == BST_PEND)
186                         break;
187                 assert(be->be_status == BST_BLOCK);
188         }
189         if (be == NULL)
190                 return (0);
191         TAILQ_REMOVE(&bc->bc_pendq, be, be_link);
192         be->be_status = BST_BUSY;
193         be->be_tid = t;
194         TAILQ_INSERT_TAIL(&bc->bc_busyq, be, be_link);
195         *bep = be;
196         return (1);
197 }
198
199 static void
200 blockif_complete(struct blockif_ctxt *bc, struct blockif_elem *be)
201 {
202         struct blockif_elem *tbe;
203
204         if (be->be_status == BST_DONE || be->be_status == BST_BUSY)
205                 TAILQ_REMOVE(&bc->bc_busyq, be, be_link);
206         else
207                 TAILQ_REMOVE(&bc->bc_pendq, be, be_link);
208         TAILQ_FOREACH(tbe, &bc->bc_pendq, be_link) {
209                 if (tbe->be_req->br_offset == be->be_block)
210                         tbe->be_status = BST_PEND;
211         }
212         be->be_tid = 0;
213         be->be_status = BST_FREE;
214         be->be_req = NULL;
215         TAILQ_INSERT_TAIL(&bc->bc_freeq, be, be_link);
216 }
217
218 static int
219 blockif_flush_bc(struct blockif_ctxt *bc)
220 {
221         if (bc->bc_ischr) {
222                 if (ioctl(bc->bc_fd, DIOCGFLUSH))
223                         return (errno);
224         } else if (fsync(bc->bc_fd))
225                 return (errno);
226
227         return (0);
228 }
229
230 static void
231 blockif_proc(struct blockif_ctxt *bc, struct blockif_elem *be, uint8_t *buf)
232 {
233         struct blockif_req *br;
234         off_t arg[2];
235         ssize_t clen, len, off, boff, voff;
236         int i, err;
237
238         br = be->be_req;
239         if (br->br_iovcnt <= 1)
240                 buf = NULL;
241         err = 0;
242         switch (be->be_op) {
243         case BOP_READ:
244                 if (buf == NULL) {
245                         if ((len = preadv(bc->bc_fd, br->br_iov, br->br_iovcnt,
246                                    br->br_offset)) < 0)
247                                 err = errno;
248                         else
249                                 br->br_resid -= len;
250                         break;
251                 }
252                 i = 0;
253                 off = voff = 0;
254                 while (br->br_resid > 0) {
255                         len = MIN(br->br_resid, MAXPHYS);
256                         if (pread(bc->bc_fd, buf, len, br->br_offset +
257                             off) < 0) {
258                                 err = errno;
259                                 break;
260                         }
261                         boff = 0;
262                         do {
263                                 clen = MIN(len - boff, br->br_iov[i].iov_len -
264                                     voff);
265                                 memcpy(br->br_iov[i].iov_base + voff,
266                                     buf + boff, clen);
267                                 if (clen < br->br_iov[i].iov_len - voff)
268                                         voff += clen;
269                                 else {
270                                         i++;
271                                         voff = 0;
272                                 }
273                                 boff += clen;
274                         } while (boff < len);
275                         off += len;
276                         br->br_resid -= len;
277                 }
278                 break;
279         case BOP_WRITE:
280                 if (bc->bc_rdonly) {
281                         err = EROFS;
282                         break;
283                 }
284                 if (buf == NULL) {
285                         if ((len = pwritev(bc->bc_fd, br->br_iov, br->br_iovcnt,
286                                     br->br_offset)) < 0)
287                                 err = errno;
288                         else
289                                 br->br_resid -= len;
290                         break;
291                 }
292                 i = 0;
293                 off = voff = 0;
294                 while (br->br_resid > 0) {
295                         len = MIN(br->br_resid, MAXPHYS);
296                         boff = 0;
297                         do {
298                                 clen = MIN(len - boff, br->br_iov[i].iov_len -
299                                     voff);
300                                 memcpy(buf + boff,
301                                     br->br_iov[i].iov_base + voff, clen);
302                                 if (clen < br->br_iov[i].iov_len - voff)
303                                         voff += clen;
304                                 else {
305                                         i++;
306                                         voff = 0;
307                                 }
308                                 boff += clen;
309                         } while (boff < len);
310                         if (pwrite(bc->bc_fd, buf, len, br->br_offset +
311                             off) < 0) {
312                                 err = errno;
313                                 break;
314                         }
315                         off += len;
316                         br->br_resid -= len;
317                 }
318                 break;
319         case BOP_FLUSH:
320                 err = blockif_flush_bc(bc);
321                 break;
322         case BOP_DELETE:
323                 if (!bc->bc_candelete)
324                         err = EOPNOTSUPP;
325                 else if (bc->bc_rdonly)
326                         err = EROFS;
327                 else if (bc->bc_ischr) {
328                         arg[0] = br->br_offset;
329                         arg[1] = br->br_resid;
330                         if (ioctl(bc->bc_fd, DIOCGDELETE, arg))
331                                 err = errno;
332                         else
333                                 br->br_resid = 0;
334                 } else
335                         err = EOPNOTSUPP;
336                 break;
337         default:
338                 err = EINVAL;
339                 break;
340         }
341
342         be->be_status = BST_DONE;
343
344         (*br->br_callback)(br, err);
345 }
346
347 static void *
348 blockif_thr(void *arg)
349 {
350         struct blockif_ctxt *bc;
351         struct blockif_elem *be;
352         pthread_t t;
353         uint8_t *buf;
354
355         bc = arg;
356         if (bc->bc_isgeom)
357                 buf = malloc(MAXPHYS);
358         else
359                 buf = NULL;
360         t = pthread_self();
361
362         pthread_mutex_lock(&bc->bc_mtx);
363         for (;;) {
364                 bc->bc_work_count++;
365
366                 /* We cannot process work if the interface is paused */
367                 while (!bc->bc_paused && blockif_dequeue(bc, t, &be)) {
368                         pthread_mutex_unlock(&bc->bc_mtx);
369                         blockif_proc(bc, be, buf);
370                         pthread_mutex_lock(&bc->bc_mtx);
371                         blockif_complete(bc, be);
372                 }
373
374                 bc->bc_work_count--;
375
376                 /* If none of the workers are busy, notify the main thread */
377                 if (bc->bc_work_count == 0)
378                         pthread_cond_broadcast(&bc->bc_work_done_cond);
379
380                 /* Check ctxt status here to see if exit requested */
381                 if (bc->bc_closing)
382                         break;
383
384                 /* Make all worker threads wait here if the device is paused */
385                 while (bc->bc_paused)
386                         pthread_cond_wait(&bc->bc_paused_cond, &bc->bc_mtx);
387
388                 pthread_cond_wait(&bc->bc_cond, &bc->bc_mtx);
389         }
390         pthread_mutex_unlock(&bc->bc_mtx);
391
392         if (buf)
393                 free(buf);
394         pthread_exit(NULL);
395         return (NULL);
396 }
397
398 static void
399 blockif_sigcont_handler(int signal, enum ev_type type, void *arg)
400 {
401         struct blockif_sig_elem *bse;
402
403         for (;;) {
404                 /*
405                  * Process the entire list even if not intended for
406                  * this thread.
407                  */
408                 do {
409                         bse = blockif_bse_head;
410                         if (bse == NULL)
411                                 return;
412                 } while (!atomic_cmpset_ptr((uintptr_t *)&blockif_bse_head,
413                                             (uintptr_t)bse,
414                                             (uintptr_t)bse->bse_next));
415
416                 pthread_mutex_lock(&bse->bse_mtx);
417                 bse->bse_pending = 0;
418                 pthread_cond_signal(&bse->bse_cond);
419                 pthread_mutex_unlock(&bse->bse_mtx);
420         }
421 }
422
423 static void
424 blockif_init(void)
425 {
426         mevent_add(SIGCONT, EVF_SIGNAL, blockif_sigcont_handler, NULL);
427         (void) signal(SIGCONT, SIG_IGN);
428 }
429
430 struct blockif_ctxt *
431 blockif_open(const char *optstr, const char *ident)
432 {
433         char tname[MAXCOMLEN + 1];
434         char name[MAXPATHLEN];
435         char *nopt, *xopts, *cp;
436         struct blockif_ctxt *bc;
437         struct stat sbuf;
438         struct diocgattr_arg arg;
439         off_t size, psectsz, psectoff;
440         int extra, fd, i, sectsz;
441         int nocache, sync, ro, candelete, geom, ssopt, pssopt;
442         int nodelete;
443
444 #ifndef WITHOUT_CAPSICUM
445         cap_rights_t rights;
446         cap_ioctl_t cmds[] = { DIOCGFLUSH, DIOCGDELETE };
447 #endif
448
449         pthread_once(&blockif_once, blockif_init);
450
451         fd = -1;
452         ssopt = 0;
453         nocache = 0;
454         sync = 0;
455         ro = 0;
456         nodelete = 0;
457
458         /*
459          * The first element in the optstring is always a pathname.
460          * Optional elements follow
461          */
462         nopt = xopts = strdup(optstr);
463         while (xopts != NULL) {
464                 cp = strsep(&xopts, ",");
465                 if (cp == nopt)         /* file or device pathname */
466                         continue;
467                 else if (!strcmp(cp, "nocache"))
468                         nocache = 1;
469                 else if (!strcmp(cp, "nodelete"))
470                         nodelete = 1;
471                 else if (!strcmp(cp, "sync") || !strcmp(cp, "direct"))
472                         sync = 1;
473                 else if (!strcmp(cp, "ro"))
474                         ro = 1;
475                 else if (sscanf(cp, "sectorsize=%d/%d", &ssopt, &pssopt) == 2)
476                         ;
477                 else if (sscanf(cp, "sectorsize=%d", &ssopt) == 1)
478                         pssopt = ssopt;
479                 else {
480                         EPRINTLN("Invalid device option \"%s\"", cp);
481                         goto err;
482                 }
483         }
484
485         extra = 0;
486         if (nocache)
487                 extra |= O_DIRECT;
488         if (sync)
489                 extra |= O_SYNC;
490
491         fd = open(nopt, (ro ? O_RDONLY : O_RDWR) | extra);
492         if (fd < 0 && !ro) {
493                 /* Attempt a r/w fail with a r/o open */
494                 fd = open(nopt, O_RDONLY | extra);
495                 ro = 1;
496         }
497
498         if (fd < 0) {
499                 warn("Could not open backing file: %s", nopt);
500                 goto err;
501         }
502
503         if (fstat(fd, &sbuf) < 0) {
504                 warn("Could not stat backing file %s", nopt);
505                 goto err;
506         }
507
508 #ifndef WITHOUT_CAPSICUM
509         cap_rights_init(&rights, CAP_FSYNC, CAP_IOCTL, CAP_READ, CAP_SEEK,
510             CAP_WRITE);
511         if (ro)
512                 cap_rights_clear(&rights, CAP_FSYNC, CAP_WRITE);
513
514         if (caph_rights_limit(fd, &rights) == -1)
515                 errx(EX_OSERR, "Unable to apply rights for sandbox");
516 #endif
517
518         /*
519          * Deal with raw devices
520          */
521         size = sbuf.st_size;
522         sectsz = DEV_BSIZE;
523         psectsz = psectoff = 0;
524         candelete = geom = 0;
525         if (S_ISCHR(sbuf.st_mode)) {
526                 if (ioctl(fd, DIOCGMEDIASIZE, &size) < 0 ||
527                     ioctl(fd, DIOCGSECTORSIZE, &sectsz)) {
528                         perror("Could not fetch dev blk/sector size");
529                         goto err;
530                 }
531                 assert(size != 0);
532                 assert(sectsz != 0);
533                 if (ioctl(fd, DIOCGSTRIPESIZE, &psectsz) == 0 && psectsz > 0)
534                         ioctl(fd, DIOCGSTRIPEOFFSET, &psectoff);
535                 strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name));
536                 arg.len = sizeof(arg.value.i);
537                 if (nodelete == 0 && ioctl(fd, DIOCGATTR, &arg) == 0)
538                         candelete = arg.value.i;
539                 if (ioctl(fd, DIOCGPROVIDERNAME, name) == 0)
540                         geom = 1;
541         } else
542                 psectsz = sbuf.st_blksize;
543
544 #ifndef WITHOUT_CAPSICUM
545         if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1)
546                 errx(EX_OSERR, "Unable to apply rights for sandbox");
547 #endif
548
549         if (ssopt != 0) {
550                 if (!powerof2(ssopt) || !powerof2(pssopt) || ssopt < 512 ||
551                     ssopt > pssopt) {
552                         EPRINTLN("Invalid sector size %d/%d",
553                             ssopt, pssopt);
554                         goto err;
555                 }
556
557                 /*
558                  * Some backend drivers (e.g. cd0, ada0) require that the I/O
559                  * size be a multiple of the device's sector size.
560                  *
561                  * Validate that the emulated sector size complies with this
562                  * requirement.
563                  */
564                 if (S_ISCHR(sbuf.st_mode)) {
565                         if (ssopt < sectsz || (ssopt % sectsz) != 0) {
566                                 EPRINTLN("Sector size %d incompatible "
567                                     "with underlying device sector size %d",
568                                     ssopt, sectsz);
569                                 goto err;
570                         }
571                 }
572
573                 sectsz = ssopt;
574                 psectsz = pssopt;
575                 psectoff = 0;
576         }
577
578         bc = calloc(1, sizeof(struct blockif_ctxt));
579         if (bc == NULL) {
580                 perror("calloc");
581                 goto err;
582         }
583
584         bc->bc_magic = BLOCKIF_SIG;
585         bc->bc_fd = fd;
586         bc->bc_ischr = S_ISCHR(sbuf.st_mode);
587         bc->bc_isgeom = geom;
588         bc->bc_candelete = candelete;
589         bc->bc_rdonly = ro;
590         bc->bc_size = size;
591         bc->bc_sectsz = sectsz;
592         bc->bc_psectsz = psectsz;
593         bc->bc_psectoff = psectoff;
594         pthread_mutex_init(&bc->bc_mtx, NULL);
595         pthread_cond_init(&bc->bc_cond, NULL);
596         bc->bc_paused = 0;
597         bc->bc_work_count = 0;
598         pthread_cond_init(&bc->bc_paused_cond, NULL);
599         pthread_cond_init(&bc->bc_work_done_cond, NULL);
600         TAILQ_INIT(&bc->bc_freeq);
601         TAILQ_INIT(&bc->bc_pendq);
602         TAILQ_INIT(&bc->bc_busyq);
603         for (i = 0; i < BLOCKIF_MAXREQ; i++) {
604                 bc->bc_reqs[i].be_status = BST_FREE;
605                 TAILQ_INSERT_HEAD(&bc->bc_freeq, &bc->bc_reqs[i], be_link);
606         }
607
608         for (i = 0; i < BLOCKIF_NUMTHR; i++) {
609                 pthread_create(&bc->bc_btid[i], NULL, blockif_thr, bc);
610                 snprintf(tname, sizeof(tname), "blk-%s-%d", ident, i);
611                 pthread_set_name_np(bc->bc_btid[i], tname);
612         }
613
614         return (bc);
615 err:
616         if (fd >= 0)
617                 close(fd);
618         free(nopt);
619         return (NULL);
620 }
621
622 static int
623 blockif_request(struct blockif_ctxt *bc, struct blockif_req *breq,
624                 enum blockop op)
625 {
626         int err;
627
628         err = 0;
629
630         pthread_mutex_lock(&bc->bc_mtx);
631         if (!TAILQ_EMPTY(&bc->bc_freeq)) {
632                 /*
633                  * Enqueue and inform the block i/o thread
634                  * that there is work available
635                  */
636                 if (blockif_enqueue(bc, breq, op))
637                         pthread_cond_signal(&bc->bc_cond);
638         } else {
639                 /*
640                  * Callers are not allowed to enqueue more than
641                  * the specified blockif queue limit. Return an
642                  * error to indicate that the queue length has been
643                  * exceeded.
644                  */
645                 err = E2BIG;
646         }
647         pthread_mutex_unlock(&bc->bc_mtx);
648
649         return (err);
650 }
651
652 int
653 blockif_read(struct blockif_ctxt *bc, struct blockif_req *breq)
654 {
655
656         assert(bc->bc_magic == BLOCKIF_SIG);
657         return (blockif_request(bc, breq, BOP_READ));
658 }
659
660 int
661 blockif_write(struct blockif_ctxt *bc, struct blockif_req *breq)
662 {
663
664         assert(bc->bc_magic == BLOCKIF_SIG);
665         return (blockif_request(bc, breq, BOP_WRITE));
666 }
667
668 int
669 blockif_flush(struct blockif_ctxt *bc, struct blockif_req *breq)
670 {
671
672         assert(bc->bc_magic == BLOCKIF_SIG);
673         return (blockif_request(bc, breq, BOP_FLUSH));
674 }
675
676 int
677 blockif_delete(struct blockif_ctxt *bc, struct blockif_req *breq)
678 {
679
680         assert(bc->bc_magic == BLOCKIF_SIG);
681         return (blockif_request(bc, breq, BOP_DELETE));
682 }
683
684 int
685 blockif_cancel(struct blockif_ctxt *bc, struct blockif_req *breq)
686 {
687         struct blockif_elem *be;
688
689         assert(bc->bc_magic == BLOCKIF_SIG);
690
691         pthread_mutex_lock(&bc->bc_mtx);
692         /* XXX: not waiting while paused */
693
694         /*
695          * Check pending requests.
696          */
697         TAILQ_FOREACH(be, &bc->bc_pendq, be_link) {
698                 if (be->be_req == breq)
699                         break;
700         }
701         if (be != NULL) {
702                 /*
703                  * Found it.
704                  */
705                 blockif_complete(bc, be);
706                 pthread_mutex_unlock(&bc->bc_mtx);
707
708                 return (0);
709         }
710
711         /*
712          * Check in-flight requests.
713          */
714         TAILQ_FOREACH(be, &bc->bc_busyq, be_link) {
715                 if (be->be_req == breq)
716                         break;
717         }
718         if (be == NULL) {
719                 /*
720                  * Didn't find it.
721                  */
722                 pthread_mutex_unlock(&bc->bc_mtx);
723                 return (EINVAL);
724         }
725
726         /*
727          * Interrupt the processing thread to force it return
728          * prematurely via it's normal callback path.
729          */
730         while (be->be_status == BST_BUSY) {
731                 struct blockif_sig_elem bse, *old_head;
732
733                 pthread_mutex_init(&bse.bse_mtx, NULL);
734                 pthread_cond_init(&bse.bse_cond, NULL);
735
736                 bse.bse_pending = 1;
737
738                 do {
739                         old_head = blockif_bse_head;
740                         bse.bse_next = old_head;
741                 } while (!atomic_cmpset_ptr((uintptr_t *)&blockif_bse_head,
742                                             (uintptr_t)old_head,
743                                             (uintptr_t)&bse));
744
745                 pthread_kill(be->be_tid, SIGCONT);
746
747                 pthread_mutex_lock(&bse.bse_mtx);
748                 while (bse.bse_pending)
749                         pthread_cond_wait(&bse.bse_cond, &bse.bse_mtx);
750                 pthread_mutex_unlock(&bse.bse_mtx);
751         }
752
753         pthread_mutex_unlock(&bc->bc_mtx);
754
755         /*
756          * The processing thread has been interrupted.  Since it's not
757          * clear if the callback has been invoked yet, return EBUSY.
758          */
759         return (EBUSY);
760 }
761
762 int
763 blockif_close(struct blockif_ctxt *bc)
764 {
765         void *jval;
766         int i;
767
768         assert(bc->bc_magic == BLOCKIF_SIG);
769
770         /*
771          * Stop the block i/o thread
772          */
773         pthread_mutex_lock(&bc->bc_mtx);
774         bc->bc_closing = 1;
775         pthread_mutex_unlock(&bc->bc_mtx);
776         pthread_cond_broadcast(&bc->bc_cond);
777         for (i = 0; i < BLOCKIF_NUMTHR; i++)
778                 pthread_join(bc->bc_btid[i], &jval);
779
780         /* XXX Cancel queued i/o's ??? */
781
782         /*
783          * Release resources
784          */
785         bc->bc_magic = 0;
786         close(bc->bc_fd);
787         free(bc);
788
789         return (0);
790 }
791
792 /*
793  * Return virtual C/H/S values for a given block. Use the algorithm
794  * outlined in the VHD specification to calculate values.
795  */
796 void
797 blockif_chs(struct blockif_ctxt *bc, uint16_t *c, uint8_t *h, uint8_t *s)
798 {
799         off_t sectors;          /* total sectors of the block dev */
800         off_t hcyl;             /* cylinders times heads */
801         uint16_t secpt;         /* sectors per track */
802         uint8_t heads;
803
804         assert(bc->bc_magic == BLOCKIF_SIG);
805
806         sectors = bc->bc_size / bc->bc_sectsz;
807
808         /* Clamp the size to the largest possible with CHS */
809         if (sectors > 65535UL*16*255)
810                 sectors = 65535UL*16*255;
811
812         if (sectors >= 65536UL*16*63) {
813                 secpt = 255;
814                 heads = 16;
815                 hcyl = sectors / secpt;
816         } else {
817                 secpt = 17;
818                 hcyl = sectors / secpt;
819                 heads = (hcyl + 1023) / 1024;
820
821                 if (heads < 4)
822                         heads = 4;
823
824                 if (hcyl >= (heads * 1024) || heads > 16) {
825                         secpt = 31;
826                         heads = 16;
827                         hcyl = sectors / secpt;
828                 }
829                 if (hcyl >= (heads * 1024)) {
830                         secpt = 63;
831                         heads = 16;
832                         hcyl = sectors / secpt;
833                 }
834         }
835
836         *c = hcyl / heads;
837         *h = heads;
838         *s = secpt;
839 }
840
841 /*
842  * Accessors
843  */
844 off_t
845 blockif_size(struct blockif_ctxt *bc)
846 {
847
848         assert(bc->bc_magic == BLOCKIF_SIG);
849         return (bc->bc_size);
850 }
851
852 int
853 blockif_sectsz(struct blockif_ctxt *bc)
854 {
855
856         assert(bc->bc_magic == BLOCKIF_SIG);
857         return (bc->bc_sectsz);
858 }
859
860 void
861 blockif_psectsz(struct blockif_ctxt *bc, int *size, int *off)
862 {
863
864         assert(bc->bc_magic == BLOCKIF_SIG);
865         *size = bc->bc_psectsz;
866         *off = bc->bc_psectoff;
867 }
868
869 int
870 blockif_queuesz(struct blockif_ctxt *bc)
871 {
872
873         assert(bc->bc_magic == BLOCKIF_SIG);
874         return (BLOCKIF_MAXREQ - 1);
875 }
876
877 int
878 blockif_is_ro(struct blockif_ctxt *bc)
879 {
880
881         assert(bc->bc_magic == BLOCKIF_SIG);
882         return (bc->bc_rdonly);
883 }
884
885 int
886 blockif_candelete(struct blockif_ctxt *bc)
887 {
888
889         assert(bc->bc_magic == BLOCKIF_SIG);
890         return (bc->bc_candelete);
891 }
892
893 #ifdef BHYVE_SNAPSHOT
894 void
895 blockif_pause(struct blockif_ctxt *bc)
896 {
897         assert(bc != NULL);
898         assert(bc->bc_magic == BLOCKIF_SIG);
899
900         pthread_mutex_lock(&bc->bc_mtx);
901         bc->bc_paused = 1;
902
903         /* The interface is paused. Wait for workers to finish their work */
904         while (bc->bc_work_count)
905                 pthread_cond_wait(&bc->bc_work_done_cond, &bc->bc_mtx);
906         pthread_mutex_unlock(&bc->bc_mtx);
907
908         if (blockif_flush_bc(bc))
909                 fprintf(stderr, "%s: [WARN] failed to flush backing file.\r\n",
910                         __func__);
911 }
912
913 void
914 blockif_resume(struct blockif_ctxt *bc)
915 {
916         assert(bc != NULL);
917         assert(bc->bc_magic == BLOCKIF_SIG);
918
919         pthread_mutex_lock(&bc->bc_mtx);
920         bc->bc_paused = 0;
921         /* resume the threads waiting for paused */
922         pthread_cond_broadcast(&bc->bc_paused_cond);
923         /* kick the threads after restore */
924         pthread_cond_broadcast(&bc->bc_cond);
925         pthread_mutex_unlock(&bc->bc_mtx);
926 }
927
928 int
929 blockif_snapshot_req(struct blockif_req *br, struct vm_snapshot_meta *meta)
930 {
931         int i;
932         struct iovec *iov;
933         int ret;
934
935         SNAPSHOT_VAR_OR_LEAVE(br->br_iovcnt, meta, ret, done);
936         SNAPSHOT_VAR_OR_LEAVE(br->br_offset, meta, ret, done);
937         SNAPSHOT_VAR_OR_LEAVE(br->br_resid, meta, ret, done);
938
939         /*
940          * XXX: The callback and parameter must be filled by the virtualized
941          * device that uses the interface, during its init; we're not touching
942          * them here.
943          */
944
945         /* Snapshot the iovecs. */
946         for (i = 0; i < br->br_iovcnt; i++) {
947                 iov = &br->br_iov[i];
948
949                 SNAPSHOT_VAR_OR_LEAVE(iov->iov_len, meta, ret, done);
950
951                 /* We assume the iov is a guest-mapped address. */
952                 SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(iov->iov_base, iov->iov_len,
953                         false, meta, ret, done);
954         }
955
956 done:
957         return (ret);
958 }
959
960 int
961 blockif_snapshot(struct blockif_ctxt *bc, struct vm_snapshot_meta *meta)
962 {
963         int ret;
964
965         if (bc->bc_paused == 0) {
966                 fprintf(stderr, "%s: Snapshot failed: "
967                         "interface not paused.\r\n", __func__);
968                 return (ENXIO);
969         }
970
971         pthread_mutex_lock(&bc->bc_mtx);
972
973         SNAPSHOT_VAR_OR_LEAVE(bc->bc_magic, meta, ret, done);
974         SNAPSHOT_VAR_OR_LEAVE(bc->bc_ischr, meta, ret, done);
975         SNAPSHOT_VAR_OR_LEAVE(bc->bc_isgeom, meta, ret, done);
976         SNAPSHOT_VAR_OR_LEAVE(bc->bc_candelete, meta, ret, done);
977         SNAPSHOT_VAR_OR_LEAVE(bc->bc_rdonly, meta, ret, done);
978         SNAPSHOT_VAR_OR_LEAVE(bc->bc_size, meta, ret, done);
979         SNAPSHOT_VAR_OR_LEAVE(bc->bc_sectsz, meta, ret, done);
980         SNAPSHOT_VAR_OR_LEAVE(bc->bc_psectsz, meta, ret, done);
981         SNAPSHOT_VAR_OR_LEAVE(bc->bc_psectoff, meta, ret, done);
982         SNAPSHOT_VAR_OR_LEAVE(bc->bc_closing, meta, ret, done);
983
984 done:
985         pthread_mutex_unlock(&bc->bc_mtx);
986         return (ret);
987 }
988 #endif