1dd84a43cSPoul-Henning Kamp /*- 2dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Poul-Henning Kamp 3dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. 4*ee75e7deSKonstantin Belousov * Copyright (c) 2013 The FreeBSD Foundation 5dd84a43cSPoul-Henning Kamp * All rights reserved. 6dd84a43cSPoul-Henning Kamp * 7dd84a43cSPoul-Henning Kamp * This software was developed for the FreeBSD Project by Poul-Henning Kamp 8dd84a43cSPoul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. 9dd84a43cSPoul-Henning Kamp * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 10dd84a43cSPoul-Henning Kamp * DARPA CHATS research program. 11dd84a43cSPoul-Henning Kamp * 12*ee75e7deSKonstantin Belousov * Portions of this software were developed by Konstantin Belousov 13*ee75e7deSKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 14*ee75e7deSKonstantin Belousov * 15dd84a43cSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 16dd84a43cSPoul-Henning Kamp * modification, are permitted provided that the following conditions 17dd84a43cSPoul-Henning Kamp * are met: 18dd84a43cSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 19dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 20dd84a43cSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 21dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 22dd84a43cSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 23dd84a43cSPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 24dd84a43cSPoul-Henning Kamp * products derived from this software without specific prior written 25dd84a43cSPoul-Henning Kamp * permission. 26dd84a43cSPoul-Henning Kamp * 27dd84a43cSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 28dd84a43cSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29dd84a43cSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30dd84a43cSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 31dd84a43cSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32dd84a43cSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33dd84a43cSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34dd84a43cSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35dd84a43cSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36dd84a43cSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37dd84a43cSPoul-Henning Kamp * SUCH DAMAGE. 38dd84a43cSPoul-Henning Kamp */ 39dd84a43cSPoul-Henning Kamp 4050b1faefSDavid E. O'Brien #include <sys/cdefs.h> 4150b1faefSDavid E. O'Brien __FBSDID("$FreeBSD$"); 42dd84a43cSPoul-Henning Kamp 43dd84a43cSPoul-Henning Kamp #include <sys/param.h> 44dd84a43cSPoul-Henning Kamp #include <sys/systm.h> 45dd84a43cSPoul-Henning Kamp #include <sys/kernel.h> 46dd84a43cSPoul-Henning Kamp #include <sys/malloc.h> 47dd84a43cSPoul-Henning Kamp #include <sys/bio.h> 4849dbb61dSRobert Watson #include <sys/ktr.h> 4951460da8SJohn Baldwin #include <sys/proc.h> 503b378147SPawel Jakub Dawidek #include <sys/stack.h> 51*ee75e7deSKonstantin Belousov #include <sys/sysctl.h> 52dd84a43cSPoul-Henning Kamp 53dd84a43cSPoul-Henning Kamp #include <sys/errno.h> 54dd84a43cSPoul-Henning Kamp #include <geom/geom.h> 55b1876192SPoul-Henning Kamp #include <geom/geom_int.h> 56e24cbd90SPoul-Henning Kamp #include <sys/devicestat.h> 57dd84a43cSPoul-Henning Kamp 585ffb2c8bSPoul-Henning Kamp #include <vm/uma.h> 59*ee75e7deSKonstantin Belousov #include <vm/vm.h> 60*ee75e7deSKonstantin Belousov #include <vm/vm_param.h> 61*ee75e7deSKonstantin Belousov #include <vm/vm_kern.h> 62*ee75e7deSKonstantin Belousov #include <vm/vm_page.h> 63*ee75e7deSKonstantin Belousov #include <vm/vm_object.h> 64*ee75e7deSKonstantin Belousov #include <vm/vm_extern.h> 65*ee75e7deSKonstantin Belousov #include <vm/vm_map.h> 665ffb2c8bSPoul-Henning Kamp 67dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_down; 68dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_up; 695fcf4e43SPoul-Henning Kamp static struct g_bioq g_bio_run_task; 70dd84a43cSPoul-Henning Kamp 713432e4fdSPoul-Henning Kamp static u_int pace; 725ffb2c8bSPoul-Henning Kamp static uma_zone_t biozone; 733432e4fdSPoul-Henning Kamp 746231f75bSLuigi Rizzo /* 756231f75bSLuigi Rizzo * The head of the list of classifiers used in g_io_request. 766231f75bSLuigi Rizzo * Use g_register_classifier() and g_unregister_classifier() 776231f75bSLuigi Rizzo * to add/remove entries to the list. 786231f75bSLuigi Rizzo * Classifiers are invoked in registration order. 796231f75bSLuigi Rizzo */ 806231f75bSLuigi Rizzo static TAILQ_HEAD(g_classifier_tailq, g_classifier_hook) 816231f75bSLuigi Rizzo g_classifier_tailq = TAILQ_HEAD_INITIALIZER(g_classifier_tailq); 826231f75bSLuigi Rizzo 83dd84a43cSPoul-Henning Kamp #include <machine/atomic.h> 84dd84a43cSPoul-Henning Kamp 85dd84a43cSPoul-Henning Kamp static void 86dd84a43cSPoul-Henning Kamp g_bioq_lock(struct g_bioq *bq) 87dd84a43cSPoul-Henning Kamp { 88dd84a43cSPoul-Henning Kamp 89dd84a43cSPoul-Henning Kamp mtx_lock(&bq->bio_queue_lock); 90dd84a43cSPoul-Henning Kamp } 91dd84a43cSPoul-Henning Kamp 92dd84a43cSPoul-Henning Kamp static void 93dd84a43cSPoul-Henning Kamp g_bioq_unlock(struct g_bioq *bq) 94dd84a43cSPoul-Henning Kamp { 95dd84a43cSPoul-Henning Kamp 96dd84a43cSPoul-Henning Kamp mtx_unlock(&bq->bio_queue_lock); 97dd84a43cSPoul-Henning Kamp } 98dd84a43cSPoul-Henning Kamp 99dd84a43cSPoul-Henning Kamp #if 0 100dd84a43cSPoul-Henning Kamp static void 101dd84a43cSPoul-Henning Kamp g_bioq_destroy(struct g_bioq *bq) 102dd84a43cSPoul-Henning Kamp { 103dd84a43cSPoul-Henning Kamp 104dd84a43cSPoul-Henning Kamp mtx_destroy(&bq->bio_queue_lock); 105dd84a43cSPoul-Henning Kamp } 106dd84a43cSPoul-Henning Kamp #endif 107dd84a43cSPoul-Henning Kamp 108dd84a43cSPoul-Henning Kamp static void 109dd84a43cSPoul-Henning Kamp g_bioq_init(struct g_bioq *bq) 110dd84a43cSPoul-Henning Kamp { 111dd84a43cSPoul-Henning Kamp 112dd84a43cSPoul-Henning Kamp TAILQ_INIT(&bq->bio_queue); 1136008862bSJohn Baldwin mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF); 114dd84a43cSPoul-Henning Kamp } 115dd84a43cSPoul-Henning Kamp 116dd84a43cSPoul-Henning Kamp static struct bio * 117dd84a43cSPoul-Henning Kamp g_bioq_first(struct g_bioq *bq) 118dd84a43cSPoul-Henning Kamp { 119dd84a43cSPoul-Henning Kamp struct bio *bp; 120dd84a43cSPoul-Henning Kamp 121dd84a43cSPoul-Henning Kamp bp = TAILQ_FIRST(&bq->bio_queue); 122dd84a43cSPoul-Henning Kamp if (bp != NULL) { 123dcbd0fe5SPoul-Henning Kamp KASSERT((bp->bio_flags & BIO_ONQUEUE), 124dcbd0fe5SPoul-Henning Kamp ("Bio not on queue bp=%p target %p", bp, bq)); 125dcbd0fe5SPoul-Henning Kamp bp->bio_flags &= ~BIO_ONQUEUE; 126dd84a43cSPoul-Henning Kamp TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue); 127dd84a43cSPoul-Henning Kamp bq->bio_queue_length--; 128dd84a43cSPoul-Henning Kamp } 129dd84a43cSPoul-Henning Kamp return (bp); 130dd84a43cSPoul-Henning Kamp } 131dd84a43cSPoul-Henning Kamp 132dd84a43cSPoul-Henning Kamp struct bio * 133dd84a43cSPoul-Henning Kamp g_new_bio(void) 134dd84a43cSPoul-Henning Kamp { 135dd84a43cSPoul-Henning Kamp struct bio *bp; 136dd84a43cSPoul-Henning Kamp 1375ffb2c8bSPoul-Henning Kamp bp = uma_zalloc(biozone, M_NOWAIT | M_ZERO); 1383b378147SPawel Jakub Dawidek #ifdef KTR 139b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1403b378147SPawel Jakub Dawidek struct stack st; 1413b378147SPawel Jakub Dawidek 1423b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_new_bio(): %p", bp); 1433b378147SPawel Jakub Dawidek stack_save(&st); 1443b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1453b378147SPawel Jakub Dawidek } 1463b378147SPawel Jakub Dawidek #endif 147dd84a43cSPoul-Henning Kamp return (bp); 148dd84a43cSPoul-Henning Kamp } 149dd84a43cSPoul-Henning Kamp 150a2033c96SPoul-Henning Kamp struct bio * 151a2033c96SPoul-Henning Kamp g_alloc_bio(void) 152a2033c96SPoul-Henning Kamp { 153a2033c96SPoul-Henning Kamp struct bio *bp; 154a2033c96SPoul-Henning Kamp 155a2033c96SPoul-Henning Kamp bp = uma_zalloc(biozone, M_WAITOK | M_ZERO); 1563b378147SPawel Jakub Dawidek #ifdef KTR 157b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1583b378147SPawel Jakub Dawidek struct stack st; 1593b378147SPawel Jakub Dawidek 1603b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_alloc_bio(): %p", bp); 1613b378147SPawel Jakub Dawidek stack_save(&st); 1623b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1633b378147SPawel Jakub Dawidek } 1643b378147SPawel Jakub Dawidek #endif 165a2033c96SPoul-Henning Kamp return (bp); 166a2033c96SPoul-Henning Kamp } 167a2033c96SPoul-Henning Kamp 168dd84a43cSPoul-Henning Kamp void 169dd84a43cSPoul-Henning Kamp g_destroy_bio(struct bio *bp) 170dd84a43cSPoul-Henning Kamp { 1713b378147SPawel Jakub Dawidek #ifdef KTR 172b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1733b378147SPawel Jakub Dawidek struct stack st; 174dd84a43cSPoul-Henning Kamp 1753b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_destroy_bio(): %p", bp); 1763b378147SPawel Jakub Dawidek stack_save(&st); 1773b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1783b378147SPawel Jakub Dawidek } 1793b378147SPawel Jakub Dawidek #endif 1805ffb2c8bSPoul-Henning Kamp uma_zfree(biozone, bp); 181dd84a43cSPoul-Henning Kamp } 182dd84a43cSPoul-Henning Kamp 183dd84a43cSPoul-Henning Kamp struct bio * 184dd84a43cSPoul-Henning Kamp g_clone_bio(struct bio *bp) 185dd84a43cSPoul-Henning Kamp { 186dd84a43cSPoul-Henning Kamp struct bio *bp2; 187dd84a43cSPoul-Henning Kamp 1885ffb2c8bSPoul-Henning Kamp bp2 = uma_zalloc(biozone, M_NOWAIT | M_ZERO); 189a1bd3ee2SPoul-Henning Kamp if (bp2 != NULL) { 190936cc461SPoul-Henning Kamp bp2->bio_parent = bp; 191dd84a43cSPoul-Henning Kamp bp2->bio_cmd = bp->bio_cmd; 19282a6ae10SJim Harris /* 19382a6ae10SJim Harris * BIO_ORDERED flag may be used by disk drivers to enforce 19482a6ae10SJim Harris * ordering restrictions, so this flag needs to be cloned. 195*ee75e7deSKonstantin Belousov * BIO_UNMAPPED should be inherited, to properly indicate 196*ee75e7deSKonstantin Belousov * which way the buffer is passed. 19782a6ae10SJim Harris * Other bio flags are not suitable for cloning. 19882a6ae10SJim Harris */ 199*ee75e7deSKonstantin Belousov bp2->bio_flags = bp->bio_flags & (BIO_ORDERED | BIO_UNMAPPED); 200dd84a43cSPoul-Henning Kamp bp2->bio_length = bp->bio_length; 201dd84a43cSPoul-Henning Kamp bp2->bio_offset = bp->bio_offset; 202dd84a43cSPoul-Henning Kamp bp2->bio_data = bp->bio_data; 203*ee75e7deSKonstantin Belousov bp2->bio_ma = bp->bio_ma; 204*ee75e7deSKonstantin Belousov bp2->bio_ma_n = bp->bio_ma_n; 205*ee75e7deSKonstantin Belousov bp2->bio_ma_offset = bp->bio_ma_offset; 206dd84a43cSPoul-Henning Kamp bp2->bio_attribute = bp->bio_attribute; 2076231f75bSLuigi Rizzo /* Inherit classification info from the parent */ 2086231f75bSLuigi Rizzo bp2->bio_classifier1 = bp->bio_classifier1; 2096231f75bSLuigi Rizzo bp2->bio_classifier2 = bp->bio_classifier2; 210801bb689SPoul-Henning Kamp bp->bio_children++; 211a1bd3ee2SPoul-Henning Kamp } 2123b378147SPawel Jakub Dawidek #ifdef KTR 213b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 2143b378147SPawel Jakub Dawidek struct stack st; 2153b378147SPawel Jakub Dawidek 216ad572235SRuslan Ermilov CTR2(KTR_GEOM, "g_clone_bio(%p): %p", bp, bp2); 2173b378147SPawel Jakub Dawidek stack_save(&st); 2183b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 2193b378147SPawel Jakub Dawidek } 2203b378147SPawel Jakub Dawidek #endif 221dd84a43cSPoul-Henning Kamp return(bp2); 222dd84a43cSPoul-Henning Kamp } 223dd84a43cSPoul-Henning Kamp 2244bec0ff1SPawel Jakub Dawidek struct bio * 2254bec0ff1SPawel Jakub Dawidek g_duplicate_bio(struct bio *bp) 2264bec0ff1SPawel Jakub Dawidek { 2274bec0ff1SPawel Jakub Dawidek struct bio *bp2; 2284bec0ff1SPawel Jakub Dawidek 2294bec0ff1SPawel Jakub Dawidek bp2 = uma_zalloc(biozone, M_WAITOK | M_ZERO); 230*ee75e7deSKonstantin Belousov bp2->bio_flags = bp->bio_flags & BIO_UNMAPPED; 2314bec0ff1SPawel Jakub Dawidek bp2->bio_parent = bp; 2324bec0ff1SPawel Jakub Dawidek bp2->bio_cmd = bp->bio_cmd; 2334bec0ff1SPawel Jakub Dawidek bp2->bio_length = bp->bio_length; 2344bec0ff1SPawel Jakub Dawidek bp2->bio_offset = bp->bio_offset; 2354bec0ff1SPawel Jakub Dawidek bp2->bio_data = bp->bio_data; 236*ee75e7deSKonstantin Belousov bp2->bio_ma = bp->bio_ma; 237*ee75e7deSKonstantin Belousov bp2->bio_ma_n = bp->bio_ma_n; 238*ee75e7deSKonstantin Belousov bp2->bio_ma_offset = bp->bio_ma_offset; 2394bec0ff1SPawel Jakub Dawidek bp2->bio_attribute = bp->bio_attribute; 2404bec0ff1SPawel Jakub Dawidek bp->bio_children++; 2414bec0ff1SPawel Jakub Dawidek #ifdef KTR 242b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 2434bec0ff1SPawel Jakub Dawidek struct stack st; 2444bec0ff1SPawel Jakub Dawidek 2454bec0ff1SPawel Jakub Dawidek CTR2(KTR_GEOM, "g_duplicate_bio(%p): %p", bp, bp2); 2464bec0ff1SPawel Jakub Dawidek stack_save(&st); 2474bec0ff1SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 2484bec0ff1SPawel Jakub Dawidek } 2494bec0ff1SPawel Jakub Dawidek #endif 2504bec0ff1SPawel Jakub Dawidek return(bp2); 2514bec0ff1SPawel Jakub Dawidek } 2524bec0ff1SPawel Jakub Dawidek 253dd84a43cSPoul-Henning Kamp void 254dd84a43cSPoul-Henning Kamp g_io_init() 255dd84a43cSPoul-Henning Kamp { 256dd84a43cSPoul-Henning Kamp 257dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_down); 258dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_up); 2595fcf4e43SPoul-Henning Kamp g_bioq_init(&g_bio_run_task); 2605ffb2c8bSPoul-Henning Kamp biozone = uma_zcreate("g_bio", sizeof (struct bio), 2615ffb2c8bSPoul-Henning Kamp NULL, NULL, 2625ffb2c8bSPoul-Henning Kamp NULL, NULL, 2635ffb2c8bSPoul-Henning Kamp 0, 0); 264dd84a43cSPoul-Henning Kamp } 265dd84a43cSPoul-Henning Kamp 266dd84a43cSPoul-Henning Kamp int 2670d3f37a8SPoul-Henning Kamp g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 268dd84a43cSPoul-Henning Kamp { 269dd84a43cSPoul-Henning Kamp struct bio *bp; 270dd84a43cSPoul-Henning Kamp int error; 271dd84a43cSPoul-Henning Kamp 272dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, "bio_getattr(%s)", attr); 273a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 274dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_GETATTR; 275dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 276dd84a43cSPoul-Henning Kamp bp->bio_attribute = attr; 277dd84a43cSPoul-Henning Kamp bp->bio_length = *len; 278dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 279dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 28053706245SPoul-Henning Kamp error = biowait(bp, "ggetattr"); 281dd84a43cSPoul-Henning Kamp *len = bp->bio_completed; 282dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 283dd84a43cSPoul-Henning Kamp return (error); 284dd84a43cSPoul-Henning Kamp } 285dd84a43cSPoul-Henning Kamp 286c3618c65SPawel Jakub Dawidek int 287c3618c65SPawel Jakub Dawidek g_io_flush(struct g_consumer *cp) 288c3618c65SPawel Jakub Dawidek { 289c3618c65SPawel Jakub Dawidek struct bio *bp; 290c3618c65SPawel Jakub Dawidek int error; 291c3618c65SPawel Jakub Dawidek 292c3618c65SPawel Jakub Dawidek g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name); 293c3618c65SPawel Jakub Dawidek bp = g_alloc_bio(); 294c3618c65SPawel Jakub Dawidek bp->bio_cmd = BIO_FLUSH; 295f03f7a0cSJustin T. Gibbs bp->bio_flags |= BIO_ORDERED; 296c3618c65SPawel Jakub Dawidek bp->bio_done = NULL; 297c3618c65SPawel Jakub Dawidek bp->bio_attribute = NULL; 298c3618c65SPawel Jakub Dawidek bp->bio_offset = cp->provider->mediasize; 299c3618c65SPawel Jakub Dawidek bp->bio_length = 0; 300c3618c65SPawel Jakub Dawidek bp->bio_data = NULL; 301c3618c65SPawel Jakub Dawidek g_io_request(bp, cp); 302c3618c65SPawel Jakub Dawidek error = biowait(bp, "gflush"); 303c3618c65SPawel Jakub Dawidek g_destroy_bio(bp); 304c3618c65SPawel Jakub Dawidek return (error); 305c3618c65SPawel Jakub Dawidek } 306c3618c65SPawel Jakub Dawidek 307e39d70d4SPoul-Henning Kamp static int 308e39d70d4SPoul-Henning Kamp g_io_check(struct bio *bp) 309e39d70d4SPoul-Henning Kamp { 310e39d70d4SPoul-Henning Kamp struct g_consumer *cp; 311e39d70d4SPoul-Henning Kamp struct g_provider *pp; 312e39d70d4SPoul-Henning Kamp 313e39d70d4SPoul-Henning Kamp cp = bp->bio_from; 314e39d70d4SPoul-Henning Kamp pp = bp->bio_to; 315e39d70d4SPoul-Henning Kamp 316e39d70d4SPoul-Henning Kamp /* Fail if access counters dont allow the operation */ 317e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 318e39d70d4SPoul-Henning Kamp case BIO_READ: 319e39d70d4SPoul-Henning Kamp case BIO_GETATTR: 320e39d70d4SPoul-Henning Kamp if (cp->acr == 0) 321e39d70d4SPoul-Henning Kamp return (EPERM); 322e39d70d4SPoul-Henning Kamp break; 323e39d70d4SPoul-Henning Kamp case BIO_WRITE: 324e39d70d4SPoul-Henning Kamp case BIO_DELETE: 325c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 326e39d70d4SPoul-Henning Kamp if (cp->acw == 0) 327e39d70d4SPoul-Henning Kamp return (EPERM); 328e39d70d4SPoul-Henning Kamp break; 329e39d70d4SPoul-Henning Kamp default: 330e39d70d4SPoul-Henning Kamp return (EPERM); 331e39d70d4SPoul-Henning Kamp } 332e39d70d4SPoul-Henning Kamp /* if provider is marked for error, don't disturb. */ 333e39d70d4SPoul-Henning Kamp if (pp->error) 334e39d70d4SPoul-Henning Kamp return (pp->error); 3353631c638SAlexander Motin if (cp->flags & G_CF_ORPHAN) 3363631c638SAlexander Motin return (ENXIO); 337e39d70d4SPoul-Henning Kamp 338e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 339e39d70d4SPoul-Henning Kamp case BIO_READ: 340e39d70d4SPoul-Henning Kamp case BIO_WRITE: 341e39d70d4SPoul-Henning Kamp case BIO_DELETE: 3422a842317SAndriy Gapon /* Zero sectorsize or mediasize is probably a lack of media. */ 3432a842317SAndriy Gapon if (pp->sectorsize == 0 || pp->mediasize == 0) 34443bff1a7SPoul-Henning Kamp return (ENXIO); 345e39d70d4SPoul-Henning Kamp /* Reject I/O not on sector boundary */ 346e39d70d4SPoul-Henning Kamp if (bp->bio_offset % pp->sectorsize) 347e39d70d4SPoul-Henning Kamp return (EINVAL); 348e39d70d4SPoul-Henning Kamp /* Reject I/O not integral sector long */ 349e39d70d4SPoul-Henning Kamp if (bp->bio_length % pp->sectorsize) 350e39d70d4SPoul-Henning Kamp return (EINVAL); 351d1b8bf47SPoul-Henning Kamp /* Reject requests before or past the end of media. */ 352d1b8bf47SPoul-Henning Kamp if (bp->bio_offset < 0) 353d1b8bf47SPoul-Henning Kamp return (EIO); 354e39d70d4SPoul-Henning Kamp if (bp->bio_offset > pp->mediasize) 355e39d70d4SPoul-Henning Kamp return (EIO); 356e39d70d4SPoul-Henning Kamp break; 357e39d70d4SPoul-Henning Kamp default: 358e39d70d4SPoul-Henning Kamp break; 359e39d70d4SPoul-Henning Kamp } 360e39d70d4SPoul-Henning Kamp return (0); 361e39d70d4SPoul-Henning Kamp } 362e39d70d4SPoul-Henning Kamp 3636231f75bSLuigi Rizzo /* 3646231f75bSLuigi Rizzo * bio classification support. 3656231f75bSLuigi Rizzo * 3666231f75bSLuigi Rizzo * g_register_classifier() and g_unregister_classifier() 3676231f75bSLuigi Rizzo * are used to add/remove a classifier from the list. 3686231f75bSLuigi Rizzo * The list is protected using the g_bio_run_down lock, 3696231f75bSLuigi Rizzo * because the classifiers are called in this path. 3706231f75bSLuigi Rizzo * 3716231f75bSLuigi Rizzo * g_io_request() passes bio's that are not already classified 3726231f75bSLuigi Rizzo * (i.e. those with bio_classifier1 == NULL) to g_run_classifiers(). 3736231f75bSLuigi Rizzo * Classifiers can store their result in the two fields 3746231f75bSLuigi Rizzo * bio_classifier1 and bio_classifier2. 3756231f75bSLuigi Rizzo * A classifier that updates one of the fields should 3766231f75bSLuigi Rizzo * return a non-zero value. 3776231f75bSLuigi Rizzo * If no classifier updates the field, g_run_classifiers() sets 3786231f75bSLuigi Rizzo * bio_classifier1 = BIO_NOTCLASSIFIED to avoid further calls. 3796231f75bSLuigi Rizzo */ 3806231f75bSLuigi Rizzo 3816231f75bSLuigi Rizzo int 3826231f75bSLuigi Rizzo g_register_classifier(struct g_classifier_hook *hook) 3836231f75bSLuigi Rizzo { 3846231f75bSLuigi Rizzo 3856231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 3866231f75bSLuigi Rizzo TAILQ_INSERT_TAIL(&g_classifier_tailq, hook, link); 3876231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 3886231f75bSLuigi Rizzo 3896231f75bSLuigi Rizzo return (0); 3906231f75bSLuigi Rizzo } 3916231f75bSLuigi Rizzo 3926231f75bSLuigi Rizzo void 3936231f75bSLuigi Rizzo g_unregister_classifier(struct g_classifier_hook *hook) 3946231f75bSLuigi Rizzo { 3956231f75bSLuigi Rizzo struct g_classifier_hook *entry; 3966231f75bSLuigi Rizzo 3976231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 3986231f75bSLuigi Rizzo TAILQ_FOREACH(entry, &g_classifier_tailq, link) { 3996231f75bSLuigi Rizzo if (entry == hook) { 4006231f75bSLuigi Rizzo TAILQ_REMOVE(&g_classifier_tailq, hook, link); 4016231f75bSLuigi Rizzo break; 4026231f75bSLuigi Rizzo } 4036231f75bSLuigi Rizzo } 4046231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 4056231f75bSLuigi Rizzo } 4066231f75bSLuigi Rizzo 4076231f75bSLuigi Rizzo static void 4086231f75bSLuigi Rizzo g_run_classifiers(struct bio *bp) 4096231f75bSLuigi Rizzo { 4106231f75bSLuigi Rizzo struct g_classifier_hook *hook; 4116231f75bSLuigi Rizzo int classified = 0; 4126231f75bSLuigi Rizzo 4136231f75bSLuigi Rizzo TAILQ_FOREACH(hook, &g_classifier_tailq, link) 4146231f75bSLuigi Rizzo classified |= hook->func(hook->arg, bp); 4156231f75bSLuigi Rizzo 4166231f75bSLuigi Rizzo if (!classified) 4176231f75bSLuigi Rizzo bp->bio_classifier1 = BIO_NOTCLASSIFIED; 4186231f75bSLuigi Rizzo } 4196231f75bSLuigi Rizzo 420dd84a43cSPoul-Henning Kamp void 421dd84a43cSPoul-Henning Kamp g_io_request(struct bio *bp, struct g_consumer *cp) 422dd84a43cSPoul-Henning Kamp { 423801bb689SPoul-Henning Kamp struct g_provider *pp; 4240d883b11SAlexander Motin int first; 425dd84a43cSPoul-Henning Kamp 426d0e17c1bSPoul-Henning Kamp KASSERT(cp != NULL, ("NULL cp in g_io_request")); 427d0e17c1bSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_request")); 428e060b6bdSPoul-Henning Kamp pp = cp->provider; 429801bb689SPoul-Henning Kamp KASSERT(pp != NULL, ("consumer not attached in g_io_request")); 43092ee312dSPawel Jakub Dawidek #ifdef DIAGNOSTIC 43192ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver1 == NULL, 43292ee312dSPawel Jakub Dawidek ("bio_driver1 used by the consumer (geom %s)", cp->geom->name)); 43392ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver2 == NULL, 43492ee312dSPawel Jakub Dawidek ("bio_driver2 used by the consumer (geom %s)", cp->geom->name)); 43592ee312dSPawel Jakub Dawidek KASSERT(bp->bio_pflags == 0, 43692ee312dSPawel Jakub Dawidek ("bio_pflags used by the consumer (geom %s)", cp->geom->name)); 43792ee312dSPawel Jakub Dawidek /* 43892ee312dSPawel Jakub Dawidek * Remember consumer's private fields, so we can detect if they were 43992ee312dSPawel Jakub Dawidek * modified by the provider. 44092ee312dSPawel Jakub Dawidek */ 44192ee312dSPawel Jakub Dawidek bp->_bio_caller1 = bp->bio_caller1; 44292ee312dSPawel Jakub Dawidek bp->_bio_caller2 = bp->bio_caller2; 44392ee312dSPawel Jakub Dawidek bp->_bio_cflags = bp->bio_cflags; 44492ee312dSPawel Jakub Dawidek #endif 445801bb689SPoul-Henning Kamp 4461ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) { 447c3618c65SPawel Jakub Dawidek KASSERT(bp->bio_data != NULL, 4481ded77b2SPawel Jakub Dawidek ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd)); 4491ded77b2SPawel Jakub Dawidek } 4501ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_DELETE|BIO_FLUSH)) { 4511ded77b2SPawel Jakub Dawidek KASSERT(bp->bio_data == NULL, 4521ded77b2SPawel Jakub Dawidek ("non-NULL bp->data in g_io_request(cmd=%hhu)", 4531ded77b2SPawel Jakub Dawidek bp->bio_cmd)); 454c3618c65SPawel Jakub Dawidek } 455dcbd0fe5SPoul-Henning Kamp if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) { 456dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_offset % cp->provider->sectorsize == 0, 457dcbd0fe5SPoul-Henning Kamp ("wrong offset %jd for sectorsize %u", 458dcbd0fe5SPoul-Henning Kamp bp->bio_offset, cp->provider->sectorsize)); 459dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_length % cp->provider->sectorsize == 0, 460dcbd0fe5SPoul-Henning Kamp ("wrong length %jd for sectorsize %u", 461dcbd0fe5SPoul-Henning Kamp bp->bio_length, cp->provider->sectorsize)); 462dcbd0fe5SPoul-Henning Kamp } 463dcbd0fe5SPoul-Henning Kamp 464f7717523SStephan Uphoff g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 465f7717523SStephan Uphoff bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); 466f7717523SStephan Uphoff 467dd84a43cSPoul-Henning Kamp bp->bio_from = cp; 468801bb689SPoul-Henning Kamp bp->bio_to = pp; 4692fccec19SPoul-Henning Kamp bp->bio_error = 0; 4702fccec19SPoul-Henning Kamp bp->bio_completed = 0; 471dd84a43cSPoul-Henning Kamp 47219fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 47319fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 47419fa21aaSPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 47519fa21aaSPoul-Henning Kamp 476a5be8eb5SAlexander Motin if (g_collectstats) 47719fa21aaSPoul-Henning Kamp binuptime(&bp->bio_t0); 478a5be8eb5SAlexander Motin else 479a5be8eb5SAlexander Motin getbinuptime(&bp->bio_t0); 4808827c821SPoul-Henning Kamp 4818827c821SPoul-Henning Kamp /* 4828827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 4838827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 4848827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 4856231f75bSLuigi Rizzo * 4866231f75bSLuigi Rizzo * We also use the lock to protect the list of classifiers. 4878827c821SPoul-Henning Kamp */ 48819fa21aaSPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 4896231f75bSLuigi Rizzo 4906231f75bSLuigi Rizzo if (!TAILQ_EMPTY(&g_classifier_tailq) && !bp->bio_classifier1) 4916231f75bSLuigi Rizzo g_run_classifiers(bp); 4926231f75bSLuigi Rizzo 493cf457284SPoul-Henning Kamp if (g_collectstats & 1) 49419fa21aaSPoul-Henning Kamp devstat_start_transaction(pp->stat, &bp->bio_t0); 495cf457284SPoul-Henning Kamp if (g_collectstats & 2) 49619fa21aaSPoul-Henning Kamp devstat_start_transaction(cp->stat, &bp->bio_t0); 49719fa21aaSPoul-Henning Kamp 49819fa21aaSPoul-Henning Kamp pp->nstart++; 499cf457284SPoul-Henning Kamp cp->nstart++; 5000d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_down.bio_queue); 50119fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_down.bio_queue, bp, bio_queue); 50219fa21aaSPoul-Henning Kamp g_bio_run_down.bio_queue_length++; 50319fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 504e39d70d4SPoul-Henning Kamp 5052fccec19SPoul-Henning Kamp /* Pass it on down. */ 5060d883b11SAlexander Motin if (first) 507dd84a43cSPoul-Henning Kamp wakeup(&g_wait_down); 508dd84a43cSPoul-Henning Kamp } 509dd84a43cSPoul-Henning Kamp 510dd84a43cSPoul-Henning Kamp void 51172840432SPoul-Henning Kamp g_io_deliver(struct bio *bp, int error) 512dd84a43cSPoul-Henning Kamp { 513801bb689SPoul-Henning Kamp struct g_consumer *cp; 514801bb689SPoul-Henning Kamp struct g_provider *pp; 5150d883b11SAlexander Motin int first; 516dd84a43cSPoul-Henning Kamp 517e060b6bdSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); 518801bb689SPoul-Henning Kamp pp = bp->bio_to; 519f7eeab17SPoul-Henning Kamp KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); 520f7eeab17SPoul-Henning Kamp cp = bp->bio_from; 521f7eeab17SPoul-Henning Kamp if (cp == NULL) { 522f7eeab17SPoul-Henning Kamp bp->bio_error = error; 523f7eeab17SPoul-Henning Kamp bp->bio_done(bp); 524f7eeab17SPoul-Henning Kamp return; 525f7eeab17SPoul-Henning Kamp } 526801bb689SPoul-Henning Kamp KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver")); 527801bb689SPoul-Henning Kamp KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver")); 528fb231f36SEdward Tomasz Napierala #ifdef DIAGNOSTIC 529fb231f36SEdward Tomasz Napierala /* 530fb231f36SEdward Tomasz Napierala * Some classes - GJournal in particular - can modify bio's 531fb231f36SEdward Tomasz Napierala * private fields while the bio is in transit; G_GEOM_VOLATILE_BIO 532fb231f36SEdward Tomasz Napierala * flag means it's an expected behaviour for that particular geom. 533fb231f36SEdward Tomasz Napierala */ 534fb231f36SEdward Tomasz Napierala if ((cp->geom->flags & G_GEOM_VOLATILE_BIO) == 0) { 535fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller1 == bp->_bio_caller1, 536fb231f36SEdward Tomasz Napierala ("bio_caller1 used by the provider %s", pp->name)); 537fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller2 == bp->_bio_caller2, 538fb231f36SEdward Tomasz Napierala ("bio_caller2 used by the provider %s", pp->name)); 539fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_cflags == bp->_bio_cflags, 540fb231f36SEdward Tomasz Napierala ("bio_cflags used by the provider %s", pp->name)); 541fb231f36SEdward Tomasz Napierala } 542fb231f36SEdward Tomasz Napierala #endif 54346aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed >= 0, ("bio_completed can't be less than 0")); 54446aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed <= bp->bio_length, 54546aeebecSPawel Jakub Dawidek ("bio_completed can't be greater than bio_length")); 5465ab413bfSPoul-Henning Kamp 547dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, 5480355b86eSPoul-Henning Kamp "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", 549801bb689SPoul-Henning Kamp bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error, 5500355b86eSPoul-Henning Kamp (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 551801bb689SPoul-Henning Kamp 55219fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 55319fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 55419fa21aaSPoul-Henning Kamp 555dcbd0fe5SPoul-Henning Kamp /* 556dcbd0fe5SPoul-Henning Kamp * XXX: next two doesn't belong here 557dcbd0fe5SPoul-Henning Kamp */ 558e24cbd90SPoul-Henning Kamp bp->bio_bcount = bp->bio_length; 559e24cbd90SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount - bp->bio_completed; 56019fa21aaSPoul-Henning Kamp 5618827c821SPoul-Henning Kamp /* 5628827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 5638827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 5648827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 5658827c821SPoul-Henning Kamp */ 56619fa21aaSPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 567cf457284SPoul-Henning Kamp if (g_collectstats & 1) 568e24cbd90SPoul-Henning Kamp devstat_end_transaction_bio(pp->stat, bp); 569cf457284SPoul-Henning Kamp if (g_collectstats & 2) 570cf457284SPoul-Henning Kamp devstat_end_transaction_bio(cp->stat, bp); 5718827c821SPoul-Henning Kamp 572c6ae9b5fSPoul-Henning Kamp cp->nend++; 573c6ae9b5fSPoul-Henning Kamp pp->nend++; 57419fa21aaSPoul-Henning Kamp if (error != ENOMEM) { 57519fa21aaSPoul-Henning Kamp bp->bio_error = error; 5760d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_up.bio_queue); 57719fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_up.bio_queue, bp, bio_queue); 578276f72c5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 57919fa21aaSPoul-Henning Kamp g_bio_run_up.bio_queue_length++; 58019fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 5810d883b11SAlexander Motin if (first) 58219fa21aaSPoul-Henning Kamp wakeup(&g_wait_up); 58319fa21aaSPoul-Henning Kamp return; 58419fa21aaSPoul-Henning Kamp } 58519fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 586dd84a43cSPoul-Henning Kamp 5872cc9686eSPoul-Henning Kamp if (bootverbose) 588801bb689SPoul-Henning Kamp printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name); 5891b949c05SPawel Jakub Dawidek bp->bio_children = 0; 5901b949c05SPawel Jakub Dawidek bp->bio_inbed = 0; 59160114438SPawel Jakub Dawidek bp->bio_driver1 = NULL; 59260114438SPawel Jakub Dawidek bp->bio_driver2 = NULL; 59360114438SPawel Jakub Dawidek bp->bio_pflags = 0; 594801bb689SPoul-Henning Kamp g_io_request(bp, cp); 5953432e4fdSPoul-Henning Kamp pace++; 5963432e4fdSPoul-Henning Kamp return; 5973432e4fdSPoul-Henning Kamp } 598dd84a43cSPoul-Henning Kamp 599*ee75e7deSKonstantin Belousov SYSCTL_DECL(_kern_geom); 600*ee75e7deSKonstantin Belousov 601*ee75e7deSKonstantin Belousov static long transient_maps; 602*ee75e7deSKonstantin Belousov SYSCTL_LONG(_kern_geom, OID_AUTO, transient_maps, CTLFLAG_RD, 603*ee75e7deSKonstantin Belousov &transient_maps, 0, 604*ee75e7deSKonstantin Belousov "Total count of the transient mapping requests"); 605*ee75e7deSKonstantin Belousov u_int transient_map_retries = 10; 606*ee75e7deSKonstantin Belousov SYSCTL_UINT(_kern_geom, OID_AUTO, transient_map_retries, CTLFLAG_RW, 607*ee75e7deSKonstantin Belousov &transient_map_retries, 0, 608*ee75e7deSKonstantin Belousov "Max count of retries used before giving up on creating transient map"); 609*ee75e7deSKonstantin Belousov int transient_map_hard_failures; 610*ee75e7deSKonstantin Belousov SYSCTL_INT(_kern_geom, OID_AUTO, transient_map_hard_failures, CTLFLAG_RD, 611*ee75e7deSKonstantin Belousov &transient_map_hard_failures, 0, 612*ee75e7deSKonstantin Belousov "Failures to establish the transient mapping due to retry attempts " 613*ee75e7deSKonstantin Belousov "exhausted"); 614*ee75e7deSKonstantin Belousov int transient_map_soft_failures; 615*ee75e7deSKonstantin Belousov SYSCTL_INT(_kern_geom, OID_AUTO, transient_map_soft_failures, CTLFLAG_RD, 616*ee75e7deSKonstantin Belousov &transient_map_soft_failures, 0, 617*ee75e7deSKonstantin Belousov "Count of retried failures to establish the transient mapping"); 618*ee75e7deSKonstantin Belousov int inflight_transient_maps; 619*ee75e7deSKonstantin Belousov SYSCTL_INT(_kern_geom, OID_AUTO, inflight_transient_maps, CTLFLAG_RD, 620*ee75e7deSKonstantin Belousov &inflight_transient_maps, 0, 621*ee75e7deSKonstantin Belousov "Current count of the active transient maps"); 622*ee75e7deSKonstantin Belousov 623*ee75e7deSKonstantin Belousov static int 624*ee75e7deSKonstantin Belousov g_io_transient_map_bio(struct bio *bp) 625*ee75e7deSKonstantin Belousov { 626*ee75e7deSKonstantin Belousov vm_offset_t addr; 627*ee75e7deSKonstantin Belousov long size; 628*ee75e7deSKonstantin Belousov u_int retried; 629*ee75e7deSKonstantin Belousov int rv; 630*ee75e7deSKonstantin Belousov 631*ee75e7deSKonstantin Belousov size = round_page(bp->bio_ma_offset + bp->bio_length); 632*ee75e7deSKonstantin Belousov KASSERT(size / PAGE_SIZE == bp->bio_ma_n, ("Bio too short %p", bp)); 633*ee75e7deSKonstantin Belousov addr = 0; 634*ee75e7deSKonstantin Belousov retried = 0; 635*ee75e7deSKonstantin Belousov atomic_add_long(&transient_maps, 1); 636*ee75e7deSKonstantin Belousov retry: 637*ee75e7deSKonstantin Belousov vm_map_lock(bio_transient_map); 638*ee75e7deSKonstantin Belousov if (vm_map_findspace(bio_transient_map, vm_map_min(bio_transient_map), 639*ee75e7deSKonstantin Belousov size, &addr)) { 640*ee75e7deSKonstantin Belousov vm_map_unlock(bio_transient_map); 641*ee75e7deSKonstantin Belousov if (transient_map_retries != 0 && 642*ee75e7deSKonstantin Belousov retried >= transient_map_retries) { 643*ee75e7deSKonstantin Belousov g_io_deliver(bp, EDEADLK/* XXXKIB */); 644*ee75e7deSKonstantin Belousov CTR2(KTR_GEOM, "g_down cannot map bp %p provider %s", 645*ee75e7deSKonstantin Belousov bp, bp->bio_to->name); 646*ee75e7deSKonstantin Belousov atomic_add_int(&transient_map_hard_failures, 1); 647*ee75e7deSKonstantin Belousov return (1); 648*ee75e7deSKonstantin Belousov } else { 649*ee75e7deSKonstantin Belousov /* 650*ee75e7deSKonstantin Belousov * Naive attempt to quisce the I/O to get more 651*ee75e7deSKonstantin Belousov * in-flight requests completed and defragment 652*ee75e7deSKonstantin Belousov * the bio_transient_map. 653*ee75e7deSKonstantin Belousov */ 654*ee75e7deSKonstantin Belousov CTR3(KTR_GEOM, "g_down retrymap bp %p provider %s r %d", 655*ee75e7deSKonstantin Belousov bp, bp->bio_to->name, retried); 656*ee75e7deSKonstantin Belousov pause("g_d_tra", hz / 10); 657*ee75e7deSKonstantin Belousov retried++; 658*ee75e7deSKonstantin Belousov atomic_add_int(&transient_map_soft_failures, 1); 659*ee75e7deSKonstantin Belousov goto retry; 660*ee75e7deSKonstantin Belousov } 661*ee75e7deSKonstantin Belousov } 662*ee75e7deSKonstantin Belousov rv = vm_map_insert(bio_transient_map, NULL, 0, addr, addr + size, 663*ee75e7deSKonstantin Belousov VM_PROT_RW, VM_PROT_RW, MAP_NOFAULT); 664*ee75e7deSKonstantin Belousov KASSERT(rv == KERN_SUCCESS, 665*ee75e7deSKonstantin Belousov ("vm_map_insert(bio_transient_map) rv %d %jx %lx", 666*ee75e7deSKonstantin Belousov rv, (uintmax_t)addr, size)); 667*ee75e7deSKonstantin Belousov vm_map_unlock(bio_transient_map); 668*ee75e7deSKonstantin Belousov atomic_add_int(&inflight_transient_maps, 1); 669*ee75e7deSKonstantin Belousov pmap_qenter((vm_offset_t)addr, bp->bio_ma, OFF_TO_IDX(size)); 670*ee75e7deSKonstantin Belousov bp->bio_data = (caddr_t)addr + bp->bio_ma_offset; 671*ee75e7deSKonstantin Belousov bp->bio_flags |= BIO_TRANSIENT_MAPPING; 672*ee75e7deSKonstantin Belousov bp->bio_flags &= ~BIO_UNMAPPED; 673*ee75e7deSKonstantin Belousov return (0); 674*ee75e7deSKonstantin Belousov } 675*ee75e7deSKonstantin Belousov 676dd84a43cSPoul-Henning Kamp void 677dd84a43cSPoul-Henning Kamp g_io_schedule_down(struct thread *tp __unused) 678dd84a43cSPoul-Henning Kamp { 679dd84a43cSPoul-Henning Kamp struct bio *bp; 680e39d70d4SPoul-Henning Kamp off_t excess; 681e39d70d4SPoul-Henning Kamp int error; 682dd84a43cSPoul-Henning Kamp 683dd84a43cSPoul-Henning Kamp for(;;) { 684f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 685dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_down); 686f0e185d7SPoul-Henning Kamp if (bp == NULL) { 68749dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down going to sleep"); 688f0e185d7SPoul-Henning Kamp msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock, 6897fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 690f0e185d7SPoul-Henning Kamp continue; 691f0e185d7SPoul-Henning Kamp } 69249dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down has work to do"); 693f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 694376ceb79SPoul-Henning Kamp if (pace > 0) { 69549dbb61dSRobert Watson CTR1(KTR_GEOM, "g_down pacing self (pace %d)", pace); 6964d70511aSJohn Baldwin pause("g_down", hz/10); 697376ceb79SPoul-Henning Kamp pace--; 698376ceb79SPoul-Henning Kamp } 699e39d70d4SPoul-Henning Kamp error = g_io_check(bp); 700e39d70d4SPoul-Henning Kamp if (error) { 70149dbb61dSRobert Watson CTR3(KTR_GEOM, "g_down g_io_check on bp %p provider " 70249dbb61dSRobert Watson "%s returned %d", bp, bp->bio_to->name, error); 703e39d70d4SPoul-Henning Kamp g_io_deliver(bp, error); 704e39d70d4SPoul-Henning Kamp continue; 705e39d70d4SPoul-Henning Kamp } 70649dbb61dSRobert Watson CTR2(KTR_GEOM, "g_down processing bp %p provider %s", bp, 70749dbb61dSRobert Watson bp->bio_to->name); 708392d56b4SPoul-Henning Kamp switch (bp->bio_cmd) { 709392d56b4SPoul-Henning Kamp case BIO_READ: 710392d56b4SPoul-Henning Kamp case BIO_WRITE: 711392d56b4SPoul-Henning Kamp case BIO_DELETE: 712e39d70d4SPoul-Henning Kamp /* Truncate requests to the end of providers media. */ 71349dbb61dSRobert Watson /* 71449dbb61dSRobert Watson * XXX: What if we truncate because of offset being 71549dbb61dSRobert Watson * bad, not length? 71649dbb61dSRobert Watson */ 717e39d70d4SPoul-Henning Kamp excess = bp->bio_offset + bp->bio_length; 718e39d70d4SPoul-Henning Kamp if (excess > bp->bio_to->mediasize) { 719e39d70d4SPoul-Henning Kamp excess -= bp->bio_to->mediasize; 720e39d70d4SPoul-Henning Kamp bp->bio_length -= excess; 72149dbb61dSRobert Watson if (excess > 0) 72249dbb61dSRobert Watson CTR3(KTR_GEOM, "g_down truncated bio " 72349dbb61dSRobert Watson "%p provider %s by %d", bp, 72449dbb61dSRobert Watson bp->bio_to->name, excess); 725e39d70d4SPoul-Henning Kamp } 726e39d70d4SPoul-Henning Kamp /* Deliver zero length transfers right here. */ 727e39d70d4SPoul-Henning Kamp if (bp->bio_length == 0) { 728e39d70d4SPoul-Henning Kamp g_io_deliver(bp, 0); 72949dbb61dSRobert Watson CTR2(KTR_GEOM, "g_down terminated 0-length " 73049dbb61dSRobert Watson "bp %p provider %s", bp, bp->bio_to->name); 731e39d70d4SPoul-Henning Kamp continue; 732e39d70d4SPoul-Henning Kamp } 733392d56b4SPoul-Henning Kamp break; 734392d56b4SPoul-Henning Kamp default: 735392d56b4SPoul-Henning Kamp break; 736392d56b4SPoul-Henning Kamp } 737*ee75e7deSKonstantin Belousov if ((bp->bio_flags & BIO_UNMAPPED) != 0 && 738*ee75e7deSKonstantin Belousov (bp->bio_to->flags & G_PF_ACCEPT_UNMAPPED) == 0 && 739*ee75e7deSKonstantin Belousov (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE)) { 740*ee75e7deSKonstantin Belousov if (g_io_transient_map_bio(bp)) 741*ee75e7deSKonstantin Belousov continue; 742*ee75e7deSKonstantin Belousov } 74351460da8SJohn Baldwin THREAD_NO_SLEEPING(); 74449dbb61dSRobert Watson CTR4(KTR_GEOM, "g_down starting bp %p provider %s off %ld " 74549dbb61dSRobert Watson "len %ld", bp, bp->bio_to->name, bp->bio_offset, 74649dbb61dSRobert Watson bp->bio_length); 747dd84a43cSPoul-Henning Kamp bp->bio_to->geom->start(bp); 74851460da8SJohn Baldwin THREAD_SLEEPING_OK(); 749dd84a43cSPoul-Henning Kamp } 750dd84a43cSPoul-Henning Kamp } 751dd84a43cSPoul-Henning Kamp 752dd84a43cSPoul-Henning Kamp void 7535fcf4e43SPoul-Henning Kamp bio_taskqueue(struct bio *bp, bio_task_t *func, void *arg) 7545fcf4e43SPoul-Henning Kamp { 7555fcf4e43SPoul-Henning Kamp bp->bio_task = func; 7565fcf4e43SPoul-Henning Kamp bp->bio_task_arg = arg; 7575fcf4e43SPoul-Henning Kamp /* 7585fcf4e43SPoul-Henning Kamp * The taskqueue is actually just a second queue off the "up" 7595fcf4e43SPoul-Henning Kamp * queue, so we use the same lock. 7605fcf4e43SPoul-Henning Kamp */ 7615fcf4e43SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 762dcbd0fe5SPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 763dcbd0fe5SPoul-Henning Kamp ("Bio already on queue bp=%p target taskq", bp)); 764dcbd0fe5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 7655fcf4e43SPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_task.bio_queue, bp, bio_queue); 7665fcf4e43SPoul-Henning Kamp g_bio_run_task.bio_queue_length++; 7675fcf4e43SPoul-Henning Kamp wakeup(&g_wait_up); 7685fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 7695fcf4e43SPoul-Henning Kamp } 7705fcf4e43SPoul-Henning Kamp 7715fcf4e43SPoul-Henning Kamp 7725fcf4e43SPoul-Henning Kamp void 773dd84a43cSPoul-Henning Kamp g_io_schedule_up(struct thread *tp __unused) 774dd84a43cSPoul-Henning Kamp { 775dd84a43cSPoul-Henning Kamp struct bio *bp; 776dd84a43cSPoul-Henning Kamp for(;;) { 777f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 7785fcf4e43SPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_task); 7795fcf4e43SPoul-Henning Kamp if (bp != NULL) { 7805fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 78151460da8SJohn Baldwin THREAD_NO_SLEEPING(); 78249dbb61dSRobert Watson CTR1(KTR_GEOM, "g_up processing task bp %p", bp); 7835fcf4e43SPoul-Henning Kamp bp->bio_task(bp->bio_task_arg); 78451460da8SJohn Baldwin THREAD_SLEEPING_OK(); 7855fcf4e43SPoul-Henning Kamp continue; 7865fcf4e43SPoul-Henning Kamp } 787dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_up); 788f0e185d7SPoul-Henning Kamp if (bp != NULL) { 789f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 79051460da8SJohn Baldwin THREAD_NO_SLEEPING(); 79149dbb61dSRobert Watson CTR4(KTR_GEOM, "g_up biodone bp %p provider %s off " 792c4901b67SSean Bruno "%jd len %ld", bp, bp->bio_to->name, 79349dbb61dSRobert Watson bp->bio_offset, bp->bio_length); 79453706245SPoul-Henning Kamp biodone(bp); 79551460da8SJohn Baldwin THREAD_SLEEPING_OK(); 796f0e185d7SPoul-Henning Kamp continue; 797f0e185d7SPoul-Henning Kamp } 79849dbb61dSRobert Watson CTR0(KTR_GEOM, "g_up going to sleep"); 799f0e185d7SPoul-Henning Kamp msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock, 8007fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 801dd84a43cSPoul-Henning Kamp } 802dd84a43cSPoul-Henning Kamp } 803dd84a43cSPoul-Henning Kamp 804dd84a43cSPoul-Henning Kamp void * 805dd84a43cSPoul-Henning Kamp g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 806dd84a43cSPoul-Henning Kamp { 807dd84a43cSPoul-Henning Kamp struct bio *bp; 808dd84a43cSPoul-Henning Kamp void *ptr; 809dd84a43cSPoul-Henning Kamp int errorc; 810dd84a43cSPoul-Henning Kamp 8118dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 8128dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_read_data(): invalid length %jd", 8138dd5480dSPawel Jakub Dawidek (intmax_t)length)); 8143eb6ffdfSPoul-Henning Kamp 815a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 816dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_READ; 817dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 818dd84a43cSPoul-Henning Kamp bp->bio_offset = offset; 819dd84a43cSPoul-Henning Kamp bp->bio_length = length; 820a163d034SWarner Losh ptr = g_malloc(length, M_WAITOK); 821dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 822dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 82353706245SPoul-Henning Kamp errorc = biowait(bp, "gread"); 824dd84a43cSPoul-Henning Kamp if (error != NULL) 825dd84a43cSPoul-Henning Kamp *error = errorc; 826dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 827dd84a43cSPoul-Henning Kamp if (errorc) { 828dd84a43cSPoul-Henning Kamp g_free(ptr); 829dd84a43cSPoul-Henning Kamp ptr = NULL; 830dd84a43cSPoul-Henning Kamp } 831dd84a43cSPoul-Henning Kamp return (ptr); 832dd84a43cSPoul-Henning Kamp } 83390b1cd56SPoul-Henning Kamp 83490b1cd56SPoul-Henning Kamp int 83590b1cd56SPoul-Henning Kamp g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) 83690b1cd56SPoul-Henning Kamp { 83790b1cd56SPoul-Henning Kamp struct bio *bp; 83890b1cd56SPoul-Henning Kamp int error; 83990b1cd56SPoul-Henning Kamp 8408dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 8418dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_write_data(): invalid length %jd", 8428dd5480dSPawel Jakub Dawidek (intmax_t)length)); 8433eb6ffdfSPoul-Henning Kamp 844a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 84590b1cd56SPoul-Henning Kamp bp->bio_cmd = BIO_WRITE; 84690b1cd56SPoul-Henning Kamp bp->bio_done = NULL; 84790b1cd56SPoul-Henning Kamp bp->bio_offset = offset; 84890b1cd56SPoul-Henning Kamp bp->bio_length = length; 84990b1cd56SPoul-Henning Kamp bp->bio_data = ptr; 85090b1cd56SPoul-Henning Kamp g_io_request(bp, cp); 85190b1cd56SPoul-Henning Kamp error = biowait(bp, "gwrite"); 85290b1cd56SPoul-Henning Kamp g_destroy_bio(bp); 85390b1cd56SPoul-Henning Kamp return (error); 85490b1cd56SPoul-Henning Kamp } 85572e33095SPawel Jakub Dawidek 8562b17fb95SPawel Jakub Dawidek int 8572b17fb95SPawel Jakub Dawidek g_delete_data(struct g_consumer *cp, off_t offset, off_t length) 8582b17fb95SPawel Jakub Dawidek { 8592b17fb95SPawel Jakub Dawidek struct bio *bp; 8602b17fb95SPawel Jakub Dawidek int error; 8612b17fb95SPawel Jakub Dawidek 862eed6cda9SPoul-Henning Kamp KASSERT(length > 0 && length >= cp->provider->sectorsize, 863eed6cda9SPoul-Henning Kamp ("g_delete_data(): invalid length %jd", (intmax_t)length)); 8642b17fb95SPawel Jakub Dawidek 8652b17fb95SPawel Jakub Dawidek bp = g_alloc_bio(); 8662b17fb95SPawel Jakub Dawidek bp->bio_cmd = BIO_DELETE; 8672b17fb95SPawel Jakub Dawidek bp->bio_done = NULL; 8682b17fb95SPawel Jakub Dawidek bp->bio_offset = offset; 8692b17fb95SPawel Jakub Dawidek bp->bio_length = length; 8702b17fb95SPawel Jakub Dawidek bp->bio_data = NULL; 8712b17fb95SPawel Jakub Dawidek g_io_request(bp, cp); 8722b17fb95SPawel Jakub Dawidek error = biowait(bp, "gdelete"); 8732b17fb95SPawel Jakub Dawidek g_destroy_bio(bp); 8742b17fb95SPawel Jakub Dawidek return (error); 8752b17fb95SPawel Jakub Dawidek } 8762b17fb95SPawel Jakub Dawidek 87772e33095SPawel Jakub Dawidek void 87872e33095SPawel Jakub Dawidek g_print_bio(struct bio *bp) 87972e33095SPawel Jakub Dawidek { 88072e33095SPawel Jakub Dawidek const char *pname, *cmd = NULL; 88172e33095SPawel Jakub Dawidek 88272e33095SPawel Jakub Dawidek if (bp->bio_to != NULL) 88372e33095SPawel Jakub Dawidek pname = bp->bio_to->name; 88472e33095SPawel Jakub Dawidek else 88572e33095SPawel Jakub Dawidek pname = "[unknown]"; 88672e33095SPawel Jakub Dawidek 88772e33095SPawel Jakub Dawidek switch (bp->bio_cmd) { 88872e33095SPawel Jakub Dawidek case BIO_GETATTR: 88972e33095SPawel Jakub Dawidek cmd = "GETATTR"; 89072e33095SPawel Jakub Dawidek printf("%s[%s(attr=%s)]", pname, cmd, bp->bio_attribute); 89172e33095SPawel Jakub Dawidek return; 892c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 893c3618c65SPawel Jakub Dawidek cmd = "FLUSH"; 894c3618c65SPawel Jakub Dawidek printf("%s[%s]", pname, cmd); 895c3618c65SPawel Jakub Dawidek return; 89672e33095SPawel Jakub Dawidek case BIO_READ: 89772e33095SPawel Jakub Dawidek cmd = "READ"; 8987ce513a5SEdward Tomasz Napierala break; 89972e33095SPawel Jakub Dawidek case BIO_WRITE: 90072e33095SPawel Jakub Dawidek cmd = "WRITE"; 9017ce513a5SEdward Tomasz Napierala break; 90272e33095SPawel Jakub Dawidek case BIO_DELETE: 90372e33095SPawel Jakub Dawidek cmd = "DELETE"; 9047ce513a5SEdward Tomasz Napierala break; 90572e33095SPawel Jakub Dawidek default: 90672e33095SPawel Jakub Dawidek cmd = "UNKNOWN"; 90772e33095SPawel Jakub Dawidek printf("%s[%s()]", pname, cmd); 90872e33095SPawel Jakub Dawidek return; 90972e33095SPawel Jakub Dawidek } 9107ce513a5SEdward Tomasz Napierala printf("%s[%s(offset=%jd, length=%jd)]", pname, cmd, 9117ce513a5SEdward Tomasz Napierala (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 91272e33095SPawel Jakub Dawidek } 913