12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673 |
- /*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2002 Poul-Henning Kamp
- * Copyright (c) 2002 Networks Associates Technology, Inc.
- * All rights reserved.
- *
- * This software was developed for the FreeBSD Project by Poul-Henning Kamp
- * and NAI Labs, the Security Research Division of Network Associates, Inc.
- * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
- * DARPA CHATS research program.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the authors may not be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #include <sys/cdefs.h>
- #include "opt_ddb.h"
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/devicestat.h>
- #include <sys/kernel.h>
- #include <sys/malloc.h>
- #include <sys/bio.h>
- #include <sys/proc.h>
- #include <sys/kthread.h>
- #include <sys/lock.h>
- #include <sys/mutex.h>
- #include <sys/errno.h>
- #include <sys/sbuf.h>
- #include <sys/sdt.h>
- #include <geom/geom.h>
- #include <geom/geom_dbg.h>
- #include <geom/geom_int.h>
- #include <machine/stdarg.h>
- #ifdef DDB
- #include <ddb/ddb.h>
- #endif
- #ifdef KDB
- #include <sys/kdb.h>
- #endif
- SDT_PROVIDER_DEFINE(geom);
- struct class_list_head g_classes = LIST_HEAD_INITIALIZER(g_classes);
- static struct g_tailq_head geoms = TAILQ_HEAD_INITIALIZER(geoms);
- char *g_wait_event, *g_wait_up, *g_wait_down;
- struct g_hh00 {
- struct g_class *mp;
- struct g_provider *pp;
- off_t size;
- int error;
- int post;
- };
- void
- g_dbg_printf(const char *classname, int lvl, struct bio *bp,
- const char *format,
- ...)
- {
- #ifndef PRINTF_BUFR_SIZE
- #define PRINTF_BUFR_SIZE 64
- #endif
- char bufr[PRINTF_BUFR_SIZE];
- struct sbuf sb, *sbp __unused;
- va_list ap;
- sbp = sbuf_new(&sb, bufr, sizeof(bufr), SBUF_FIXEDLEN);
- KASSERT(sbp != NULL, ("sbuf_new misused?"));
- sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
- sbuf_cat(&sb, classname);
- if (lvl >= 0)
- sbuf_printf(&sb, "[%d]", lvl);
- va_start(ap, format);
- sbuf_vprintf(&sb, format, ap);
- va_end(ap);
- if (bp != NULL) {
- sbuf_putc(&sb, ' ');
- g_format_bio(&sb, bp);
- }
- /* Terminate the debug line with a single '\n'. */
- sbuf_nl_terminate(&sb);
- /* Flush line to printf. */
- sbuf_finish(&sb);
- sbuf_delete(&sb);
- }
- /*
- * This event offers a new class a chance to taste all preexisting providers.
- */
- static void
- g_load_class(void *arg, int flag)
- {
- struct g_hh00 *hh;
- struct g_class *mp2, *mp;
- struct g_geom *gp;
- struct g_provider *pp;
- g_topology_assert();
- if (flag == EV_CANCEL) /* XXX: can't happen ? */
- return;
- if (g_shutdown)
- return;
- hh = arg;
- mp = hh->mp;
- hh->error = 0;
- if (hh->post) {
- g_free(hh);
- hh = NULL;
- }
- g_trace(G_T_TOPOLOGY, "g_load_class(%s)", mp->name);
- KASSERT(mp->name != NULL && *mp->name != '\0',
- ("GEOM class has no name"));
- LIST_FOREACH(mp2, &g_classes, class) {
- if (mp2 == mp) {
- printf("The GEOM class %s is already loaded.\n",
- mp2->name);
- if (hh != NULL)
- hh->error = EEXIST;
- return;
- } else if (strcmp(mp2->name, mp->name) == 0) {
- printf("A GEOM class %s is already loaded.\n",
- mp2->name);
- if (hh != NULL)
- hh->error = EEXIST;
- return;
- }
- }
- LIST_INIT(&mp->geom);
- LIST_INSERT_HEAD(&g_classes, mp, class);
- if (mp->init != NULL)
- mp->init(mp);
- if (mp->taste == NULL)
- return;
- LIST_FOREACH(mp2, &g_classes, class) {
- if (mp == mp2)
- continue;
- LIST_FOREACH(gp, &mp2->geom, geom) {
- LIST_FOREACH(pp, &gp->provider, provider) {
- mp->taste(mp, pp, 0);
- g_topology_assert();
- }
- }
- }
- }
- static int
- g_unload_class(struct g_class *mp)
- {
- struct g_geom *gp;
- struct g_provider *pp;
- struct g_consumer *cp;
- int error;
- g_topology_lock();
- g_trace(G_T_TOPOLOGY, "g_unload_class(%s)", mp->name);
- retry:
- G_VALID_CLASS(mp);
- LIST_FOREACH(gp, &mp->geom, geom) {
- /* We refuse to unload if anything is open */
- LIST_FOREACH(pp, &gp->provider, provider)
- if (pp->acr || pp->acw || pp->ace) {
- g_topology_unlock();
- return (EBUSY);
- }
- LIST_FOREACH(cp, &gp->consumer, consumer)
- if (cp->acr || cp->acw || cp->ace) {
- g_topology_unlock();
- return (EBUSY);
- }
- /* If the geom is withering, wait for it to finish. */
- if (gp->flags & G_GEOM_WITHER) {
- g_topology_sleep(mp, 1);
- goto retry;
- }
- }
- /*
- * We allow unloading if we have no geoms, or a class
- * method we can use to get rid of them.
- */
- if (!LIST_EMPTY(&mp->geom) && mp->destroy_geom == NULL) {
- g_topology_unlock();
- return (EOPNOTSUPP);
- }
- /* Bar new entries */
- mp->taste = NULL;
- LIST_FOREACH(gp, &mp->geom, geom) {
- error = mp->destroy_geom(NULL, mp, gp);
- if (error != 0) {
- g_topology_unlock();
- return (error);
- }
- }
- /* Wait for withering to finish. */
- for (;;) {
- gp = LIST_FIRST(&mp->geom);
- if (gp == NULL)
- break;
- KASSERT(gp->flags & G_GEOM_WITHER,
- ("Non-withering geom in class %s", mp->name));
- g_topology_sleep(mp, 1);
- }
- G_VALID_CLASS(mp);
- if (mp->fini != NULL)
- mp->fini(mp);
- LIST_REMOVE(mp, class);
- g_topology_unlock();
- return (0);
- }
- int
- g_modevent(module_t mod, int type, void *data)
- {
- struct g_hh00 *hh;
- int error;
- static int g_ignition;
- struct g_class *mp;
- mp = data;
- if (mp->version != G_VERSION) {
- printf("GEOM class %s has Wrong version %x\n",
- mp->name, mp->version);
- return (EINVAL);
- }
- if (!g_ignition) {
- g_ignition++;
- g_init();
- }
- error = EOPNOTSUPP;
- switch (type) {
- case MOD_LOAD:
- g_trace(G_T_TOPOLOGY, "g_modevent(%s, LOAD)", mp->name);
- hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO);
- hh->mp = mp;
- /*
- * Once the system is not cold, MOD_LOAD calls will be
- * from the userland and the g_event thread will be able
- * to acknowledge their completion.
- */
- if (cold) {
- hh->post = 1;
- error = g_post_event(g_load_class, hh, M_WAITOK, NULL);
- } else {
- error = g_waitfor_event(g_load_class, hh, M_WAITOK,
- NULL);
- if (error == 0)
- error = hh->error;
- g_free(hh);
- }
- break;
- case MOD_UNLOAD:
- g_trace(G_T_TOPOLOGY, "g_modevent(%s, UNLOAD)", mp->name);
- error = g_unload_class(mp);
- if (error == 0) {
- KASSERT(LIST_EMPTY(&mp->geom),
- ("Unloaded class (%s) still has geom", mp->name));
- }
- break;
- }
- return (error);
- }
- static void
- g_retaste_event(void *arg, int flag)
- {
- struct g_class *mp, *mp2;
- struct g_geom *gp;
- struct g_hh00 *hh;
- struct g_provider *pp;
- struct g_consumer *cp;
- g_topology_assert();
- if (flag == EV_CANCEL) /* XXX: can't happen ? */
- return;
- if (g_shutdown || g_notaste)
- return;
- hh = arg;
- mp = hh->mp;
- hh->error = 0;
- if (hh->post) {
- g_free(hh);
- hh = NULL;
- }
- g_trace(G_T_TOPOLOGY, "g_retaste(%s)", mp->name);
- LIST_FOREACH(mp2, &g_classes, class) {
- LIST_FOREACH(gp, &mp2->geom, geom) {
- LIST_FOREACH(pp, &gp->provider, provider) {
- if (pp->acr || pp->acw || pp->ace)
- continue;
- LIST_FOREACH(cp, &pp->consumers, consumers) {
- if (cp->geom->class == mp &&
- (cp->flags & G_CF_ORPHAN) == 0)
- break;
- }
- if (cp != NULL) {
- cp->flags |= G_CF_ORPHAN;
- g_wither_geom(cp->geom, ENXIO);
- }
- mp->taste(mp, pp, 0);
- g_topology_assert();
- }
- }
- }
- }
- int
- g_retaste(struct g_class *mp)
- {
- struct g_hh00 *hh;
- int error;
- if (mp->taste == NULL)
- return (EINVAL);
- hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO);
- hh->mp = mp;
- if (cold) {
- hh->post = 1;
- error = g_post_event(g_retaste_event, hh, M_WAITOK, NULL);
- } else {
- error = g_waitfor_event(g_retaste_event, hh, M_WAITOK, NULL);
- if (error == 0)
- error = hh->error;
- g_free(hh);
- }
- return (error);
- }
- struct g_geom *
- g_new_geomf(struct g_class *mp, const char *fmt, ...)
- {
- struct g_geom *gp;
- va_list ap;
- struct sbuf *sb;
- g_topology_assert();
- G_VALID_CLASS(mp);
- sb = sbuf_new_auto();
- va_start(ap, fmt);
- sbuf_vprintf(sb, fmt, ap);
- va_end(ap);
- sbuf_finish(sb);
- gp = g_malloc(sizeof *gp, M_WAITOK | M_ZERO);
- gp->name = g_malloc(sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
- gp->class = mp;
- gp->rank = 1;
- LIST_INIT(&gp->consumer);
- LIST_INIT(&gp->provider);
- LIST_INSERT_HEAD(&mp->geom, gp, geom);
- TAILQ_INSERT_HEAD(&geoms, gp, geoms);
- strcpy(gp->name, sbuf_data(sb));
- sbuf_delete(sb);
- /* Fill in defaults from class */
- gp->start = mp->start;
- gp->spoiled = mp->spoiled;
- gp->attrchanged = mp->attrchanged;
- gp->providergone = mp->providergone;
- gp->dumpconf = mp->dumpconf;
- gp->access = mp->access;
- gp->orphan = mp->orphan;
- gp->ioctl = mp->ioctl;
- gp->resize = mp->resize;
- return (gp);
- }
- void
- g_destroy_geom(struct g_geom *gp)
- {
- g_topology_assert();
- G_VALID_GEOM(gp);
- g_trace(G_T_TOPOLOGY, "g_destroy_geom(%p(%s))", gp, gp->name);
- KASSERT(LIST_EMPTY(&gp->consumer),
- ("g_destroy_geom(%s) with consumer(s) [%p]",
- gp->name, LIST_FIRST(&gp->consumer)));
- KASSERT(LIST_EMPTY(&gp->provider),
- ("g_destroy_geom(%s) with provider(s) [%p]",
- gp->name, LIST_FIRST(&gp->provider)));
- g_cancel_event(gp);
- LIST_REMOVE(gp, geom);
- TAILQ_REMOVE(&geoms, gp, geoms);
- g_free(gp->name);
- g_free(gp);
- }
- /*
- * This function is called (repeatedly) until the geom has withered away.
- */
- void
- g_wither_geom(struct g_geom *gp, int error)
- {
- struct g_provider *pp;
- g_topology_assert();
- G_VALID_GEOM(gp);
- g_trace(G_T_TOPOLOGY, "g_wither_geom(%p(%s))", gp, gp->name);
- if (!(gp->flags & G_GEOM_WITHER)) {
- gp->flags |= G_GEOM_WITHER;
- LIST_FOREACH(pp, &gp->provider, provider)
- if (!(pp->flags & G_PF_ORPHAN))
- g_orphan_provider(pp, error);
- }
- g_do_wither();
- }
- /*
- * Convenience function to destroy a particular provider.
- */
- void
- g_wither_provider(struct g_provider *pp, int error)
- {
- pp->flags |= G_PF_WITHER;
- if (!(pp->flags & G_PF_ORPHAN))
- g_orphan_provider(pp, error);
- }
- /*
- * This function is called (repeatedly) until the has withered away.
- */
- void
- g_wither_geom_close(struct g_geom *gp, int error)
- {
- struct g_consumer *cp;
- g_topology_assert();
- G_VALID_GEOM(gp);
- g_trace(G_T_TOPOLOGY, "g_wither_geom_close(%p(%s))", gp, gp->name);
- LIST_FOREACH(cp, &gp->consumer, consumer)
- if (cp->acr || cp->acw || cp->ace)
- g_access(cp, -cp->acr, -cp->acw, -cp->ace);
- g_wither_geom(gp, error);
- }
- /*
- * This function is called (repeatedly) until we can't wash away more
- * withered bits at present.
- */
- void
- g_wither_washer(void)
- {
- struct g_class *mp;
- struct g_geom *gp, *gp2;
- struct g_provider *pp, *pp2;
- struct g_consumer *cp, *cp2;
- g_topology_assert();
- LIST_FOREACH(mp, &g_classes, class) {
- LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
- LIST_FOREACH_SAFE(pp, &gp->provider, provider, pp2) {
- if (!(pp->flags & G_PF_WITHER))
- continue;
- if (LIST_EMPTY(&pp->consumers))
- g_destroy_provider(pp);
- }
- if (!(gp->flags & G_GEOM_WITHER))
- continue;
- LIST_FOREACH_SAFE(pp, &gp->provider, provider, pp2) {
- if (LIST_EMPTY(&pp->consumers))
- g_destroy_provider(pp);
- }
- LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp2) {
- if (cp->acr || cp->acw || cp->ace)
- continue;
- if (cp->provider != NULL)
- g_detach(cp);
- g_destroy_consumer(cp);
- }
- if (LIST_EMPTY(&gp->provider) &&
- LIST_EMPTY(&gp->consumer))
- g_destroy_geom(gp);
- }
- }
- }
- struct g_consumer *
- g_new_consumer(struct g_geom *gp)
- {
- struct g_consumer *cp;
- g_topology_assert();
- G_VALID_GEOM(gp);
- KASSERT(!(gp->flags & G_GEOM_WITHER),
- ("g_new_consumer on WITHERing geom(%s) (class %s)",
- gp->name, gp->class->name));
- KASSERT(gp->orphan != NULL,
- ("g_new_consumer on geom(%s) (class %s) without orphan",
- gp->name, gp->class->name));
- cp = g_malloc(sizeof *cp, M_WAITOK | M_ZERO);
- cp->geom = gp;
- cp->stat = devstat_new_entry(cp, -1, 0, DEVSTAT_ALL_SUPPORTED,
- DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
- LIST_INSERT_HEAD(&gp->consumer, cp, consumer);
- return(cp);
- }
- void
- g_destroy_consumer(struct g_consumer *cp)
- {
- struct g_geom *gp;
- g_topology_assert();
- G_VALID_CONSUMER(cp);
- g_trace(G_T_TOPOLOGY, "g_destroy_consumer(%p)", cp);
- KASSERT (cp->provider == NULL, ("g_destroy_consumer but attached"));
- KASSERT (cp->acr == 0, ("g_destroy_consumer with acr"));
- KASSERT (cp->acw == 0, ("g_destroy_consumer with acw"));
- KASSERT (cp->ace == 0, ("g_destroy_consumer with ace"));
- g_cancel_event(cp);
- gp = cp->geom;
- LIST_REMOVE(cp, consumer);
- devstat_remove_entry(cp->stat);
- g_free(cp);
- if (gp->flags & G_GEOM_WITHER)
- g_do_wither();
- }
- static void
- g_new_provider_event(void *arg, int flag)
- {
- struct g_class *mp;
- struct g_provider *pp;
- struct g_consumer *cp, *next_cp;
- g_topology_assert();
- if (flag == EV_CANCEL)
- return;
- if (g_shutdown)
- return;
- pp = arg;
- G_VALID_PROVIDER(pp);
- if ((pp->flags & G_PF_WITHER) != 0)
- return;
- LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, next_cp) {
- if ((cp->flags & G_CF_ORPHAN) == 0 &&
- cp->geom->attrchanged != NULL)
- cp->geom->attrchanged(cp, "GEOM::media");
- }
- if (g_notaste)
- return;
- LIST_FOREACH(mp, &g_classes, class) {
- if (mp->taste == NULL)
- continue;
- LIST_FOREACH(cp, &pp->consumers, consumers)
- if (cp->geom->class == mp &&
- (cp->flags & G_CF_ORPHAN) == 0)
- break;
- if (cp != NULL)
- continue;
- mp->taste(mp, pp, 0);
- g_topology_assert();
- }
- }
- struct g_provider *
- g_new_providerf(struct g_geom *gp, const char *fmt, ...)
- {
- struct g_provider *pp;
- struct sbuf *sb;
- va_list ap;
- g_topology_assert();
- G_VALID_GEOM(gp);
- KASSERT(gp->access != NULL,
- ("new provider on geom(%s) without ->access (class %s)",
- gp->name, gp->class->name));
- KASSERT(gp->start != NULL,
- ("new provider on geom(%s) without ->start (class %s)",
- gp->name, gp->class->name));
- KASSERT(!(gp->flags & G_GEOM_WITHER),
- ("new provider on WITHERing geom(%s) (class %s)",
- gp->name, gp->class->name));
- sb = sbuf_new_auto();
- va_start(ap, fmt);
- sbuf_vprintf(sb, fmt, ap);
- va_end(ap);
- sbuf_finish(sb);
- pp = g_malloc(sizeof *pp + sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
- pp->name = (char *)(pp + 1);
- strcpy(pp->name, sbuf_data(sb));
- sbuf_delete(sb);
- LIST_INIT(&pp->consumers);
- LIST_INIT(&pp->aliases);
- pp->error = ENXIO;
- pp->geom = gp;
- pp->stat = devstat_new_entry(pp, -1, 0, DEVSTAT_ALL_SUPPORTED,
- DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
- LIST_INSERT_HEAD(&gp->provider, pp, provider);
- g_post_event(g_new_provider_event, pp, M_WAITOK, pp, gp, NULL);
- return (pp);
- }
- void
- g_provider_add_alias(struct g_provider *pp, const char *fmt, ...)
- {
- struct sbuf *sb;
- struct g_geom_alias *gap;
- va_list ap;
- /*
- * Generate the alias string and save it in the list.
- */
- sb = sbuf_new_auto();
- va_start(ap, fmt);
- sbuf_vprintf(sb, fmt, ap);
- va_end(ap);
- sbuf_finish(sb);
- LIST_FOREACH(gap, &pp->aliases, ga_next) {
- if (strcmp(gap->ga_alias, sbuf_data(sb)) != 0)
- continue;
- /* Don't re-add the same alias. */
- sbuf_delete(sb);
- return;
- }
- gap = g_malloc(sizeof(*gap) + sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
- memcpy((char *)(gap + 1), sbuf_data(sb), sbuf_len(sb));
- sbuf_delete(sb);
- gap->ga_alias = (const char *)(gap + 1);
- LIST_INSERT_HEAD(&pp->aliases, gap, ga_next);
- }
- void
- g_error_provider(struct g_provider *pp, int error)
- {
- /* G_VALID_PROVIDER(pp); We may not have g_topology */
- pp->error = error;
- }
- static void
- g_resize_provider_event(void *arg, int flag)
- {
- struct g_hh00 *hh;
- struct g_class *mp;
- struct g_geom *gp;
- struct g_provider *pp;
- struct g_consumer *cp, *cp2;
- off_t size;
- g_topology_assert();
- if (g_shutdown)
- return;
- hh = arg;
- pp = hh->pp;
- size = hh->size;
- g_free(hh);
- G_VALID_PROVIDER(pp);
- KASSERT(!(pp->flags & G_PF_WITHER),
- ("g_resize_provider_event but withered"));
- g_trace(G_T_TOPOLOGY, "g_resize_provider_event(%p)", pp);
- LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) {
- gp = cp->geom;
- if (gp->resize == NULL && size < pp->mediasize) {
- /*
- * XXX: g_dev_orphan method does deferred destroying
- * and it is possible, that other event could already
- * call the orphan method. Check consumer's flags to
- * do not schedule it twice.
- */
- if (cp->flags & G_CF_ORPHAN)
- continue;
- cp->flags |= G_CF_ORPHAN;
- cp->geom->orphan(cp);
- }
- }
- pp->mediasize = size;
- LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) {
- gp = cp->geom;
- if ((gp->flags & G_GEOM_WITHER) == 0 && gp->resize != NULL)
- gp->resize(cp);
- }
- /*
- * After resizing, the previously invalid GEOM class metadata
- * might become valid. This means we should retaste.
- */
- LIST_FOREACH(mp, &g_classes, class) {
- if (mp->taste == NULL)
- continue;
- LIST_FOREACH(cp, &pp->consumers, consumers)
- if (cp->geom->class == mp &&
- (cp->flags & G_CF_ORPHAN) == 0)
- break;
- if (cp != NULL)
- continue;
- mp->taste(mp, pp, 0);
- g_topology_assert();
- }
- }
- void
- g_resize_provider(struct g_provider *pp, off_t size)
- {
- struct g_hh00 *hh;
- G_VALID_PROVIDER(pp);
- if (pp->flags & G_PF_WITHER)
- return;
- if (size == pp->mediasize)
- return;
- hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO);
- hh->pp = pp;
- hh->size = size;
- g_post_event(g_resize_provider_event, hh, M_WAITOK, NULL);
- }
- struct g_provider *
- g_provider_by_name(char const *arg)
- {
- struct g_class *cp;
- struct g_geom *gp;
- struct g_provider *pp, *wpp;
- if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
- arg += sizeof(_PATH_DEV) - 1;
- wpp = NULL;
- LIST_FOREACH(cp, &g_classes, class) {
- LIST_FOREACH(gp, &cp->geom, geom) {
- LIST_FOREACH(pp, &gp->provider, provider) {
- if (strcmp(arg, pp->name) != 0)
- continue;
- if ((gp->flags & G_GEOM_WITHER) == 0 &&
- (pp->flags & G_PF_WITHER) == 0)
- return (pp);
- else
- wpp = pp;
- }
- }
- }
- return (wpp);
- }
- void
- g_destroy_provider(struct g_provider *pp)
- {
- struct g_geom *gp;
- struct g_geom_alias *gap, *gaptmp;
- g_topology_assert();
- G_VALID_PROVIDER(pp);
- KASSERT(LIST_EMPTY(&pp->consumers),
- ("g_destroy_provider but attached"));
- KASSERT (pp->acr == 0, ("g_destroy_provider with acr"));
- KASSERT (pp->acw == 0, ("g_destroy_provider with acw"));
- KASSERT (pp->ace == 0, ("g_destroy_provider with ace"));
- g_cancel_event(pp);
- LIST_REMOVE(pp, provider);
- gp = pp->geom;
- devstat_remove_entry(pp->stat);
- /*
- * If a callback was provided, send notification that the provider
- * is now gone.
- */
- if (gp->providergone != NULL)
- gp->providergone(pp);
- LIST_FOREACH_SAFE(gap, &pp->aliases, ga_next, gaptmp)
- g_free(gap);
- g_free(pp);
- if ((gp->flags & G_GEOM_WITHER))
- g_do_wither();
- }
- /*
- * We keep the "geoms" list sorted by topological order (== increasing
- * numerical rank) at all times.
- * When an attach is done, the attaching geoms rank is invalidated
- * and it is moved to the tail of the list.
- * All geoms later in the sequence has their ranks reevaluated in
- * sequence. If we cannot assign rank to a geom because it's
- * prerequisites do not have rank, we move that element to the tail
- * of the sequence with invalid rank as well.
- * At some point we encounter our original geom and if we stil fail
- * to assign it a rank, there must be a loop and we fail back to
- * g_attach() which detach again and calls redo_rank again
- * to fix up the damage.
- * It would be much simpler code wise to do it recursively, but we
- * can't risk that on the kernel stack.
- */
- static int
- redo_rank(struct g_geom *gp)
- {
- struct g_consumer *cp;
- struct g_geom *gp1, *gp2;
- int n, m;
- g_topology_assert();
- G_VALID_GEOM(gp);
- /* Invalidate this geoms rank and move it to the tail */
- gp1 = TAILQ_NEXT(gp, geoms);
- if (gp1 != NULL) {
- gp->rank = 0;
- TAILQ_REMOVE(&geoms, gp, geoms);
- TAILQ_INSERT_TAIL(&geoms, gp, geoms);
- } else {
- gp1 = gp;
- }
- /* re-rank the rest of the sequence */
- for (; gp1 != NULL; gp1 = gp2) {
- gp1->rank = 0;
- m = 1;
- LIST_FOREACH(cp, &gp1->consumer, consumer) {
- if (cp->provider == NULL)
- continue;
- n = cp->provider->geom->rank;
- if (n == 0) {
- m = 0;
- break;
- } else if (n >= m)
- m = n + 1;
- }
- gp1->rank = m;
- gp2 = TAILQ_NEXT(gp1, geoms);
- /* got a rank, moving on */
- if (m != 0)
- continue;
- /* no rank to original geom means loop */
- if (gp == gp1)
- return (ELOOP);
- /* no rank, put it at the end move on */
- TAILQ_REMOVE(&geoms, gp1, geoms);
- TAILQ_INSERT_TAIL(&geoms, gp1, geoms);
- }
- return (0);
- }
- int
- g_attach(struct g_consumer *cp, struct g_provider *pp)
- {
- int error;
- g_topology_assert();
- G_VALID_CONSUMER(cp);
- G_VALID_PROVIDER(pp);
- g_trace(G_T_TOPOLOGY, "g_attach(%p, %p)", cp, pp);
- KASSERT(cp->provider == NULL, ("attach but attached"));
- if ((pp->flags & (G_PF_ORPHAN | G_PF_WITHER)) != 0)
- return (ENXIO);
- cp->provider = pp;
- cp->flags &= ~G_CF_ORPHAN;
- LIST_INSERT_HEAD(&pp->consumers, cp, consumers);
- error = redo_rank(cp->geom);
- if (error) {
- LIST_REMOVE(cp, consumers);
- cp->provider = NULL;
- redo_rank(cp->geom);
- }
- return (error);
- }
- void
- g_detach(struct g_consumer *cp)
- {
- struct g_provider *pp;
- g_topology_assert();
- G_VALID_CONSUMER(cp);
- g_trace(G_T_TOPOLOGY, "g_detach(%p)", cp);
- KASSERT(cp->provider != NULL, ("detach but not attached"));
- KASSERT(cp->acr == 0, ("detach but nonzero acr"));
- KASSERT(cp->acw == 0, ("detach but nonzero acw"));
- KASSERT(cp->ace == 0, ("detach but nonzero ace"));
- KASSERT(cp->nstart == cp->nend,
- ("detach with active requests"));
- pp = cp->provider;
- LIST_REMOVE(cp, consumers);
- cp->provider = NULL;
- if ((cp->geom->flags & G_GEOM_WITHER) ||
- (pp->geom->flags & G_GEOM_WITHER) ||
- (pp->flags & G_PF_WITHER))
- g_do_wither();
- redo_rank(cp->geom);
- }
- /*
- * g_access()
- *
- * Access-check with delta values. The question asked is "can provider
- * "cp" change the access counters by the relative amounts dc[rwe] ?"
- */
- int
- g_access(struct g_consumer *cp, int dcr, int dcw, int dce)
- {
- struct g_provider *pp;
- struct g_geom *gp;
- int pw, pe;
- #ifdef INVARIANTS
- int sr, sw, se;
- #endif
- int error;
- g_topology_assert();
- G_VALID_CONSUMER(cp);
- pp = cp->provider;
- KASSERT(pp != NULL, ("access but not attached"));
- G_VALID_PROVIDER(pp);
- gp = pp->geom;
- g_trace(G_T_ACCESS, "g_access(%p(%s), %d, %d, %d)",
- cp, pp->name, dcr, dcw, dce);
- KASSERT(cp->acr + dcr >= 0, ("access resulting in negative acr"));
- KASSERT(cp->acw + dcw >= 0, ("access resulting in negative acw"));
- KASSERT(cp->ace + dce >= 0, ("access resulting in negative ace"));
- KASSERT(dcr != 0 || dcw != 0 || dce != 0, ("NOP access request"));
- KASSERT(cp->acr + dcr != 0 || cp->acw + dcw != 0 ||
- cp->ace + dce != 0 || cp->nstart == cp->nend,
- ("Last close with active requests"));
- KASSERT(gp->access != NULL, ("NULL geom->access"));
- /*
- * If our class cares about being spoiled, and we have been, we
- * are probably just ahead of the event telling us that. Fail
- * now rather than having to unravel this later.
- */
- if (cp->geom->spoiled != NULL && (cp->flags & G_CF_SPOILED) &&
- (dcr > 0 || dcw > 0 || dce > 0))
- return (ENXIO);
- /*
- * A number of GEOM classes either need to perform an I/O on the first
- * open or to acquire a different subsystem's lock. To do that they
- * may have to drop the topology lock.
- * Other GEOM classes perform special actions when opening a lower rank
- * geom for the first time. As a result, more than one thread may
- * end up performing the special actions.
- * So, we prevent concurrent "first" opens by marking the consumer with
- * special flag.
- *
- * Note that if the geom's access method never drops the topology lock,
- * then we will never see G_GEOM_IN_ACCESS here.
- */
- while ((gp->flags & G_GEOM_IN_ACCESS) != 0) {
- g_trace(G_T_ACCESS,
- "%s: race on geom %s via provider %s and consumer of %s",
- __func__, gp->name, pp->name, cp->geom->name);
- gp->flags |= G_GEOM_ACCESS_WAIT;
- g_topology_sleep(gp, 0);
- }
- /*
- * Figure out what counts the provider would have had, if this
- * consumer had (r0w0e0) at this time.
- */
- pw = pp->acw - cp->acw;
- pe = pp->ace - cp->ace;
- g_trace(G_T_ACCESS,
- "open delta:[r%dw%de%d] old:[r%dw%de%d] provider:[r%dw%de%d] %p(%s)",
- dcr, dcw, dce,
- cp->acr, cp->acw, cp->ace,
- pp->acr, pp->acw, pp->ace,
- pp, pp->name);
- /* If foot-shooting is enabled, any open on rank#1 is OK */
- if ((g_debugflags & G_F_FOOTSHOOTING) && gp->rank == 1)
- ;
- /* If we try exclusive but already write: fail */
- else if (dce > 0 && pw > 0)
- return (EPERM);
- /* If we try write but already exclusive: fail */
- else if (dcw > 0 && pe > 0)
- return (EPERM);
- /* If we try to open more but provider is error'ed: fail */
- else if ((dcr > 0 || dcw > 0 || dce > 0) && pp->error != 0) {
- printf("%s(%d): provider %s has error %d set\n",
- __func__, __LINE__, pp->name, pp->error);
- return (pp->error);
- }
- /* Ok then... */
- #ifdef INVARIANTS
- sr = cp->acr;
- sw = cp->acw;
- se = cp->ace;
- #endif
- gp->flags |= G_GEOM_IN_ACCESS;
- error = gp->access(pp, dcr, dcw, dce);
- KASSERT(dcr > 0 || dcw > 0 || dce > 0 || error == 0,
- ("Geom provider %s::%s dcr=%d dcw=%d dce=%d error=%d failed "
- "closing ->access()", gp->class->name, pp->name, dcr, dcw,
- dce, error));
- g_topology_assert();
- gp->flags &= ~G_GEOM_IN_ACCESS;
- KASSERT(cp->acr == sr && cp->acw == sw && cp->ace == se,
- ("Access counts changed during geom->access"));
- if ((gp->flags & G_GEOM_ACCESS_WAIT) != 0) {
- gp->flags &= ~G_GEOM_ACCESS_WAIT;
- wakeup(gp);
- }
- if (!error) {
- /*
- * If we open first write, spoil any partner consumers.
- * If we close last write and provider is not errored,
- * trigger re-taste.
- */
- if (pp->acw == 0 && dcw != 0)
- g_spoil(pp, cp);
- else if (pp->acw != 0 && pp->acw == -dcw && pp->error == 0 &&
- !(gp->flags & G_GEOM_WITHER))
- g_post_event(g_new_provider_event, pp, M_WAITOK,
- pp, NULL);
- pp->acr += dcr;
- pp->acw += dcw;
- pp->ace += dce;
- cp->acr += dcr;
- cp->acw += dcw;
- cp->ace += dce;
- if (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)
- KASSERT(pp->sectorsize > 0,
- ("Provider %s lacks sectorsize", pp->name));
- if ((cp->geom->flags & G_GEOM_WITHER) &&
- cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
- g_do_wither();
- }
- return (error);
- }
- int
- g_handleattr_int(struct bio *bp, const char *attribute, int val)
- {
- return (g_handleattr(bp, attribute, &val, sizeof val));
- }
- int
- g_handleattr_uint16_t(struct bio *bp, const char *attribute, uint16_t val)
- {
- return (g_handleattr(bp, attribute, &val, sizeof val));
- }
- int
- g_handleattr_off_t(struct bio *bp, const char *attribute, off_t val)
- {
- return (g_handleattr(bp, attribute, &val, sizeof val));
- }
- int
- g_handleattr_str(struct bio *bp, const char *attribute, const char *str)
- {
- return (g_handleattr(bp, attribute, str, 0));
- }
- int
- g_handleattr(struct bio *bp, const char *attribute, const void *val, int len)
- {
- int error = 0;
- if (strcmp(bp->bio_attribute, attribute))
- return (0);
- if (len == 0) {
- bzero(bp->bio_data, bp->bio_length);
- if (strlcpy(bp->bio_data, val, bp->bio_length) >=
- bp->bio_length) {
- printf("%s: %s %s bio_length %jd strlen %zu -> EFAULT\n",
- __func__, bp->bio_to->name, attribute,
- (intmax_t)bp->bio_length, strlen(val));
- error = EFAULT;
- }
- } else if (bp->bio_length == len) {
- bcopy(val, bp->bio_data, len);
- } else {
- printf("%s: %s %s bio_length %jd len %d -> EFAULT\n", __func__,
- bp->bio_to->name, attribute, (intmax_t)bp->bio_length, len);
- error = EFAULT;
- }
- if (error == 0)
- bp->bio_completed = bp->bio_length;
- g_io_deliver(bp, error);
- return (1);
- }
- int
- g_std_access(struct g_provider *pp,
- int dr __unused, int dw __unused, int de __unused)
- {
- g_topology_assert();
- G_VALID_PROVIDER(pp);
- return (0);
- }
- void
- g_std_done(struct bio *bp)
- {
- struct bio *bp2;
- bp2 = bp->bio_parent;
- if (bp2->bio_error == 0)
- bp2->bio_error = bp->bio_error;
- bp2->bio_completed += bp->bio_completed;
- g_destroy_bio(bp);
- bp2->bio_inbed++;
- if (bp2->bio_children == bp2->bio_inbed) {
- if (bp2->bio_cmd == BIO_SPEEDUP)
- bp2->bio_completed = bp2->bio_length;
- g_io_deliver(bp2, bp2->bio_error);
- }
- }
- /* XXX: maybe this is only g_slice_spoiled */
- void
- g_std_spoiled(struct g_consumer *cp)
- {
- struct g_geom *gp;
- struct g_provider *pp;
- g_topology_assert();
- G_VALID_CONSUMER(cp);
- g_trace(G_T_TOPOLOGY, "g_std_spoiled(%p)", cp);
- cp->flags |= G_CF_ORPHAN;
- g_detach(cp);
- gp = cp->geom;
- LIST_FOREACH(pp, &gp->provider, provider)
- g_orphan_provider(pp, ENXIO);
- g_destroy_consumer(cp);
- if (LIST_EMPTY(&gp->provider) && LIST_EMPTY(&gp->consumer))
- g_destroy_geom(gp);
- else
- gp->flags |= G_GEOM_WITHER;
- }
- /*
- * Spoiling happens when a provider is opened for writing, but consumers
- * which are configured by in-band data are attached (slicers for instance).
- * Since the write might potentially change the in-band data, such consumers
- * need to re-evaluate their existence after the writing session closes.
- * We do this by (offering to) tear them down when the open for write happens
- * in return for a re-taste when it closes again.
- * Together with the fact that such consumers grab an 'e' bit whenever they
- * are open, regardless of mode, this ends up DTRT.
- */
- static void
- g_spoil_event(void *arg, int flag)
- {
- struct g_provider *pp;
- struct g_consumer *cp, *cp2;
- g_topology_assert();
- if (flag == EV_CANCEL)
- return;
- pp = arg;
- G_VALID_PROVIDER(pp);
- g_trace(G_T_TOPOLOGY, "%s %p(%s:%s:%s)", __func__, pp,
- pp->geom->class->name, pp->geom->name, pp->name);
- for (cp = LIST_FIRST(&pp->consumers); cp != NULL; cp = cp2) {
- cp2 = LIST_NEXT(cp, consumers);
- if ((cp->flags & G_CF_SPOILED) == 0)
- continue;
- cp->flags &= ~G_CF_SPOILED;
- if (cp->geom->spoiled == NULL)
- continue;
- cp->geom->spoiled(cp);
- g_topology_assert();
- }
- }
- void
- g_spoil(struct g_provider *pp, struct g_consumer *cp)
- {
- struct g_consumer *cp2;
- g_topology_assert();
- G_VALID_PROVIDER(pp);
- G_VALID_CONSUMER(cp);
- LIST_FOREACH(cp2, &pp->consumers, consumers) {
- if (cp2 == cp)
- continue;
- /*
- KASSERT(cp2->acr == 0, ("spoiling cp->acr = %d", cp2->acr));
- KASSERT(cp2->acw == 0, ("spoiling cp->acw = %d", cp2->acw));
- */
- KASSERT(cp2->ace == 0, ("spoiling cp->ace = %d", cp2->ace));
- cp2->flags |= G_CF_SPOILED;
- }
- g_post_event(g_spoil_event, pp, M_WAITOK, pp, NULL);
- }
- static void
- g_media_changed_event(void *arg, int flag)
- {
- struct g_provider *pp;
- int retaste;
- g_topology_assert();
- if (flag == EV_CANCEL)
- return;
- pp = arg;
- G_VALID_PROVIDER(pp);
- /*
- * If provider was not open for writing, queue retaste after spoiling.
- * If it was, retaste will happen automatically on close.
- */
- retaste = (pp->acw == 0 && pp->error == 0 &&
- !(pp->geom->flags & G_GEOM_WITHER));
- g_spoil_event(arg, flag);
- if (retaste)
- g_post_event(g_new_provider_event, pp, M_WAITOK, pp, NULL);
- }
- int
- g_media_changed(struct g_provider *pp, int flag)
- {
- struct g_consumer *cp;
- LIST_FOREACH(cp, &pp->consumers, consumers)
- cp->flags |= G_CF_SPOILED;
- return (g_post_event(g_media_changed_event, pp, flag, pp, NULL));
- }
- int
- g_media_gone(struct g_provider *pp, int flag)
- {
- struct g_consumer *cp;
- LIST_FOREACH(cp, &pp->consumers, consumers)
- cp->flags |= G_CF_SPOILED;
- return (g_post_event(g_spoil_event, pp, flag, pp, NULL));
- }
- int
- g_getattr__(const char *attr, struct g_consumer *cp, void *var, int len)
- {
- int error, i;
- i = len;
- error = g_io_getattr(attr, cp, &i, var);
- if (error)
- return (error);
- if (i != len)
- return (EINVAL);
- return (0);
- }
- static int
- g_get_device_prefix_len(const char *name)
- {
- int len;
- if (strncmp(name, "ada", 3) == 0)
- len = 3;
- else if (strncmp(name, "ad", 2) == 0)
- len = 2;
- else
- return (0);
- if (name[len] < '0' || name[len] > '9')
- return (0);
- do {
- len++;
- } while (name[len] >= '0' && name[len] <= '9');
- return (len);
- }
- int
- g_compare_names(const char *namea, const char *nameb)
- {
- int deva, devb;
- if (strcmp(namea, nameb) == 0)
- return (1);
- deva = g_get_device_prefix_len(namea);
- if (deva == 0)
- return (0);
- devb = g_get_device_prefix_len(nameb);
- if (devb == 0)
- return (0);
- if (strcmp(namea + deva, nameb + devb) == 0)
- return (1);
- return (0);
- }
- #if defined(DIAGNOSTIC) || defined(DDB)
- /*
- * This function walks the mesh and returns a non-zero integer if it
- * finds the argument pointer is an object. The return value indicates
- * which type of object it is believed to be. If topology is not locked,
- * this function is potentially dangerous, but we don't assert that the
- * topology lock is held when called from debugger.
- */
- int
- g_valid_obj(void const *ptr)
- {
- struct g_class *mp;
- struct g_geom *gp;
- struct g_consumer *cp;
- struct g_provider *pp;
- #ifdef KDB
- if (kdb_active == 0)
- #endif
- g_topology_assert();
- LIST_FOREACH(mp, &g_classes, class) {
- if (ptr == mp)
- return (1);
- LIST_FOREACH(gp, &mp->geom, geom) {
- if (ptr == gp)
- return (2);
- LIST_FOREACH(cp, &gp->consumer, consumer)
- if (ptr == cp)
- return (3);
- LIST_FOREACH(pp, &gp->provider, provider)
- if (ptr == pp)
- return (4);
- }
- }
- return(0);
- }
- #endif
- #ifdef DDB
- #define gprintf(...) do { \
- db_printf("%*s", indent, ""); \
- db_printf(__VA_ARGS__); \
- } while (0)
- #define gprintln(...) do { \
- gprintf(__VA_ARGS__); \
- db_printf("\n"); \
- } while (0)
- #define ADDFLAG(obj, flag, sflag) do { \
- if ((obj)->flags & (flag)) { \
- if (comma) \
- strlcat(str, ",", size); \
- strlcat(str, (sflag), size); \
- comma = 1; \
- } \
- } while (0)
- static char *
- provider_flags_to_string(struct g_provider *pp, char *str, size_t size)
- {
- int comma = 0;
- bzero(str, size);
- if (pp->flags == 0) {
- strlcpy(str, "NONE", size);
- return (str);
- }
- ADDFLAG(pp, G_PF_WITHER, "G_PF_WITHER");
- ADDFLAG(pp, G_PF_ORPHAN, "G_PF_ORPHAN");
- return (str);
- }
- static char *
- geom_flags_to_string(struct g_geom *gp, char *str, size_t size)
- {
- int comma = 0;
- bzero(str, size);
- if (gp->flags == 0) {
- strlcpy(str, "NONE", size);
- return (str);
- }
- ADDFLAG(gp, G_GEOM_WITHER, "G_GEOM_WITHER");
- return (str);
- }
- static void
- db_show_geom_consumer(int indent, struct g_consumer *cp)
- {
- if (indent == 0) {
- gprintln("consumer: %p", cp);
- gprintln(" class: %s (%p)", cp->geom->class->name,
- cp->geom->class);
- gprintln(" geom: %s (%p)", cp->geom->name, cp->geom);
- if (cp->provider == NULL)
- gprintln(" provider: none");
- else {
- gprintln(" provider: %s (%p)", cp->provider->name,
- cp->provider);
- }
- gprintln(" access: r%dw%de%d", cp->acr, cp->acw, cp->ace);
- gprintln(" flags: 0x%04x", cp->flags);
- #ifdef INVARIANTS
- gprintln(" nstart: %u", cp->nstart);
- gprintln(" nend: %u", cp->nend);
- #endif
- } else {
- gprintf("consumer: %p (%s), access=r%dw%de%d", cp,
- cp->provider != NULL ? cp->provider->name : "none",
- cp->acr, cp->acw, cp->ace);
- if (cp->flags)
- db_printf(", flags=0x%04x", cp->flags);
- db_printf("\n");
- }
- }
- static void
- db_show_geom_provider(int indent, struct g_provider *pp)
- {
- struct g_consumer *cp;
- char flags[64];
- if (indent == 0) {
- gprintln("provider: %s (%p)", pp->name, pp);
- gprintln(" class: %s (%p)", pp->geom->class->name,
- pp->geom->class);
- gprintln(" geom: %s (%p)", pp->geom->name, pp->geom);
- gprintln(" mediasize: %jd", (intmax_t)pp->mediasize);
- gprintln(" sectorsize: %u", pp->sectorsize);
- gprintln(" stripesize: %ju", (uintmax_t)pp->stripesize);
- gprintln(" stripeoffset: %ju", (uintmax_t)pp->stripeoffset);
- gprintln(" access: r%dw%de%d", pp->acr, pp->acw,
- pp->ace);
- gprintln(" flags: %s (0x%04x)",
- provider_flags_to_string(pp, flags, sizeof(flags)),
- pp->flags);
- gprintln(" error: %d", pp->error);
- if (LIST_EMPTY(&pp->consumers))
- gprintln(" consumers: none");
- } else {
- gprintf("provider: %s (%p), access=r%dw%de%d",
- pp->name, pp, pp->acr, pp->acw, pp->ace);
- if (pp->flags != 0) {
- db_printf(", flags=%s (0x%04x)",
- provider_flags_to_string(pp, flags, sizeof(flags)),
- pp->flags);
- }
- db_printf("\n");
- }
- if (!LIST_EMPTY(&pp->consumers)) {
- LIST_FOREACH(cp, &pp->consumers, consumers) {
- db_show_geom_consumer(indent + 2, cp);
- if (db_pager_quit)
- break;
- }
- }
- }
- static void
- db_show_geom_geom(int indent, struct g_geom *gp)
- {
- struct g_provider *pp;
- struct g_consumer *cp;
- char flags[64];
- if (indent == 0) {
- gprintln("geom: %s (%p)", gp->name, gp);
- gprintln(" class: %s (%p)", gp->class->name, gp->class);
- gprintln(" flags: %s (0x%04x)",
- geom_flags_to_string(gp, flags, sizeof(flags)), gp->flags);
- gprintln(" rank: %d", gp->rank);
- if (LIST_EMPTY(&gp->provider))
- gprintln(" providers: none");
- if (LIST_EMPTY(&gp->consumer))
- gprintln(" consumers: none");
- } else {
- gprintf("geom: %s (%p), rank=%d", gp->name, gp, gp->rank);
- if (gp->flags != 0) {
- db_printf(", flags=%s (0x%04x)",
- geom_flags_to_string(gp, flags, sizeof(flags)),
- gp->flags);
- }
- db_printf("\n");
- }
- if (!LIST_EMPTY(&gp->provider)) {
- LIST_FOREACH(pp, &gp->provider, provider) {
- db_show_geom_provider(indent + 2, pp);
- if (db_pager_quit)
- break;
- }
- }
- if (!LIST_EMPTY(&gp->consumer)) {
- LIST_FOREACH(cp, &gp->consumer, consumer) {
- db_show_geom_consumer(indent + 2, cp);
- if (db_pager_quit)
- break;
- }
- }
- }
- static void
- db_show_geom_class(struct g_class *mp)
- {
- struct g_geom *gp;
- db_printf("class: %s (%p)\n", mp->name, mp);
- LIST_FOREACH(gp, &mp->geom, geom) {
- db_show_geom_geom(2, gp);
- if (db_pager_quit)
- break;
- }
- }
- /*
- * Print the GEOM topology or the given object.
- */
- DB_SHOW_COMMAND(geom, db_show_geom)
- {
- struct g_class *mp;
- if (!have_addr) {
- /* No address given, print the entire topology. */
- LIST_FOREACH(mp, &g_classes, class) {
- db_show_geom_class(mp);
- db_printf("\n");
- if (db_pager_quit)
- break;
- }
- } else {
- switch (g_valid_obj((void *)addr)) {
- case 1:
- db_show_geom_class((struct g_class *)addr);
- break;
- case 2:
- db_show_geom_geom(0, (struct g_geom *)addr);
- break;
- case 3:
- db_show_geom_consumer(0, (struct g_consumer *)addr);
- break;
- case 4:
- db_show_geom_provider(0, (struct g_provider *)addr);
- break;
- default:
- db_printf("Not a GEOM object.\n");
- break;
- }
- }
- }
- static void
- db_print_bio_cmd(struct bio *bp)
- {
- db_printf(" cmd: ");
- switch (bp->bio_cmd) {
- case BIO_READ: db_printf("BIO_READ"); break;
- case BIO_WRITE: db_printf("BIO_WRITE"); break;
- case BIO_DELETE: db_printf("BIO_DELETE"); break;
- case BIO_GETATTR: db_printf("BIO_GETATTR"); break;
- case BIO_FLUSH: db_printf("BIO_FLUSH"); break;
- case BIO_CMD0: db_printf("BIO_CMD0"); break;
- case BIO_CMD1: db_printf("BIO_CMD1"); break;
- case BIO_CMD2: db_printf("BIO_CMD2"); break;
- case BIO_ZONE: db_printf("BIO_ZONE"); break;
- default: db_printf("UNKNOWN"); break;
- }
- db_printf("\n");
- }
- static void
- db_print_bio_flags(struct bio *bp)
- {
- int comma;
- comma = 0;
- db_printf(" flags: ");
- if (bp->bio_flags & BIO_ERROR) {
- db_printf("BIO_ERROR");
- comma = 1;
- }
- if (bp->bio_flags & BIO_DONE) {
- db_printf("%sBIO_DONE", (comma ? ", " : ""));
- comma = 1;
- }
- if (bp->bio_flags & BIO_ONQUEUE)
- db_printf("%sBIO_ONQUEUE", (comma ? ", " : ""));
- db_printf("\n");
- }
- /*
- * Print useful information in a BIO
- */
- DB_SHOW_COMMAND(bio, db_show_bio)
- {
- struct bio *bp;
- if (have_addr) {
- bp = (struct bio *)addr;
- db_printf("BIO %p\n", bp);
- db_print_bio_cmd(bp);
- db_print_bio_flags(bp);
- db_printf(" cflags: 0x%hx\n", bp->bio_cflags);
- db_printf(" pflags: 0x%hx\n", bp->bio_pflags);
- db_printf(" offset: %jd\n", (intmax_t)bp->bio_offset);
- db_printf(" length: %jd\n", (intmax_t)bp->bio_length);
- db_printf(" bcount: %ld\n", bp->bio_bcount);
- db_printf(" resid: %ld\n", bp->bio_resid);
- db_printf(" completed: %jd\n", (intmax_t)bp->bio_completed);
- db_printf(" children: %u\n", bp->bio_children);
- db_printf(" inbed: %u\n", bp->bio_inbed);
- db_printf(" error: %d\n", bp->bio_error);
- db_printf(" parent: %p\n", bp->bio_parent);
- db_printf(" driver1: %p\n", bp->bio_driver1);
- db_printf(" driver2: %p\n", bp->bio_driver2);
- db_printf(" caller1: %p\n", bp->bio_caller1);
- db_printf(" caller2: %p\n", bp->bio_caller2);
- db_printf(" bio_from: %p\n", bp->bio_from);
- db_printf(" bio_to: %p\n", bp->bio_to);
- #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
- db_printf(" bio_track_bp: %p\n", bp->bio_track_bp);
- #endif
- }
- }
- #undef gprintf
- #undef gprintln
- #undef ADDFLAG
- #endif /* DDB */
|