With this patch it is safe to kldload/kldunload raidframe.ko (if there are no valid components in system). What was done: - There was bogus allocation of raidctl, it was fixed. - We're checking in rf_taste() if initialization process goes correct. - On shutdown, resources allocated in rf_startup() are freed. - We don't use autoconf_head list to put tasted providers there, rf_create_auto_sets() function was definitely removed, we're now adding every matching provider it its set directly. - Added hack to detect if we're tasting last provider when our geom class is beeing loaded (GEOM gives us a chance to taste every active provider). It is needed for now, because its tell us when to call function for arrays configuration. - Returned type of rf_does_it_fit() function was changed to boolean_t. diff -ruP raidframe.2004.01.14/rf_freebsdkintf.c raidframe/rf_freebsdkintf.c --- raidframe.2004.01.14/rf_freebsdkintf.c Wed Jan 14 11:00:42 2004 +++ raidframe/rf_freebsdkintf.c Wed Jan 14 10:24:40 2004 @@ -158,6 +158,7 @@ #include #include #include +#include #include #include @@ -253,7 +254,7 @@ #define RAIDOUTSTANDING 10 #endif -struct raidctl_softc *raidctl; +struct raidctl_softc *raidctl = NULL; /* prototypes */ static void KernelWakeupFunc(struct bio *); @@ -275,8 +276,7 @@ static void rf_RewriteParityThread(RF_Raid_t *raidPtr); static void rf_CopybackThread(RF_Raid_t *raidPtr); static void rf_ReconstructInPlaceThread(struct rf_recon_req *); -static void rf_create_auto_sets(void); -static int rf_does_it_fit(RF_ConfigSet_t *,RF_AutoConfig_t *); +static boolean_t rf_does_it_fit(RF_ConfigSet_t *,RF_AutoConfig_t *); static int rf_reasonable_label(RF_ComponentLabel_t *); #ifdef not_used static void rf_create_configuration(RF_AutoConfig_t *,RF_Config_t *, @@ -303,11 +303,15 @@ static g_orphan_t rf_component_orphan; static void -rf_startup(struct g_class *mp) +rf_startup(struct g_class *mp __unused) { dev_t dev; /* This is where all the initialization stuff gets done. */ + /* + * XXX: We should panic if something goes wrong here, or we should + * check if raidctl is not NULL in rf_taste() ? + */ if(rf_mutex_init(&rf_sparet_wait_mutex, __FUNCTION__)) { rf_printf(0, "RAIDframe: failed to initialize mutexes\n"); @@ -316,8 +320,9 @@ rf_sparet_wait_queue = rf_sparet_resp_queue = NULL; - if ((raidctl = malloc(sizeof(struct raidctl_softc), M_RAIDFRAME, - M_NOWAIT | M_ZERO)) == NULL); + raidctl = malloc(sizeof(struct raidctl_softc), M_RAIDFRAME, + M_NOWAIT | M_ZERO); + if (raidctl == NULL) return; TAILQ_INIT(&raidctl->autoconf_head); @@ -329,8 +334,10 @@ rf_printf(0, "Serious error booting RAIDframe!!\n"); destroy_dev(dev); free(raidctl, M_RAIDFRAME); + raidctl = NULL; return; } + rf_printf(0, "Kernelized RAIDframe activated\n"); } @@ -358,7 +365,10 @@ #endif } + rf_UnbootRaidframe(); destroy_dev(raidctl->dev); + free(raidctl, M_RAIDFRAME); + rf_mutex_destroy(&rf_sparet_wait_mutex); return; } @@ -428,6 +438,74 @@ g_io_deliver(bp, EOPNOTSUPP); } +static void +rf_add_provider(RF_AutoConfig_t *ac) +{ + RF_ConfigSet_t *cset; + + TAILQ_INIT(&raidctl->cset_head); + + if (TAILQ_EMPTY(&raidctl->cset_head)) { + /* will need at least this one... */ + cset = malloc(sizeof(RF_ConfigSet_t), M_RAIDFRAME, + M_ZERO | M_NOWAIT); + KASSERT(cset != NULL, ("rf_create_auto_sets: No memory!")); + /* this one is easy :) */ + TAILQ_INIT(&cset->ac_head); + TAILQ_INSERT_TAIL(&cset->ac_head, ac, ac_link); + TAILQ_INSERT_TAIL(&raidctl->cset_head, cset, cset_link); + cset->rootable = 0; + } else { + int ac_claimed = 0; + + /* which set does this component fit into? */ + TAILQ_FOREACH(cset, &raidctl->cset_head, cset_link) { + if (rf_does_it_fit(cset, ac)) { + /* looks like it matches... */ + TAILQ_INSERT_TAIL(&cset->ac_head, ac, ac_link); + ac_claimed = 1; + break; + } + } + if (ac_claimed == 0) { + /* didn't find a match above... new set..*/ + cset = malloc(sizeof(RF_ConfigSet_t), M_RAIDFRAME, + M_ZERO | M_NOWAIT); + KASSERT(cset != NULL, + ("rf_create_auto_sets: No memory!")); + TAILQ_INSERT_TAIL(&cset->ac_head, ac, ac_link); + TAILQ_INSERT_TAIL(&raidctl->cset_head, cset, cset_link); + cset->rootable = 0; + } + } +} + +/* + * XXX: HACK!! + * This function is checking if given provider is the last one that + * could be tasted. + */ +static boolean_t +rf_last_provider(struct g_class *myclass, struct g_provider *pp) +{ + struct g_class *mp; + struct g_geom *gp; + struct g_provider *pp2, *lastpp = NULL; + + for (mp = pp->geom->class; mp != NULL; mp = LIST_NEXT(mp, class)) { + if (mp == myclass) + continue; + LIST_FOREACH(gp, &mp->geom, geom) { + LIST_FOREACH(pp2, &gp->provider, provider) + lastpp = pp2; + } + } + + if (lastpp == pp) + return (1); + return (0); +} + static struct g_geom * rf_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) { @@ -435,17 +513,37 @@ struct g_geom *gp; struct g_consumer *cp; RF_ComponentLabel_t *clabel; + static int first_taste = 1; int error; + /* + * Initialization process failed? + */ + if (raidctl == NULL) + return (NULL); + + /* + * From now on, on every failure we have to jump to 'out' label, + * because we need to check if this wasn't last provider + * in first taste events (when class is loaded). + * This is quite hackish, because for now RF starts + * building arrays if it has all providers. + */ + rf_printf(0, "rf_taste called on %s, %s\n", mp->name, pp->name); + ac = NULL; + cp = NULL; + gp = NULL; + clabel = malloc(sizeof(RF_ComponentLabel_t), M_RAIDFRAME, - M_NOWAIT | M_ZERO); + M_NOWAIT | M_ZERO); if (clabel == NULL) - return (NULL); + goto out; g_topology_assert(); gp = g_new_geomf(mp, "%s.rftaste", pp->name); + gp->softc = NULL; gp->start = rf_component_start; gp->spoiled = rf_component_orphan; @@ -453,15 +551,11 @@ gp->access = rf_component_access; cp = g_new_consumer(gp); g_attach(cp, pp); - if (g_access_rel(cp, 1, 0, 0) != 0) { - g_detach(cp); - g_destroy_consumer(cp); - g_destroy_geom(gp); - free(clabel, M_RAIDFRAME); - return (NULL); - } + if (g_access_rel(cp, 1, 0, 0) != 0) + goto out; g_topology_unlock(); error = raidread_component_label((RF_Device_t)cp, clabel); + g_topology_lock(); if (error || rf_reasonable_label(clabel) == 0) { if (error) rf_printf(0, "Error %d reading component label!\n", @@ -475,26 +569,42 @@ ac->dev = (RF_Device_t)cp; ac->clabel = clabel; bcopy(pp->name, ac->devname, 56); - TAILQ_INSERT_TAIL(&raidctl->autoconf_head, ac, ac_link); + rf_add_provider(ac); gp->softc = ac; - - /* - * If this is post-boot, what is the right way to process the autoconf - * set? - * rf_create_auto_sets(); - */ - out: - g_topology_lock(); - g_access_rel(cp, -1, 0, 0); - if (gp->softc != NULL) + if (cp != NULL) + g_access_rel(cp, -1, 0, 0); + if (rf_last_provider(mp, pp)) { + if (atomic_cmpset_int(&first_taste, 1, 0)) { + printf("LAST Provider: %s\n", pp->name); + /* + * XXX: Call rescan function. + * For now returned 'gp' is not used by GEOM + * so rescan function could be called directly + * from here, if it will change, we have to + * call rescan function from event queue. + */ + } + } + if (gp != NULL && gp->softc != NULL) return (gp); /* Nothing found */ - g_detach(cp); - g_destroy_consumer(cp); - g_destroy_geom(gp); - free(clabel, M_RAIDFRAME); + /* XXX: Cannot happend, because there is no place for failure + after memory for 'ac' is allocated. + If this will be possible, we need to call rescan function + after removal of this element, now it is called before. + if (ac != NULL) + rf_remove_provider(ac); + */ + if (cp != NULL) { + g_detach(cp); + g_destroy_consumer(cp); + } + if (gp != NULL) + g_destroy_geom(gp); + if (clabel != NULL) + free(clabel, M_RAIDFRAME); return (NULL); } @@ -2187,59 +2297,7 @@ } -static void -rf_create_auto_sets(void) -{ - RF_AutoConfig_t *ac; - RF_ConfigSet_t *cset; - - TAILQ_INIT(&raidctl->cset_head); - - /* Go through the AutoConfig list, and figure out which components - belong to what sets. */ - TAILQ_FOREACH(ac, &raidctl->autoconf_head, ac_link) { - if (TAILQ_EMPTY(&raidctl->cset_head)) { - /* will need at least this one... */ - cset = malloc(sizeof(RF_ConfigSet_t), M_RAIDFRAME, - M_ZERO | M_NOWAIT); - if (cset == NULL) { - panic("rf_create_auto_sets: No memory!\n"); - } - /* this one is easy :) */ - TAILQ_INIT(&cset->ac_head); - TAILQ_INSERT_TAIL(&cset->ac_head, ac, ac_link); - TAILQ_INSERT_TAIL(&raidctl->cset_head, cset, cset_link); - cset->rootable = 0; - } else { - int ac_claimed = 0; - - /* which set does this component fit into? */ - TAILQ_FOREACH(cset, &raidctl->cset_head, cset_link) { - if (rf_does_it_fit(cset, ac)) { - /* looks like it matches... */ - TAILQ_INSERT_TAIL(&cset->ac_head, ac, - ac_link); - ac_claimed = 1; - break; - } - } - if (ac_claimed == 0) { - /* didn't find a match above... new set..*/ - cset = malloc(sizeof(RF_ConfigSet_t), - M_RAIDFRAME, M_ZERO | M_NOWAIT); - if (cset == NULL) { - panic("rf_create_auto_sets: No memory!\n"); - } - TAILQ_INSERT_TAIL(&cset->ac_head, ac, ac_link); - TAILQ_INSERT_TAIL(&raidctl->cset_head, cset, - cset_link); - cset->rootable = 0; - } - } - } -} - -static int +static boolean_t rf_does_it_fit(cset, ac) RF_ConfigSet_t *cset; RF_AutoConfig_t *ac; @@ -2715,7 +2773,6 @@ static void rf_complete_autoconf(void) { - rf_create_auto_sets(); #ifdef not_yet rf_auto_config_set(); #endif