1dd84a43cSPoul-Henning Kamp /*- 2dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Poul-Henning Kamp 3dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. 4ee75e7deSKonstantin 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 * 12ee75e7deSKonstantin Belousov * Portions of this software were developed by Konstantin Belousov 13ee75e7deSKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 14ee75e7deSKonstantin 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> 51ee75e7deSKonstantin Belousov #include <sys/sysctl.h> 525f518366SJeff Roberson #include <sys/vmem.h> 53dd84a43cSPoul-Henning Kamp 54dd84a43cSPoul-Henning Kamp #include <sys/errno.h> 55dd84a43cSPoul-Henning Kamp #include <geom/geom.h> 56b1876192SPoul-Henning Kamp #include <geom/geom_int.h> 57e24cbd90SPoul-Henning Kamp #include <sys/devicestat.h> 58dd84a43cSPoul-Henning Kamp 595ffb2c8bSPoul-Henning Kamp #include <vm/uma.h> 60ee75e7deSKonstantin Belousov #include <vm/vm.h> 61ee75e7deSKonstantin Belousov #include <vm/vm_param.h> 62ee75e7deSKonstantin Belousov #include <vm/vm_kern.h> 63ee75e7deSKonstantin Belousov #include <vm/vm_page.h> 64ee75e7deSKonstantin Belousov #include <vm/vm_object.h> 65ee75e7deSKonstantin Belousov #include <vm/vm_extern.h> 66ee75e7deSKonstantin Belousov #include <vm/vm_map.h> 675ffb2c8bSPoul-Henning Kamp 68*40ea77a0SAlexander Motin static int g_io_transient_map_bio(struct bio *bp); 69*40ea77a0SAlexander Motin 70dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_down; 71dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_up; 725fcf4e43SPoul-Henning Kamp static struct g_bioq g_bio_run_task; 73dd84a43cSPoul-Henning Kamp 743432e4fdSPoul-Henning Kamp static u_int pace; 755ffb2c8bSPoul-Henning Kamp static uma_zone_t biozone; 763432e4fdSPoul-Henning Kamp 776231f75bSLuigi Rizzo /* 786231f75bSLuigi Rizzo * The head of the list of classifiers used in g_io_request. 796231f75bSLuigi Rizzo * Use g_register_classifier() and g_unregister_classifier() 806231f75bSLuigi Rizzo * to add/remove entries to the list. 816231f75bSLuigi Rizzo * Classifiers are invoked in registration order. 826231f75bSLuigi Rizzo */ 836231f75bSLuigi Rizzo static TAILQ_HEAD(g_classifier_tailq, g_classifier_hook) 846231f75bSLuigi Rizzo g_classifier_tailq = TAILQ_HEAD_INITIALIZER(g_classifier_tailq); 856231f75bSLuigi Rizzo 86dd84a43cSPoul-Henning Kamp #include <machine/atomic.h> 87dd84a43cSPoul-Henning Kamp 88dd84a43cSPoul-Henning Kamp static void 89dd84a43cSPoul-Henning Kamp g_bioq_lock(struct g_bioq *bq) 90dd84a43cSPoul-Henning Kamp { 91dd84a43cSPoul-Henning Kamp 92dd84a43cSPoul-Henning Kamp mtx_lock(&bq->bio_queue_lock); 93dd84a43cSPoul-Henning Kamp } 94dd84a43cSPoul-Henning Kamp 95dd84a43cSPoul-Henning Kamp static void 96dd84a43cSPoul-Henning Kamp g_bioq_unlock(struct g_bioq *bq) 97dd84a43cSPoul-Henning Kamp { 98dd84a43cSPoul-Henning Kamp 99dd84a43cSPoul-Henning Kamp mtx_unlock(&bq->bio_queue_lock); 100dd84a43cSPoul-Henning Kamp } 101dd84a43cSPoul-Henning Kamp 102dd84a43cSPoul-Henning Kamp #if 0 103dd84a43cSPoul-Henning Kamp static void 104dd84a43cSPoul-Henning Kamp g_bioq_destroy(struct g_bioq *bq) 105dd84a43cSPoul-Henning Kamp { 106dd84a43cSPoul-Henning Kamp 107dd84a43cSPoul-Henning Kamp mtx_destroy(&bq->bio_queue_lock); 108dd84a43cSPoul-Henning Kamp } 109dd84a43cSPoul-Henning Kamp #endif 110dd84a43cSPoul-Henning Kamp 111dd84a43cSPoul-Henning Kamp static void 112dd84a43cSPoul-Henning Kamp g_bioq_init(struct g_bioq *bq) 113dd84a43cSPoul-Henning Kamp { 114dd84a43cSPoul-Henning Kamp 115dd84a43cSPoul-Henning Kamp TAILQ_INIT(&bq->bio_queue); 1166008862bSJohn Baldwin mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF); 117dd84a43cSPoul-Henning Kamp } 118dd84a43cSPoul-Henning Kamp 119dd84a43cSPoul-Henning Kamp static struct bio * 120dd84a43cSPoul-Henning Kamp g_bioq_first(struct g_bioq *bq) 121dd84a43cSPoul-Henning Kamp { 122dd84a43cSPoul-Henning Kamp struct bio *bp; 123dd84a43cSPoul-Henning Kamp 124dd84a43cSPoul-Henning Kamp bp = TAILQ_FIRST(&bq->bio_queue); 125dd84a43cSPoul-Henning Kamp if (bp != NULL) { 126dcbd0fe5SPoul-Henning Kamp KASSERT((bp->bio_flags & BIO_ONQUEUE), 127dcbd0fe5SPoul-Henning Kamp ("Bio not on queue bp=%p target %p", bp, bq)); 128dcbd0fe5SPoul-Henning Kamp bp->bio_flags &= ~BIO_ONQUEUE; 129dd84a43cSPoul-Henning Kamp TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue); 130dd84a43cSPoul-Henning Kamp bq->bio_queue_length--; 131dd84a43cSPoul-Henning Kamp } 132dd84a43cSPoul-Henning Kamp return (bp); 133dd84a43cSPoul-Henning Kamp } 134dd84a43cSPoul-Henning Kamp 135dd84a43cSPoul-Henning Kamp struct bio * 136dd84a43cSPoul-Henning Kamp g_new_bio(void) 137dd84a43cSPoul-Henning Kamp { 138dd84a43cSPoul-Henning Kamp struct bio *bp; 139dd84a43cSPoul-Henning Kamp 1405ffb2c8bSPoul-Henning Kamp bp = uma_zalloc(biozone, M_NOWAIT | M_ZERO); 1413b378147SPawel Jakub Dawidek #ifdef KTR 142b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1433b378147SPawel Jakub Dawidek struct stack st; 1443b378147SPawel Jakub Dawidek 1453b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_new_bio(): %p", bp); 1463b378147SPawel Jakub Dawidek stack_save(&st); 1473b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1483b378147SPawel Jakub Dawidek } 1493b378147SPawel Jakub Dawidek #endif 150dd84a43cSPoul-Henning Kamp return (bp); 151dd84a43cSPoul-Henning Kamp } 152dd84a43cSPoul-Henning Kamp 153a2033c96SPoul-Henning Kamp struct bio * 154a2033c96SPoul-Henning Kamp g_alloc_bio(void) 155a2033c96SPoul-Henning Kamp { 156a2033c96SPoul-Henning Kamp struct bio *bp; 157a2033c96SPoul-Henning Kamp 158a2033c96SPoul-Henning Kamp bp = uma_zalloc(biozone, M_WAITOK | M_ZERO); 1593b378147SPawel Jakub Dawidek #ifdef KTR 160b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1613b378147SPawel Jakub Dawidek struct stack st; 1623b378147SPawel Jakub Dawidek 1633b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_alloc_bio(): %p", bp); 1643b378147SPawel Jakub Dawidek stack_save(&st); 1653b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1663b378147SPawel Jakub Dawidek } 1673b378147SPawel Jakub Dawidek #endif 168a2033c96SPoul-Henning Kamp return (bp); 169a2033c96SPoul-Henning Kamp } 170a2033c96SPoul-Henning Kamp 171dd84a43cSPoul-Henning Kamp void 172dd84a43cSPoul-Henning Kamp g_destroy_bio(struct bio *bp) 173dd84a43cSPoul-Henning Kamp { 1743b378147SPawel Jakub Dawidek #ifdef KTR 175b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1763b378147SPawel Jakub Dawidek struct stack st; 177dd84a43cSPoul-Henning Kamp 1783b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_destroy_bio(): %p", bp); 1793b378147SPawel Jakub Dawidek stack_save(&st); 1803b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1813b378147SPawel Jakub Dawidek } 1823b378147SPawel Jakub Dawidek #endif 1835ffb2c8bSPoul-Henning Kamp uma_zfree(biozone, bp); 184dd84a43cSPoul-Henning Kamp } 185dd84a43cSPoul-Henning Kamp 186dd84a43cSPoul-Henning Kamp struct bio * 187dd84a43cSPoul-Henning Kamp g_clone_bio(struct bio *bp) 188dd84a43cSPoul-Henning Kamp { 189dd84a43cSPoul-Henning Kamp struct bio *bp2; 190dd84a43cSPoul-Henning Kamp 1915ffb2c8bSPoul-Henning Kamp bp2 = uma_zalloc(biozone, M_NOWAIT | M_ZERO); 192a1bd3ee2SPoul-Henning Kamp if (bp2 != NULL) { 193936cc461SPoul-Henning Kamp bp2->bio_parent = bp; 194dd84a43cSPoul-Henning Kamp bp2->bio_cmd = bp->bio_cmd; 19582a6ae10SJim Harris /* 19682a6ae10SJim Harris * BIO_ORDERED flag may be used by disk drivers to enforce 19782a6ae10SJim Harris * ordering restrictions, so this flag needs to be cloned. 198ee75e7deSKonstantin Belousov * BIO_UNMAPPED should be inherited, to properly indicate 199ee75e7deSKonstantin Belousov * which way the buffer is passed. 20082a6ae10SJim Harris * Other bio flags are not suitable for cloning. 20182a6ae10SJim Harris */ 202ee75e7deSKonstantin Belousov bp2->bio_flags = bp->bio_flags & (BIO_ORDERED | BIO_UNMAPPED); 203dd84a43cSPoul-Henning Kamp bp2->bio_length = bp->bio_length; 204dd84a43cSPoul-Henning Kamp bp2->bio_offset = bp->bio_offset; 205dd84a43cSPoul-Henning Kamp bp2->bio_data = bp->bio_data; 206ee75e7deSKonstantin Belousov bp2->bio_ma = bp->bio_ma; 207ee75e7deSKonstantin Belousov bp2->bio_ma_n = bp->bio_ma_n; 208ee75e7deSKonstantin Belousov bp2->bio_ma_offset = bp->bio_ma_offset; 209dd84a43cSPoul-Henning Kamp bp2->bio_attribute = bp->bio_attribute; 2106231f75bSLuigi Rizzo /* Inherit classification info from the parent */ 2116231f75bSLuigi Rizzo bp2->bio_classifier1 = bp->bio_classifier1; 2126231f75bSLuigi Rizzo bp2->bio_classifier2 = bp->bio_classifier2; 213801bb689SPoul-Henning Kamp bp->bio_children++; 214a1bd3ee2SPoul-Henning Kamp } 2153b378147SPawel Jakub Dawidek #ifdef KTR 216b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 2173b378147SPawel Jakub Dawidek struct stack st; 2183b378147SPawel Jakub Dawidek 219ad572235SRuslan Ermilov CTR2(KTR_GEOM, "g_clone_bio(%p): %p", bp, bp2); 2203b378147SPawel Jakub Dawidek stack_save(&st); 2213b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 2223b378147SPawel Jakub Dawidek } 2233b378147SPawel Jakub Dawidek #endif 224dd84a43cSPoul-Henning Kamp return(bp2); 225dd84a43cSPoul-Henning Kamp } 226dd84a43cSPoul-Henning Kamp 2274bec0ff1SPawel Jakub Dawidek struct bio * 2284bec0ff1SPawel Jakub Dawidek g_duplicate_bio(struct bio *bp) 2294bec0ff1SPawel Jakub Dawidek { 2304bec0ff1SPawel Jakub Dawidek struct bio *bp2; 2314bec0ff1SPawel Jakub Dawidek 2324bec0ff1SPawel Jakub Dawidek bp2 = uma_zalloc(biozone, M_WAITOK | M_ZERO); 233ee75e7deSKonstantin Belousov bp2->bio_flags = bp->bio_flags & BIO_UNMAPPED; 2344bec0ff1SPawel Jakub Dawidek bp2->bio_parent = bp; 2354bec0ff1SPawel Jakub Dawidek bp2->bio_cmd = bp->bio_cmd; 2364bec0ff1SPawel Jakub Dawidek bp2->bio_length = bp->bio_length; 2374bec0ff1SPawel Jakub Dawidek bp2->bio_offset = bp->bio_offset; 2384bec0ff1SPawel Jakub Dawidek bp2->bio_data = bp->bio_data; 239ee75e7deSKonstantin Belousov bp2->bio_ma = bp->bio_ma; 240ee75e7deSKonstantin Belousov bp2->bio_ma_n = bp->bio_ma_n; 241ee75e7deSKonstantin Belousov bp2->bio_ma_offset = bp->bio_ma_offset; 2424bec0ff1SPawel Jakub Dawidek bp2->bio_attribute = bp->bio_attribute; 2434bec0ff1SPawel Jakub Dawidek bp->bio_children++; 2444bec0ff1SPawel Jakub Dawidek #ifdef KTR 245b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 2464bec0ff1SPawel Jakub Dawidek struct stack st; 2474bec0ff1SPawel Jakub Dawidek 2484bec0ff1SPawel Jakub Dawidek CTR2(KTR_GEOM, "g_duplicate_bio(%p): %p", bp, bp2); 2494bec0ff1SPawel Jakub Dawidek stack_save(&st); 2504bec0ff1SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 2514bec0ff1SPawel Jakub Dawidek } 2524bec0ff1SPawel Jakub Dawidek #endif 2534bec0ff1SPawel Jakub Dawidek return(bp2); 2544bec0ff1SPawel Jakub Dawidek } 2554bec0ff1SPawel Jakub Dawidek 256dd84a43cSPoul-Henning Kamp void 257dd84a43cSPoul-Henning Kamp g_io_init() 258dd84a43cSPoul-Henning Kamp { 259dd84a43cSPoul-Henning Kamp 260dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_down); 261dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_up); 2625fcf4e43SPoul-Henning Kamp g_bioq_init(&g_bio_run_task); 2635ffb2c8bSPoul-Henning Kamp biozone = uma_zcreate("g_bio", sizeof (struct bio), 2645ffb2c8bSPoul-Henning Kamp NULL, NULL, 2655ffb2c8bSPoul-Henning Kamp NULL, NULL, 2665ffb2c8bSPoul-Henning Kamp 0, 0); 267dd84a43cSPoul-Henning Kamp } 268dd84a43cSPoul-Henning Kamp 269dd84a43cSPoul-Henning Kamp int 2700d3f37a8SPoul-Henning Kamp g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 271dd84a43cSPoul-Henning Kamp { 272dd84a43cSPoul-Henning Kamp struct bio *bp; 273dd84a43cSPoul-Henning Kamp int error; 274dd84a43cSPoul-Henning Kamp 275dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, "bio_getattr(%s)", attr); 276a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 277dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_GETATTR; 278dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 279dd84a43cSPoul-Henning Kamp bp->bio_attribute = attr; 280dd84a43cSPoul-Henning Kamp bp->bio_length = *len; 281dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 282dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 28353706245SPoul-Henning Kamp error = biowait(bp, "ggetattr"); 284dd84a43cSPoul-Henning Kamp *len = bp->bio_completed; 285dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 286dd84a43cSPoul-Henning Kamp return (error); 287dd84a43cSPoul-Henning Kamp } 288dd84a43cSPoul-Henning Kamp 289c3618c65SPawel Jakub Dawidek int 290c3618c65SPawel Jakub Dawidek g_io_flush(struct g_consumer *cp) 291c3618c65SPawel Jakub Dawidek { 292c3618c65SPawel Jakub Dawidek struct bio *bp; 293c3618c65SPawel Jakub Dawidek int error; 294c3618c65SPawel Jakub Dawidek 295c3618c65SPawel Jakub Dawidek g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name); 296c3618c65SPawel Jakub Dawidek bp = g_alloc_bio(); 297c3618c65SPawel Jakub Dawidek bp->bio_cmd = BIO_FLUSH; 298f03f7a0cSJustin T. Gibbs bp->bio_flags |= BIO_ORDERED; 299c3618c65SPawel Jakub Dawidek bp->bio_done = NULL; 300c3618c65SPawel Jakub Dawidek bp->bio_attribute = NULL; 301c3618c65SPawel Jakub Dawidek bp->bio_offset = cp->provider->mediasize; 302c3618c65SPawel Jakub Dawidek bp->bio_length = 0; 303c3618c65SPawel Jakub Dawidek bp->bio_data = NULL; 304c3618c65SPawel Jakub Dawidek g_io_request(bp, cp); 305c3618c65SPawel Jakub Dawidek error = biowait(bp, "gflush"); 306c3618c65SPawel Jakub Dawidek g_destroy_bio(bp); 307c3618c65SPawel Jakub Dawidek return (error); 308c3618c65SPawel Jakub Dawidek } 309c3618c65SPawel Jakub Dawidek 310e39d70d4SPoul-Henning Kamp static int 311e39d70d4SPoul-Henning Kamp g_io_check(struct bio *bp) 312e39d70d4SPoul-Henning Kamp { 313e39d70d4SPoul-Henning Kamp struct g_consumer *cp; 314e39d70d4SPoul-Henning Kamp struct g_provider *pp; 315*40ea77a0SAlexander Motin off_t excess; 316*40ea77a0SAlexander Motin int error; 317e39d70d4SPoul-Henning Kamp 318e39d70d4SPoul-Henning Kamp cp = bp->bio_from; 319e39d70d4SPoul-Henning Kamp pp = bp->bio_to; 320e39d70d4SPoul-Henning Kamp 321e39d70d4SPoul-Henning Kamp /* Fail if access counters dont allow the operation */ 322e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 323e39d70d4SPoul-Henning Kamp case BIO_READ: 324e39d70d4SPoul-Henning Kamp case BIO_GETATTR: 325e39d70d4SPoul-Henning Kamp if (cp->acr == 0) 326e39d70d4SPoul-Henning Kamp return (EPERM); 327e39d70d4SPoul-Henning Kamp break; 328e39d70d4SPoul-Henning Kamp case BIO_WRITE: 329e39d70d4SPoul-Henning Kamp case BIO_DELETE: 330c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 331e39d70d4SPoul-Henning Kamp if (cp->acw == 0) 332e39d70d4SPoul-Henning Kamp return (EPERM); 333e39d70d4SPoul-Henning Kamp break; 334e39d70d4SPoul-Henning Kamp default: 335e39d70d4SPoul-Henning Kamp return (EPERM); 336e39d70d4SPoul-Henning Kamp } 337e39d70d4SPoul-Henning Kamp /* if provider is marked for error, don't disturb. */ 338e39d70d4SPoul-Henning Kamp if (pp->error) 339e39d70d4SPoul-Henning Kamp return (pp->error); 3403631c638SAlexander Motin if (cp->flags & G_CF_ORPHAN) 3413631c638SAlexander Motin return (ENXIO); 342e39d70d4SPoul-Henning Kamp 343e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 344e39d70d4SPoul-Henning Kamp case BIO_READ: 345e39d70d4SPoul-Henning Kamp case BIO_WRITE: 346e39d70d4SPoul-Henning Kamp case BIO_DELETE: 3472a842317SAndriy Gapon /* Zero sectorsize or mediasize is probably a lack of media. */ 3482a842317SAndriy Gapon if (pp->sectorsize == 0 || pp->mediasize == 0) 34943bff1a7SPoul-Henning Kamp return (ENXIO); 350e39d70d4SPoul-Henning Kamp /* Reject I/O not on sector boundary */ 351e39d70d4SPoul-Henning Kamp if (bp->bio_offset % pp->sectorsize) 352e39d70d4SPoul-Henning Kamp return (EINVAL); 353e39d70d4SPoul-Henning Kamp /* Reject I/O not integral sector long */ 354e39d70d4SPoul-Henning Kamp if (bp->bio_length % pp->sectorsize) 355e39d70d4SPoul-Henning Kamp return (EINVAL); 356d1b8bf47SPoul-Henning Kamp /* Reject requests before or past the end of media. */ 357d1b8bf47SPoul-Henning Kamp if (bp->bio_offset < 0) 358d1b8bf47SPoul-Henning Kamp return (EIO); 359e39d70d4SPoul-Henning Kamp if (bp->bio_offset > pp->mediasize) 360e39d70d4SPoul-Henning Kamp return (EIO); 361*40ea77a0SAlexander Motin 362*40ea77a0SAlexander Motin /* Truncate requests to the end of providers media. */ 363*40ea77a0SAlexander Motin excess = bp->bio_offset + bp->bio_length; 364*40ea77a0SAlexander Motin if (excess > bp->bio_to->mediasize) { 365*40ea77a0SAlexander Motin KASSERT((bp->bio_flags & BIO_UNMAPPED) == 0 || 366*40ea77a0SAlexander Motin round_page(bp->bio_ma_offset + 367*40ea77a0SAlexander Motin bp->bio_length) / PAGE_SIZE == bp->bio_ma_n, 368*40ea77a0SAlexander Motin ("excess bio %p too short", bp)); 369*40ea77a0SAlexander Motin excess -= bp->bio_to->mediasize; 370*40ea77a0SAlexander Motin bp->bio_length -= excess; 371*40ea77a0SAlexander Motin if ((bp->bio_flags & BIO_UNMAPPED) != 0) { 372*40ea77a0SAlexander Motin bp->bio_ma_n = round_page(bp->bio_ma_offset + 373*40ea77a0SAlexander Motin bp->bio_length) / PAGE_SIZE; 374*40ea77a0SAlexander Motin } 375*40ea77a0SAlexander Motin if (excess > 0) 376*40ea77a0SAlexander Motin CTR3(KTR_GEOM, "g_down truncated bio " 377*40ea77a0SAlexander Motin "%p provider %s by %d", bp, 378*40ea77a0SAlexander Motin bp->bio_to->name, excess); 379*40ea77a0SAlexander Motin } 380*40ea77a0SAlexander Motin 381*40ea77a0SAlexander Motin /* Deliver zero length transfers right here. */ 382*40ea77a0SAlexander Motin if (bp->bio_length == 0) { 383*40ea77a0SAlexander Motin CTR2(KTR_GEOM, "g_down terminated 0-length " 384*40ea77a0SAlexander Motin "bp %p provider %s", bp, bp->bio_to->name); 385*40ea77a0SAlexander Motin return (0); 386*40ea77a0SAlexander Motin } 387*40ea77a0SAlexander Motin 388*40ea77a0SAlexander Motin if ((bp->bio_flags & BIO_UNMAPPED) != 0 && 389*40ea77a0SAlexander Motin (bp->bio_to->flags & G_PF_ACCEPT_UNMAPPED) == 0 && 390*40ea77a0SAlexander Motin (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE)) { 391*40ea77a0SAlexander Motin if ((error = g_io_transient_map_bio(bp)) >= 0) 392*40ea77a0SAlexander Motin return (error); 393*40ea77a0SAlexander Motin } 394e39d70d4SPoul-Henning Kamp break; 395e39d70d4SPoul-Henning Kamp default: 396e39d70d4SPoul-Henning Kamp break; 397e39d70d4SPoul-Henning Kamp } 398*40ea77a0SAlexander Motin return (EJUSTRETURN); 399e39d70d4SPoul-Henning Kamp } 400e39d70d4SPoul-Henning Kamp 4016231f75bSLuigi Rizzo /* 4026231f75bSLuigi Rizzo * bio classification support. 4036231f75bSLuigi Rizzo * 4046231f75bSLuigi Rizzo * g_register_classifier() and g_unregister_classifier() 4056231f75bSLuigi Rizzo * are used to add/remove a classifier from the list. 4066231f75bSLuigi Rizzo * The list is protected using the g_bio_run_down lock, 4076231f75bSLuigi Rizzo * because the classifiers are called in this path. 4086231f75bSLuigi Rizzo * 4096231f75bSLuigi Rizzo * g_io_request() passes bio's that are not already classified 4106231f75bSLuigi Rizzo * (i.e. those with bio_classifier1 == NULL) to g_run_classifiers(). 4116231f75bSLuigi Rizzo * Classifiers can store their result in the two fields 4126231f75bSLuigi Rizzo * bio_classifier1 and bio_classifier2. 4136231f75bSLuigi Rizzo * A classifier that updates one of the fields should 4146231f75bSLuigi Rizzo * return a non-zero value. 4156231f75bSLuigi Rizzo * If no classifier updates the field, g_run_classifiers() sets 4166231f75bSLuigi Rizzo * bio_classifier1 = BIO_NOTCLASSIFIED to avoid further calls. 4176231f75bSLuigi Rizzo */ 4186231f75bSLuigi Rizzo 4196231f75bSLuigi Rizzo int 4206231f75bSLuigi Rizzo g_register_classifier(struct g_classifier_hook *hook) 4216231f75bSLuigi Rizzo { 4226231f75bSLuigi Rizzo 4236231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 4246231f75bSLuigi Rizzo TAILQ_INSERT_TAIL(&g_classifier_tailq, hook, link); 4256231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 4266231f75bSLuigi Rizzo 4276231f75bSLuigi Rizzo return (0); 4286231f75bSLuigi Rizzo } 4296231f75bSLuigi Rizzo 4306231f75bSLuigi Rizzo void 4316231f75bSLuigi Rizzo g_unregister_classifier(struct g_classifier_hook *hook) 4326231f75bSLuigi Rizzo { 4336231f75bSLuigi Rizzo struct g_classifier_hook *entry; 4346231f75bSLuigi Rizzo 4356231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 4366231f75bSLuigi Rizzo TAILQ_FOREACH(entry, &g_classifier_tailq, link) { 4376231f75bSLuigi Rizzo if (entry == hook) { 4386231f75bSLuigi Rizzo TAILQ_REMOVE(&g_classifier_tailq, hook, link); 4396231f75bSLuigi Rizzo break; 4406231f75bSLuigi Rizzo } 4416231f75bSLuigi Rizzo } 4426231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 4436231f75bSLuigi Rizzo } 4446231f75bSLuigi Rizzo 4456231f75bSLuigi Rizzo static void 4466231f75bSLuigi Rizzo g_run_classifiers(struct bio *bp) 4476231f75bSLuigi Rizzo { 4486231f75bSLuigi Rizzo struct g_classifier_hook *hook; 4496231f75bSLuigi Rizzo int classified = 0; 4506231f75bSLuigi Rizzo 4516231f75bSLuigi Rizzo TAILQ_FOREACH(hook, &g_classifier_tailq, link) 4526231f75bSLuigi Rizzo classified |= hook->func(hook->arg, bp); 4536231f75bSLuigi Rizzo 4546231f75bSLuigi Rizzo if (!classified) 4556231f75bSLuigi Rizzo bp->bio_classifier1 = BIO_NOTCLASSIFIED; 4566231f75bSLuigi Rizzo } 4576231f75bSLuigi Rizzo 458dd84a43cSPoul-Henning Kamp void 459dd84a43cSPoul-Henning Kamp g_io_request(struct bio *bp, struct g_consumer *cp) 460dd84a43cSPoul-Henning Kamp { 461801bb689SPoul-Henning Kamp struct g_provider *pp; 462*40ea77a0SAlexander Motin struct mtx *mtxp; 463*40ea77a0SAlexander Motin int direct, error, first; 464dd84a43cSPoul-Henning Kamp 465d0e17c1bSPoul-Henning Kamp KASSERT(cp != NULL, ("NULL cp in g_io_request")); 466d0e17c1bSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_request")); 467e060b6bdSPoul-Henning Kamp pp = cp->provider; 468801bb689SPoul-Henning Kamp KASSERT(pp != NULL, ("consumer not attached in g_io_request")); 46992ee312dSPawel Jakub Dawidek #ifdef DIAGNOSTIC 47092ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver1 == NULL, 47192ee312dSPawel Jakub Dawidek ("bio_driver1 used by the consumer (geom %s)", cp->geom->name)); 47292ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver2 == NULL, 47392ee312dSPawel Jakub Dawidek ("bio_driver2 used by the consumer (geom %s)", cp->geom->name)); 47492ee312dSPawel Jakub Dawidek KASSERT(bp->bio_pflags == 0, 47592ee312dSPawel Jakub Dawidek ("bio_pflags used by the consumer (geom %s)", cp->geom->name)); 47692ee312dSPawel Jakub Dawidek /* 47792ee312dSPawel Jakub Dawidek * Remember consumer's private fields, so we can detect if they were 47892ee312dSPawel Jakub Dawidek * modified by the provider. 47992ee312dSPawel Jakub Dawidek */ 48092ee312dSPawel Jakub Dawidek bp->_bio_caller1 = bp->bio_caller1; 48192ee312dSPawel Jakub Dawidek bp->_bio_caller2 = bp->bio_caller2; 48292ee312dSPawel Jakub Dawidek bp->_bio_cflags = bp->bio_cflags; 48392ee312dSPawel Jakub Dawidek #endif 484801bb689SPoul-Henning Kamp 4851ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) { 486c3618c65SPawel Jakub Dawidek KASSERT(bp->bio_data != NULL, 4871ded77b2SPawel Jakub Dawidek ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd)); 4881ded77b2SPawel Jakub Dawidek } 4891ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_DELETE|BIO_FLUSH)) { 4901ded77b2SPawel Jakub Dawidek KASSERT(bp->bio_data == NULL, 4911ded77b2SPawel Jakub Dawidek ("non-NULL bp->data in g_io_request(cmd=%hhu)", 4921ded77b2SPawel Jakub Dawidek bp->bio_cmd)); 493c3618c65SPawel Jakub Dawidek } 494dcbd0fe5SPoul-Henning Kamp if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) { 495dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_offset % cp->provider->sectorsize == 0, 496dcbd0fe5SPoul-Henning Kamp ("wrong offset %jd for sectorsize %u", 497dcbd0fe5SPoul-Henning Kamp bp->bio_offset, cp->provider->sectorsize)); 498dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_length % cp->provider->sectorsize == 0, 499dcbd0fe5SPoul-Henning Kamp ("wrong length %jd for sectorsize %u", 500dcbd0fe5SPoul-Henning Kamp bp->bio_length, cp->provider->sectorsize)); 501dcbd0fe5SPoul-Henning Kamp } 502dcbd0fe5SPoul-Henning Kamp 503f7717523SStephan Uphoff g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 504f7717523SStephan Uphoff bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); 505f7717523SStephan Uphoff 506dd84a43cSPoul-Henning Kamp bp->bio_from = cp; 507801bb689SPoul-Henning Kamp bp->bio_to = pp; 5082fccec19SPoul-Henning Kamp bp->bio_error = 0; 5092fccec19SPoul-Henning Kamp bp->bio_completed = 0; 510dd84a43cSPoul-Henning Kamp 51119fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 51219fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 513*40ea77a0SAlexander Motin if ((g_collectstats & G_STATS_CONSUMERS) != 0 || 514*40ea77a0SAlexander Motin ((g_collectstats & G_STATS_PROVIDERS) != 0 && pp->stat != NULL)) 51519fa21aaSPoul-Henning Kamp binuptime(&bp->bio_t0); 516a5be8eb5SAlexander Motin else 517a5be8eb5SAlexander Motin getbinuptime(&bp->bio_t0); 5188827c821SPoul-Henning Kamp 519*40ea77a0SAlexander Motin #ifdef GET_STACK_USAGE 520*40ea77a0SAlexander Motin direct = (cp->flags & G_CF_DIRECT_SEND) && 521*40ea77a0SAlexander Motin (pp->flags & G_PF_DIRECT_RECEIVE) && 522*40ea77a0SAlexander Motin !g_is_geom_thread(curthread) && 523*40ea77a0SAlexander Motin (((pp->flags & G_PF_ACCEPT_UNMAPPED) == 0 && 524*40ea77a0SAlexander Motin (bp->bio_flags & BIO_UNMAPPED) != 0) || THREAD_CAN_SLEEP()); 525*40ea77a0SAlexander Motin if (direct) { 526*40ea77a0SAlexander Motin /* Block direct execution if less then half of stack left. */ 527*40ea77a0SAlexander Motin size_t st, su; 528*40ea77a0SAlexander Motin GET_STACK_USAGE(st, su); 529*40ea77a0SAlexander Motin if (su * 2 > st) 530*40ea77a0SAlexander Motin direct = 0; 531*40ea77a0SAlexander Motin } 532*40ea77a0SAlexander Motin #else 533*40ea77a0SAlexander Motin direct = 0; 534*40ea77a0SAlexander Motin #endif 535*40ea77a0SAlexander Motin 536*40ea77a0SAlexander Motin if (!TAILQ_EMPTY(&g_classifier_tailq) && !bp->bio_classifier1) { 537*40ea77a0SAlexander Motin g_bioq_lock(&g_bio_run_down); 538*40ea77a0SAlexander Motin g_run_classifiers(bp); 539*40ea77a0SAlexander Motin g_bioq_unlock(&g_bio_run_down); 540*40ea77a0SAlexander Motin } 541*40ea77a0SAlexander Motin 5428827c821SPoul-Henning Kamp /* 5438827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 5448827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 5458827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 5468827c821SPoul-Henning Kamp */ 547*40ea77a0SAlexander Motin mtxp = mtx_pool_find(mtxpool_sleep, pp); 548*40ea77a0SAlexander Motin mtx_lock(mtxp); 549*40ea77a0SAlexander Motin if (g_collectstats & G_STATS_PROVIDERS) 55019fa21aaSPoul-Henning Kamp devstat_start_transaction(pp->stat, &bp->bio_t0); 551*40ea77a0SAlexander Motin if (g_collectstats & G_STATS_CONSUMERS) 55219fa21aaSPoul-Henning Kamp devstat_start_transaction(cp->stat, &bp->bio_t0); 55319fa21aaSPoul-Henning Kamp pp->nstart++; 554cf457284SPoul-Henning Kamp cp->nstart++; 555*40ea77a0SAlexander Motin mtx_unlock(mtxp); 556*40ea77a0SAlexander Motin 557*40ea77a0SAlexander Motin if (direct) { 558*40ea77a0SAlexander Motin error = g_io_check(bp); 559*40ea77a0SAlexander Motin if (error >= 0) { 560*40ea77a0SAlexander Motin CTR3(KTR_GEOM, "g_io_request g_io_check on bp %p " 561*40ea77a0SAlexander Motin "provider %s returned %d", bp, bp->bio_to->name, 562*40ea77a0SAlexander Motin error); 563*40ea77a0SAlexander Motin g_io_deliver(bp, error); 564*40ea77a0SAlexander Motin return; 565*40ea77a0SAlexander Motin } 566*40ea77a0SAlexander Motin bp->bio_to->geom->start(bp); 567*40ea77a0SAlexander Motin } else { 568*40ea77a0SAlexander Motin g_bioq_lock(&g_bio_run_down); 5690d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_down.bio_queue); 57019fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_down.bio_queue, bp, bio_queue); 571*40ea77a0SAlexander Motin bp->bio_flags |= BIO_ONQUEUE; 57219fa21aaSPoul-Henning Kamp g_bio_run_down.bio_queue_length++; 57319fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 5742fccec19SPoul-Henning Kamp /* Pass it on down. */ 5750d883b11SAlexander Motin if (first) 576dd84a43cSPoul-Henning Kamp wakeup(&g_wait_down); 577dd84a43cSPoul-Henning Kamp } 578*40ea77a0SAlexander Motin } 579dd84a43cSPoul-Henning Kamp 580dd84a43cSPoul-Henning Kamp void 58172840432SPoul-Henning Kamp g_io_deliver(struct bio *bp, int error) 582dd84a43cSPoul-Henning Kamp { 583e431d66cSAlexander Motin struct bintime now; 584801bb689SPoul-Henning Kamp struct g_consumer *cp; 585801bb689SPoul-Henning Kamp struct g_provider *pp; 586*40ea77a0SAlexander Motin struct mtx *mtxp; 587*40ea77a0SAlexander Motin int direct, first; 588dd84a43cSPoul-Henning Kamp 589e060b6bdSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); 590801bb689SPoul-Henning Kamp pp = bp->bio_to; 591f7eeab17SPoul-Henning Kamp KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); 592f7eeab17SPoul-Henning Kamp cp = bp->bio_from; 593f7eeab17SPoul-Henning Kamp if (cp == NULL) { 594f7eeab17SPoul-Henning Kamp bp->bio_error = error; 595f7eeab17SPoul-Henning Kamp bp->bio_done(bp); 596f7eeab17SPoul-Henning Kamp return; 597f7eeab17SPoul-Henning Kamp } 598801bb689SPoul-Henning Kamp KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver")); 599801bb689SPoul-Henning Kamp KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver")); 600fb231f36SEdward Tomasz Napierala #ifdef DIAGNOSTIC 601fb231f36SEdward Tomasz Napierala /* 602fb231f36SEdward Tomasz Napierala * Some classes - GJournal in particular - can modify bio's 603fb231f36SEdward Tomasz Napierala * private fields while the bio is in transit; G_GEOM_VOLATILE_BIO 604fb231f36SEdward Tomasz Napierala * flag means it's an expected behaviour for that particular geom. 605fb231f36SEdward Tomasz Napierala */ 606fb231f36SEdward Tomasz Napierala if ((cp->geom->flags & G_GEOM_VOLATILE_BIO) == 0) { 607fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller1 == bp->_bio_caller1, 608fb231f36SEdward Tomasz Napierala ("bio_caller1 used by the provider %s", pp->name)); 609fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller2 == bp->_bio_caller2, 610fb231f36SEdward Tomasz Napierala ("bio_caller2 used by the provider %s", pp->name)); 611fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_cflags == bp->_bio_cflags, 612fb231f36SEdward Tomasz Napierala ("bio_cflags used by the provider %s", pp->name)); 613fb231f36SEdward Tomasz Napierala } 614fb231f36SEdward Tomasz Napierala #endif 61546aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed >= 0, ("bio_completed can't be less than 0")); 61646aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed <= bp->bio_length, 61746aeebecSPawel Jakub Dawidek ("bio_completed can't be greater than bio_length")); 6185ab413bfSPoul-Henning Kamp 619dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, 6200355b86eSPoul-Henning Kamp "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", 621801bb689SPoul-Henning Kamp bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error, 6220355b86eSPoul-Henning Kamp (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 623801bb689SPoul-Henning Kamp 62419fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 62519fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 62619fa21aaSPoul-Henning Kamp 627dcbd0fe5SPoul-Henning Kamp /* 628dcbd0fe5SPoul-Henning Kamp * XXX: next two doesn't belong here 629dcbd0fe5SPoul-Henning Kamp */ 630e24cbd90SPoul-Henning Kamp bp->bio_bcount = bp->bio_length; 631e24cbd90SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount - bp->bio_completed; 63219fa21aaSPoul-Henning Kamp 633*40ea77a0SAlexander Motin #ifdef GET_STACK_USAGE 634*40ea77a0SAlexander Motin direct = (pp->flags & G_PF_DIRECT_SEND) && 635*40ea77a0SAlexander Motin (cp->flags & G_CF_DIRECT_RECEIVE) && 636*40ea77a0SAlexander Motin !g_is_geom_thread(curthread); 637*40ea77a0SAlexander Motin if (direct) { 638*40ea77a0SAlexander Motin /* Block direct execution if less then half of stack left. */ 639*40ea77a0SAlexander Motin size_t st, su; 640*40ea77a0SAlexander Motin GET_STACK_USAGE(st, su); 641*40ea77a0SAlexander Motin if (su * 2 > st) 642*40ea77a0SAlexander Motin direct = 0; 643*40ea77a0SAlexander Motin } 644*40ea77a0SAlexander Motin #else 645*40ea77a0SAlexander Motin direct = 0; 646*40ea77a0SAlexander Motin #endif 647*40ea77a0SAlexander Motin 6488827c821SPoul-Henning Kamp /* 6498827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 6508827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 6518827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 6528827c821SPoul-Henning Kamp */ 653*40ea77a0SAlexander Motin if ((g_collectstats & G_STATS_CONSUMERS) != 0 || 654*40ea77a0SAlexander Motin ((g_collectstats & G_STATS_PROVIDERS) != 0 && pp->stat != NULL)) 655e431d66cSAlexander Motin binuptime(&now); 656*40ea77a0SAlexander Motin mtxp = mtx_pool_find(mtxpool_sleep, cp); 657*40ea77a0SAlexander Motin mtx_lock(mtxp); 658*40ea77a0SAlexander Motin if (g_collectstats & G_STATS_PROVIDERS) 659e431d66cSAlexander Motin devstat_end_transaction_bio_bt(pp->stat, bp, &now); 660*40ea77a0SAlexander Motin if (g_collectstats & G_STATS_CONSUMERS) 661e431d66cSAlexander Motin devstat_end_transaction_bio_bt(cp->stat, bp, &now); 662c6ae9b5fSPoul-Henning Kamp cp->nend++; 663c6ae9b5fSPoul-Henning Kamp pp->nend++; 664*40ea77a0SAlexander Motin mtx_unlock(mtxp); 665*40ea77a0SAlexander Motin 66619fa21aaSPoul-Henning Kamp if (error != ENOMEM) { 66719fa21aaSPoul-Henning Kamp bp->bio_error = error; 668*40ea77a0SAlexander Motin if (direct) { 669*40ea77a0SAlexander Motin biodone(bp); 670*40ea77a0SAlexander Motin } else { 671*40ea77a0SAlexander Motin g_bioq_lock(&g_bio_run_up); 6720d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_up.bio_queue); 67319fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_up.bio_queue, bp, bio_queue); 674276f72c5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 67519fa21aaSPoul-Henning Kamp g_bio_run_up.bio_queue_length++; 67619fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 6770d883b11SAlexander Motin if (first) 67819fa21aaSPoul-Henning Kamp wakeup(&g_wait_up); 679*40ea77a0SAlexander Motin } 68019fa21aaSPoul-Henning Kamp return; 68119fa21aaSPoul-Henning Kamp } 682dd84a43cSPoul-Henning Kamp 6832cc9686eSPoul-Henning Kamp if (bootverbose) 684801bb689SPoul-Henning Kamp printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name); 6851b949c05SPawel Jakub Dawidek bp->bio_children = 0; 6861b949c05SPawel Jakub Dawidek bp->bio_inbed = 0; 68760114438SPawel Jakub Dawidek bp->bio_driver1 = NULL; 68860114438SPawel Jakub Dawidek bp->bio_driver2 = NULL; 68960114438SPawel Jakub Dawidek bp->bio_pflags = 0; 690801bb689SPoul-Henning Kamp g_io_request(bp, cp); 6913432e4fdSPoul-Henning Kamp pace++; 6923432e4fdSPoul-Henning Kamp return; 6933432e4fdSPoul-Henning Kamp } 694dd84a43cSPoul-Henning Kamp 695ee75e7deSKonstantin Belousov SYSCTL_DECL(_kern_geom); 696ee75e7deSKonstantin Belousov 697ee75e7deSKonstantin Belousov static long transient_maps; 698ee75e7deSKonstantin Belousov SYSCTL_LONG(_kern_geom, OID_AUTO, transient_maps, CTLFLAG_RD, 699ee75e7deSKonstantin Belousov &transient_maps, 0, 700ee75e7deSKonstantin Belousov "Total count of the transient mapping requests"); 701ee75e7deSKonstantin Belousov u_int transient_map_retries = 10; 702ee75e7deSKonstantin Belousov SYSCTL_UINT(_kern_geom, OID_AUTO, transient_map_retries, CTLFLAG_RW, 703ee75e7deSKonstantin Belousov &transient_map_retries, 0, 704ee75e7deSKonstantin Belousov "Max count of retries used before giving up on creating transient map"); 705ee75e7deSKonstantin Belousov int transient_map_hard_failures; 706ee75e7deSKonstantin Belousov SYSCTL_INT(_kern_geom, OID_AUTO, transient_map_hard_failures, CTLFLAG_RD, 707ee75e7deSKonstantin Belousov &transient_map_hard_failures, 0, 708ee75e7deSKonstantin Belousov "Failures to establish the transient mapping due to retry attempts " 709ee75e7deSKonstantin Belousov "exhausted"); 710ee75e7deSKonstantin Belousov int transient_map_soft_failures; 711ee75e7deSKonstantin Belousov SYSCTL_INT(_kern_geom, OID_AUTO, transient_map_soft_failures, CTLFLAG_RD, 712ee75e7deSKonstantin Belousov &transient_map_soft_failures, 0, 713ee75e7deSKonstantin Belousov "Count of retried failures to establish the transient mapping"); 714ee75e7deSKonstantin Belousov int inflight_transient_maps; 715ee75e7deSKonstantin Belousov SYSCTL_INT(_kern_geom, OID_AUTO, inflight_transient_maps, CTLFLAG_RD, 716ee75e7deSKonstantin Belousov &inflight_transient_maps, 0, 717ee75e7deSKonstantin Belousov "Current count of the active transient maps"); 718ee75e7deSKonstantin Belousov 719ee75e7deSKonstantin Belousov static int 720ee75e7deSKonstantin Belousov g_io_transient_map_bio(struct bio *bp) 721ee75e7deSKonstantin Belousov { 722ee75e7deSKonstantin Belousov vm_offset_t addr; 723ee75e7deSKonstantin Belousov long size; 724ee75e7deSKonstantin Belousov u_int retried; 725ee75e7deSKonstantin Belousov 7266c83fce3SKonstantin Belousov KASSERT(unmapped_buf_allowed, ("unmapped disabled")); 7276c83fce3SKonstantin Belousov 728ee75e7deSKonstantin Belousov size = round_page(bp->bio_ma_offset + bp->bio_length); 729ee75e7deSKonstantin Belousov KASSERT(size / PAGE_SIZE == bp->bio_ma_n, ("Bio too short %p", bp)); 730ee75e7deSKonstantin Belousov addr = 0; 731ee75e7deSKonstantin Belousov retried = 0; 732ee75e7deSKonstantin Belousov atomic_add_long(&transient_maps, 1); 733ee75e7deSKonstantin Belousov retry: 7345f518366SJeff Roberson if (vmem_alloc(transient_arena, size, M_BESTFIT | M_NOWAIT, &addr)) { 735ee75e7deSKonstantin Belousov if (transient_map_retries != 0 && 736ee75e7deSKonstantin Belousov retried >= transient_map_retries) { 737ee75e7deSKonstantin Belousov CTR2(KTR_GEOM, "g_down cannot map bp %p provider %s", 738ee75e7deSKonstantin Belousov bp, bp->bio_to->name); 739ee75e7deSKonstantin Belousov atomic_add_int(&transient_map_hard_failures, 1); 740*40ea77a0SAlexander Motin return (EDEADLK/* XXXKIB */); 741ee75e7deSKonstantin Belousov } else { 742ee75e7deSKonstantin Belousov /* 743ee75e7deSKonstantin Belousov * Naive attempt to quisce the I/O to get more 744ee75e7deSKonstantin Belousov * in-flight requests completed and defragment 7455f518366SJeff Roberson * the transient_arena. 746ee75e7deSKonstantin Belousov */ 747ee75e7deSKonstantin Belousov CTR3(KTR_GEOM, "g_down retrymap bp %p provider %s r %d", 748ee75e7deSKonstantin Belousov bp, bp->bio_to->name, retried); 749ee75e7deSKonstantin Belousov pause("g_d_tra", hz / 10); 750ee75e7deSKonstantin Belousov retried++; 751ee75e7deSKonstantin Belousov atomic_add_int(&transient_map_soft_failures, 1); 752ee75e7deSKonstantin Belousov goto retry; 753ee75e7deSKonstantin Belousov } 754ee75e7deSKonstantin Belousov } 755ee75e7deSKonstantin Belousov atomic_add_int(&inflight_transient_maps, 1); 756ee75e7deSKonstantin Belousov pmap_qenter((vm_offset_t)addr, bp->bio_ma, OFF_TO_IDX(size)); 757ee75e7deSKonstantin Belousov bp->bio_data = (caddr_t)addr + bp->bio_ma_offset; 758ee75e7deSKonstantin Belousov bp->bio_flags |= BIO_TRANSIENT_MAPPING; 759ee75e7deSKonstantin Belousov bp->bio_flags &= ~BIO_UNMAPPED; 760*40ea77a0SAlexander Motin return (EJUSTRETURN); 761ee75e7deSKonstantin Belousov } 762ee75e7deSKonstantin Belousov 763dd84a43cSPoul-Henning Kamp void 764dd84a43cSPoul-Henning Kamp g_io_schedule_down(struct thread *tp __unused) 765dd84a43cSPoul-Henning Kamp { 766dd84a43cSPoul-Henning Kamp struct bio *bp; 767e39d70d4SPoul-Henning Kamp int error; 768dd84a43cSPoul-Henning Kamp 769dd84a43cSPoul-Henning Kamp for(;;) { 770f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 771dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_down); 772f0e185d7SPoul-Henning Kamp if (bp == NULL) { 77349dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down going to sleep"); 774f0e185d7SPoul-Henning Kamp msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock, 7757fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 776f0e185d7SPoul-Henning Kamp continue; 777f0e185d7SPoul-Henning Kamp } 77849dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down has work to do"); 779f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 780376ceb79SPoul-Henning Kamp if (pace > 0) { 78149dbb61dSRobert Watson CTR1(KTR_GEOM, "g_down pacing self (pace %d)", pace); 7824d70511aSJohn Baldwin pause("g_down", hz/10); 783376ceb79SPoul-Henning Kamp pace--; 784376ceb79SPoul-Henning Kamp } 785*40ea77a0SAlexander Motin CTR2(KTR_GEOM, "g_down processing bp %p provider %s", bp, 786*40ea77a0SAlexander Motin bp->bio_to->name); 787e39d70d4SPoul-Henning Kamp error = g_io_check(bp); 788*40ea77a0SAlexander Motin if (error >= 0) { 78949dbb61dSRobert Watson CTR3(KTR_GEOM, "g_down g_io_check on bp %p provider " 79049dbb61dSRobert Watson "%s returned %d", bp, bp->bio_to->name, error); 791e39d70d4SPoul-Henning Kamp g_io_deliver(bp, error); 792e39d70d4SPoul-Henning Kamp continue; 793e39d70d4SPoul-Henning Kamp } 79451460da8SJohn Baldwin THREAD_NO_SLEEPING(); 79549dbb61dSRobert Watson CTR4(KTR_GEOM, "g_down starting bp %p provider %s off %ld " 79649dbb61dSRobert Watson "len %ld", bp, bp->bio_to->name, bp->bio_offset, 79749dbb61dSRobert Watson bp->bio_length); 798dd84a43cSPoul-Henning Kamp bp->bio_to->geom->start(bp); 79951460da8SJohn Baldwin THREAD_SLEEPING_OK(); 800dd84a43cSPoul-Henning Kamp } 801dd84a43cSPoul-Henning Kamp } 802dd84a43cSPoul-Henning Kamp 803dd84a43cSPoul-Henning Kamp void 8045fcf4e43SPoul-Henning Kamp bio_taskqueue(struct bio *bp, bio_task_t *func, void *arg) 8055fcf4e43SPoul-Henning Kamp { 8065fcf4e43SPoul-Henning Kamp bp->bio_task = func; 8075fcf4e43SPoul-Henning Kamp bp->bio_task_arg = arg; 8085fcf4e43SPoul-Henning Kamp /* 8095fcf4e43SPoul-Henning Kamp * The taskqueue is actually just a second queue off the "up" 8105fcf4e43SPoul-Henning Kamp * queue, so we use the same lock. 8115fcf4e43SPoul-Henning Kamp */ 8125fcf4e43SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 813dcbd0fe5SPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 814dcbd0fe5SPoul-Henning Kamp ("Bio already on queue bp=%p target taskq", bp)); 815dcbd0fe5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 8165fcf4e43SPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_task.bio_queue, bp, bio_queue); 8175fcf4e43SPoul-Henning Kamp g_bio_run_task.bio_queue_length++; 8185fcf4e43SPoul-Henning Kamp wakeup(&g_wait_up); 8195fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 8205fcf4e43SPoul-Henning Kamp } 8215fcf4e43SPoul-Henning Kamp 8225fcf4e43SPoul-Henning Kamp 8235fcf4e43SPoul-Henning Kamp void 824dd84a43cSPoul-Henning Kamp g_io_schedule_up(struct thread *tp __unused) 825dd84a43cSPoul-Henning Kamp { 826dd84a43cSPoul-Henning Kamp struct bio *bp; 827dd84a43cSPoul-Henning Kamp for(;;) { 828f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 8295fcf4e43SPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_task); 8305fcf4e43SPoul-Henning Kamp if (bp != NULL) { 8315fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 83251460da8SJohn Baldwin THREAD_NO_SLEEPING(); 83349dbb61dSRobert Watson CTR1(KTR_GEOM, "g_up processing task bp %p", bp); 8345fcf4e43SPoul-Henning Kamp bp->bio_task(bp->bio_task_arg); 83551460da8SJohn Baldwin THREAD_SLEEPING_OK(); 8365fcf4e43SPoul-Henning Kamp continue; 8375fcf4e43SPoul-Henning Kamp } 838dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_up); 839f0e185d7SPoul-Henning Kamp if (bp != NULL) { 840f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 84151460da8SJohn Baldwin THREAD_NO_SLEEPING(); 84249dbb61dSRobert Watson CTR4(KTR_GEOM, "g_up biodone bp %p provider %s off " 843c4901b67SSean Bruno "%jd len %ld", bp, bp->bio_to->name, 84449dbb61dSRobert Watson bp->bio_offset, bp->bio_length); 84553706245SPoul-Henning Kamp biodone(bp); 84651460da8SJohn Baldwin THREAD_SLEEPING_OK(); 847f0e185d7SPoul-Henning Kamp continue; 848f0e185d7SPoul-Henning Kamp } 84949dbb61dSRobert Watson CTR0(KTR_GEOM, "g_up going to sleep"); 850f0e185d7SPoul-Henning Kamp msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock, 8517fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 852dd84a43cSPoul-Henning Kamp } 853dd84a43cSPoul-Henning Kamp } 854dd84a43cSPoul-Henning Kamp 855dd84a43cSPoul-Henning Kamp void * 856dd84a43cSPoul-Henning Kamp g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 857dd84a43cSPoul-Henning Kamp { 858dd84a43cSPoul-Henning Kamp struct bio *bp; 859dd84a43cSPoul-Henning Kamp void *ptr; 860dd84a43cSPoul-Henning Kamp int errorc; 861dd84a43cSPoul-Henning Kamp 8628dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 8638dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_read_data(): invalid length %jd", 8648dd5480dSPawel Jakub Dawidek (intmax_t)length)); 8653eb6ffdfSPoul-Henning Kamp 866a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 867dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_READ; 868dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 869dd84a43cSPoul-Henning Kamp bp->bio_offset = offset; 870dd84a43cSPoul-Henning Kamp bp->bio_length = length; 871a163d034SWarner Losh ptr = g_malloc(length, M_WAITOK); 872dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 873dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 87453706245SPoul-Henning Kamp errorc = biowait(bp, "gread"); 875dd84a43cSPoul-Henning Kamp if (error != NULL) 876dd84a43cSPoul-Henning Kamp *error = errorc; 877dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 878dd84a43cSPoul-Henning Kamp if (errorc) { 879dd84a43cSPoul-Henning Kamp g_free(ptr); 880dd84a43cSPoul-Henning Kamp ptr = NULL; 881dd84a43cSPoul-Henning Kamp } 882dd84a43cSPoul-Henning Kamp return (ptr); 883dd84a43cSPoul-Henning Kamp } 88490b1cd56SPoul-Henning Kamp 88590b1cd56SPoul-Henning Kamp int 88690b1cd56SPoul-Henning Kamp g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) 88790b1cd56SPoul-Henning Kamp { 88890b1cd56SPoul-Henning Kamp struct bio *bp; 88990b1cd56SPoul-Henning Kamp int error; 89090b1cd56SPoul-Henning Kamp 8918dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 8928dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_write_data(): invalid length %jd", 8938dd5480dSPawel Jakub Dawidek (intmax_t)length)); 8943eb6ffdfSPoul-Henning Kamp 895a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 89690b1cd56SPoul-Henning Kamp bp->bio_cmd = BIO_WRITE; 89790b1cd56SPoul-Henning Kamp bp->bio_done = NULL; 89890b1cd56SPoul-Henning Kamp bp->bio_offset = offset; 89990b1cd56SPoul-Henning Kamp bp->bio_length = length; 90090b1cd56SPoul-Henning Kamp bp->bio_data = ptr; 90190b1cd56SPoul-Henning Kamp g_io_request(bp, cp); 90290b1cd56SPoul-Henning Kamp error = biowait(bp, "gwrite"); 90390b1cd56SPoul-Henning Kamp g_destroy_bio(bp); 90490b1cd56SPoul-Henning Kamp return (error); 90590b1cd56SPoul-Henning Kamp } 90672e33095SPawel Jakub Dawidek 9072b17fb95SPawel Jakub Dawidek int 9082b17fb95SPawel Jakub Dawidek g_delete_data(struct g_consumer *cp, off_t offset, off_t length) 9092b17fb95SPawel Jakub Dawidek { 9102b17fb95SPawel Jakub Dawidek struct bio *bp; 9112b17fb95SPawel Jakub Dawidek int error; 9122b17fb95SPawel Jakub Dawidek 913eed6cda9SPoul-Henning Kamp KASSERT(length > 0 && length >= cp->provider->sectorsize, 914eed6cda9SPoul-Henning Kamp ("g_delete_data(): invalid length %jd", (intmax_t)length)); 9152b17fb95SPawel Jakub Dawidek 9162b17fb95SPawel Jakub Dawidek bp = g_alloc_bio(); 9172b17fb95SPawel Jakub Dawidek bp->bio_cmd = BIO_DELETE; 9182b17fb95SPawel Jakub Dawidek bp->bio_done = NULL; 9192b17fb95SPawel Jakub Dawidek bp->bio_offset = offset; 9202b17fb95SPawel Jakub Dawidek bp->bio_length = length; 9212b17fb95SPawel Jakub Dawidek bp->bio_data = NULL; 9222b17fb95SPawel Jakub Dawidek g_io_request(bp, cp); 9232b17fb95SPawel Jakub Dawidek error = biowait(bp, "gdelete"); 9242b17fb95SPawel Jakub Dawidek g_destroy_bio(bp); 9252b17fb95SPawel Jakub Dawidek return (error); 9262b17fb95SPawel Jakub Dawidek } 9272b17fb95SPawel Jakub Dawidek 92872e33095SPawel Jakub Dawidek void 92972e33095SPawel Jakub Dawidek g_print_bio(struct bio *bp) 93072e33095SPawel Jakub Dawidek { 93172e33095SPawel Jakub Dawidek const char *pname, *cmd = NULL; 93272e33095SPawel Jakub Dawidek 93372e33095SPawel Jakub Dawidek if (bp->bio_to != NULL) 93472e33095SPawel Jakub Dawidek pname = bp->bio_to->name; 93572e33095SPawel Jakub Dawidek else 93672e33095SPawel Jakub Dawidek pname = "[unknown]"; 93772e33095SPawel Jakub Dawidek 93872e33095SPawel Jakub Dawidek switch (bp->bio_cmd) { 93972e33095SPawel Jakub Dawidek case BIO_GETATTR: 94072e33095SPawel Jakub Dawidek cmd = "GETATTR"; 94172e33095SPawel Jakub Dawidek printf("%s[%s(attr=%s)]", pname, cmd, bp->bio_attribute); 94272e33095SPawel Jakub Dawidek return; 943c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 944c3618c65SPawel Jakub Dawidek cmd = "FLUSH"; 945c3618c65SPawel Jakub Dawidek printf("%s[%s]", pname, cmd); 946c3618c65SPawel Jakub Dawidek return; 94772e33095SPawel Jakub Dawidek case BIO_READ: 94872e33095SPawel Jakub Dawidek cmd = "READ"; 9497ce513a5SEdward Tomasz Napierala break; 95072e33095SPawel Jakub Dawidek case BIO_WRITE: 95172e33095SPawel Jakub Dawidek cmd = "WRITE"; 9527ce513a5SEdward Tomasz Napierala break; 95372e33095SPawel Jakub Dawidek case BIO_DELETE: 95472e33095SPawel Jakub Dawidek cmd = "DELETE"; 9557ce513a5SEdward Tomasz Napierala break; 95672e33095SPawel Jakub Dawidek default: 95772e33095SPawel Jakub Dawidek cmd = "UNKNOWN"; 95872e33095SPawel Jakub Dawidek printf("%s[%s()]", pname, cmd); 95972e33095SPawel Jakub Dawidek return; 96072e33095SPawel Jakub Dawidek } 9617ce513a5SEdward Tomasz Napierala printf("%s[%s(offset=%jd, length=%jd)]", pname, cmd, 9627ce513a5SEdward Tomasz Napierala (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 96372e33095SPawel Jakub Dawidek } 964