Changeset View
Changeset View
Standalone View
Standalone View
head/sys/geom/journal/g_journal.c
Show First 20 Lines • Show All 221 Lines • ▼ Show 20 Lines | struct g_class g_journal_class = { | ||||
.ctlreq = g_journal_config, | .ctlreq = g_journal_config, | ||||
.dumpconf = g_journal_dumpconf, | .dumpconf = g_journal_dumpconf, | ||||
.init = g_journal_init, | .init = g_journal_init, | ||||
.fini = g_journal_fini | .fini = g_journal_fini | ||||
}; | }; | ||||
static int g_journal_destroy(struct g_journal_softc *sc); | static int g_journal_destroy(struct g_journal_softc *sc); | ||||
static void g_journal_metadata_update(struct g_journal_softc *sc); | static void g_journal_metadata_update(struct g_journal_softc *sc); | ||||
static void g_journal_start_switcher(struct g_class *mp); | |||||
static void g_journal_stop_switcher(void); | |||||
static void g_journal_switch_wait(struct g_journal_softc *sc); | static void g_journal_switch_wait(struct g_journal_softc *sc); | ||||
#define GJ_SWITCHER_WORKING 0 | #define GJ_SWITCHER_WORKING 0 | ||||
#define GJ_SWITCHER_DIE 1 | #define GJ_SWITCHER_DIE 1 | ||||
#define GJ_SWITCHER_DIED 2 | #define GJ_SWITCHER_DIED 2 | ||||
static struct proc *g_journal_switcher_proc = NULL; | |||||
static int g_journal_switcher_state = GJ_SWITCHER_WORKING; | static int g_journal_switcher_state = GJ_SWITCHER_WORKING; | ||||
static int g_journal_switcher_wokenup = 0; | static int g_journal_switcher_wokenup = 0; | ||||
static int g_journal_sync_requested = 0; | static int g_journal_sync_requested = 0; | ||||
#ifdef GJ_MEMDEBUG | #ifdef GJ_MEMDEBUG | ||||
struct meminfo { | struct meminfo { | ||||
size_t mi_size; | size_t mi_size; | ||||
struct stack mi_stack; | struct stack mi_stack; | ||||
▲ Show 20 Lines • Show All 2,135 Lines • ▼ Show 20 Lines | if (cp == NULL) { | ||||
* Journal is on the same provider as data, which means | * Journal is on the same provider as data, which means | ||||
* that data provider ends where journal starts. | * that data provider ends where journal starts. | ||||
*/ | */ | ||||
sc->sc_mediasize = md->md_jstart; | sc->sc_mediasize = md->md_jstart; | ||||
} | } | ||||
sc->sc_jconsumer = cp; | sc->sc_jconsumer = cp; | ||||
} | } | ||||
/* Start switcher kproc if needed. */ | |||||
if (g_journal_switcher_proc == NULL) | |||||
g_journal_start_switcher(mp); | |||||
if ((sc->sc_type & GJ_TYPE_COMPLETE) != GJ_TYPE_COMPLETE) { | if ((sc->sc_type & GJ_TYPE_COMPLETE) != GJ_TYPE_COMPLETE) { | ||||
/* Journal is not complete yet. */ | /* Journal is not complete yet. */ | ||||
return (gp); | return (gp); | ||||
} else { | } else { | ||||
/* Journal complete, cancel timeout. */ | /* Journal complete, cancel timeout. */ | ||||
callout_drain(&sc->sc_callout); | callout_drain(&sc->sc_callout); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 360 Lines • ▼ Show 20 Lines | g_journal_lowmem(void *arg, int howto __unused) | ||||
g_topology_unlock(); | g_topology_unlock(); | ||||
} | } | ||||
static void g_journal_switcher(void *arg); | static void g_journal_switcher(void *arg); | ||||
static void | static void | ||||
g_journal_init(struct g_class *mp) | g_journal_init(struct g_class *mp) | ||||
{ | { | ||||
int error; | |||||
/* Pick a conservative value if provided value sucks. */ | /* Pick a conservative value if provided value sucks. */ | ||||
if (g_journal_cache_divisor <= 0 || | if (g_journal_cache_divisor <= 0 || | ||||
(vm_kmem_size / g_journal_cache_divisor == 0)) { | (vm_kmem_size / g_journal_cache_divisor == 0)) { | ||||
g_journal_cache_divisor = 5; | g_journal_cache_divisor = 5; | ||||
} | } | ||||
if (g_journal_cache_limit > 0) { | if (g_journal_cache_limit > 0) { | ||||
g_journal_cache_limit = vm_kmem_size / g_journal_cache_divisor; | g_journal_cache_limit = vm_kmem_size / g_journal_cache_divisor; | ||||
g_journal_cache_low = | g_journal_cache_low = | ||||
(g_journal_cache_limit / 100) * g_journal_cache_switch; | (g_journal_cache_limit / 100) * g_journal_cache_switch; | ||||
} | } | ||||
g_journal_event_shutdown = EVENTHANDLER_REGISTER(shutdown_post_sync, | g_journal_event_shutdown = EVENTHANDLER_REGISTER(shutdown_post_sync, | ||||
g_journal_shutdown, mp, EVENTHANDLER_PRI_FIRST); | g_journal_shutdown, mp, EVENTHANDLER_PRI_FIRST); | ||||
if (g_journal_event_shutdown == NULL) | if (g_journal_event_shutdown == NULL) | ||||
GJ_DEBUG(0, "Warning! Cannot register shutdown event."); | GJ_DEBUG(0, "Warning! Cannot register shutdown event."); | ||||
g_journal_event_lowmem = EVENTHANDLER_REGISTER(vm_lowmem, | g_journal_event_lowmem = EVENTHANDLER_REGISTER(vm_lowmem, | ||||
g_journal_lowmem, mp, EVENTHANDLER_PRI_FIRST); | g_journal_lowmem, mp, EVENTHANDLER_PRI_FIRST); | ||||
if (g_journal_event_lowmem == NULL) | if (g_journal_event_lowmem == NULL) | ||||
GJ_DEBUG(0, "Warning! Cannot register lowmem event."); | GJ_DEBUG(0, "Warning! Cannot register lowmem event."); | ||||
error = kproc_create(g_journal_switcher, mp, NULL, 0, 0, | |||||
"g_journal switcher"); | |||||
KASSERT(error == 0, ("Cannot create switcher thread.")); | |||||
} | } | ||||
static void | static void | ||||
g_journal_fini(struct g_class *mp) | g_journal_fini(struct g_class *mp) | ||||
{ | { | ||||
if (g_journal_event_shutdown != NULL) { | if (g_journal_event_shutdown != NULL) { | ||||
EVENTHANDLER_DEREGISTER(shutdown_post_sync, | EVENTHANDLER_DEREGISTER(shutdown_post_sync, | ||||
g_journal_event_shutdown); | g_journal_event_shutdown); | ||||
} | } | ||||
if (g_journal_event_lowmem != NULL) | if (g_journal_event_lowmem != NULL) | ||||
EVENTHANDLER_DEREGISTER(vm_lowmem, g_journal_event_lowmem); | EVENTHANDLER_DEREGISTER(vm_lowmem, g_journal_event_lowmem); | ||||
g_journal_switcher_state = GJ_SWITCHER_DIE; | g_journal_stop_switcher(); | ||||
wakeup(&g_journal_switcher_state); | |||||
while (g_journal_switcher_state != GJ_SWITCHER_DIED) | |||||
tsleep(&g_journal_switcher_state, PRIBIO, "jfini:wait", hz / 5); | |||||
GJ_DEBUG(1, "Switcher died."); | |||||
} | } | ||||
DECLARE_GEOM_CLASS(g_journal_class, g_journal); | DECLARE_GEOM_CLASS(g_journal_class, g_journal); | ||||
static const struct g_journal_desc * | static const struct g_journal_desc * | ||||
g_journal_find_desc(const char *fstype) | g_journal_find_desc(const char *fstype) | ||||
{ | { | ||||
const struct g_journal_desc *desc; | const struct g_journal_desc *desc; | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | for (;;) { | ||||
if (sc == NULL) | if (sc == NULL) | ||||
break; | break; | ||||
mtx_assert(&sc->sc_mtx, MA_OWNED); | mtx_assert(&sc->sc_mtx, MA_OWNED); | ||||
g_journal_switch_wait(sc); | g_journal_switch_wait(sc); | ||||
mtx_unlock(&sc->sc_mtx); | mtx_unlock(&sc->sc_mtx); | ||||
} | } | ||||
} | } | ||||
static void | |||||
g_journal_start_switcher(struct g_class *mp) | |||||
{ | |||||
int error; | |||||
g_topology_assert(); | |||||
MPASS(g_journal_switcher_proc == NULL); | |||||
g_journal_switcher_state = GJ_SWITCHER_WORKING; | |||||
error = kproc_create(g_journal_switcher, mp, &g_journal_switcher_proc, | |||||
0, 0, "g_journal switcher"); | |||||
KASSERT(error == 0, ("Cannot create switcher thread.")); | |||||
} | |||||
static void | |||||
g_journal_stop_switcher(void) | |||||
{ | |||||
g_topology_assert(); | |||||
MPASS(g_journal_switcher_proc != NULL); | |||||
g_journal_switcher_state = GJ_SWITCHER_DIE; | |||||
wakeup(&g_journal_switcher_state); | |||||
while (g_journal_switcher_state != GJ_SWITCHER_DIED) | |||||
tsleep(&g_journal_switcher_state, PRIBIO, "jfini:wait", hz / 5); | |||||
GJ_DEBUG(1, "Switcher died."); | |||||
g_journal_switcher_proc = NULL; | |||||
} | |||||
/* | /* | ||||
* TODO: Switcher thread should be started on first geom creation and killed on | * TODO: Kill switcher thread on last geom destruction? | ||||
* last geom destruction. | |||||
*/ | */ | ||||
static void | static void | ||||
g_journal_switcher(void *arg) | g_journal_switcher(void *arg) | ||||
{ | { | ||||
struct g_class *mp; | struct g_class *mp; | ||||
struct bintime bt; | struct bintime bt; | ||||
int error; | int error; | ||||
Show All 26 Lines |