summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c
index c7be1b4..bebb0f3 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c
@@ -39,6 +39,23 @@ SYSCTL_INT(_vfs_zfs, OID_AUTO, space_map_last_hope, CTLFLAG_RDTUN,
&space_map_last_hope, 0,
"If kernel panic in space_map code on pool import, import the pool in readonly mode and backup all your data before trying this option.");
+static kmem_cache_t *space_seg_cache;
+
+void
+space_map_init(void)
+{
+ ASSERT(space_seg_cache == NULL);
+ space_seg_cache = kmem_cache_create("space_seg_cache",
+ sizeof (space_seg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+void
+space_map_fini(void)
+{
+ kmem_cache_destroy(space_seg_cache);
+ space_seg_cache = NULL;
+}
+
/*
* Space map routines.
* NOTE: caller is responsible for all locking.
@@ -148,7 +165,7 @@ again:
avl_remove(sm->sm_pp_root, ss_after);
}
ss_after->ss_start = ss_before->ss_start;
- kmem_free(ss_before, sizeof (*ss_before));
+ kmem_cache_free(space_seg_cache, ss_before);
ss = ss_after;
} else if (merge_before) {
ss_before->ss_end = end;
@@ -161,7 +178,7 @@ again:
avl_remove(sm->sm_pp_root, ss_after);
ss = ss_after;
} else {
- ss = kmem_alloc(sizeof (*ss), KM_SLEEP);
+ ss = kmem_cache_alloc(space_seg_cache, KM_SLEEP);
ss->ss_start = start;
ss->ss_end = end;
avl_insert(&sm->sm_root, ss, where);
@@ -207,7 +224,7 @@ space_map_remove(space_map_t *sm, uint64_t start, uint64_t size)
avl_remove(sm->sm_pp_root, ss);
if (left_over && right_over) {
- newseg = kmem_alloc(sizeof (*newseg), KM_SLEEP);
+ newseg = kmem_cache_alloc(space_seg_cache, KM_SLEEP);
newseg->ss_start = end;
newseg->ss_end = ss->ss_end;
ss->ss_end = start;
@@ -220,7 +237,7 @@ space_map_remove(space_map_t *sm, uint64_t start, uint64_t size)
ss->ss_start = end;
} else {
avl_remove(&sm->sm_root, ss);
- kmem_free(ss, sizeof (*ss));
+ kmem_cache_free(space_seg_cache, ss);
ss = NULL;
}
@@ -260,7 +277,7 @@ space_map_vacate(space_map_t *sm, space_map_func_t *func, space_map_t *mdest)
while ((ss = avl_destroy_nodes(&sm->sm_root, &cookie)) != NULL) {
if (func != NULL)
func(mdest, ss->ss_start, ss->ss_end - ss->ss_start);
- kmem_free(ss, sizeof (*ss));
+ kmem_cache_free(space_seg_cache, ss);
}
sm->sm_space = 0;
}
@@ -432,7 +449,7 @@ space_map_sync(space_map_t *sm, uint8_t maptype,
spa_t *spa = dmu_objset_spa(os);
void *cookie = NULL;
space_seg_t *ss;
- uint64_t bufsize, start, size, run_len;
+ uint64_t bufsize, start, size, run_len, delta, sm_space;
uint64_t *entry, *entry_map, *entry_map_end;
ASSERT(MUTEX_HELD(sm->sm_lock));
@@ -461,11 +478,13 @@ space_map_sync(space_map_t *sm, uint8_t maptype,
SM_DEBUG_SYNCPASS_ENCODE(spa_sync_pass(spa)) |
SM_DEBUG_TXG_ENCODE(dmu_tx_get_txg(tx));
+ delta = 0;
+ sm_space = sm->sm_space;
while ((ss = avl_destroy_nodes(&sm->sm_root, &cookie)) != NULL) {
size = ss->ss_end - ss->ss_start;
start = (ss->ss_start - sm->sm_start) >> sm->sm_shift;
- sm->sm_space -= size;
+ delta += size;
size >>= sm->sm_shift;
while (size) {
@@ -487,7 +506,7 @@ space_map_sync(space_map_t *sm, uint8_t maptype,
start += run_len;
size -= run_len;
}
- kmem_free(ss, sizeof (*ss));
+ kmem_cache_free(space_seg_cache, ss);
}
if (entry != entry_map) {
@@ -499,8 +518,15 @@ space_map_sync(space_map_t *sm, uint8_t maptype,
smo->smo_objsize += size;
}
+ /*
+ * Ensure that the space_map's accounting wasn't changed
+ * while we were in the middle of writing it out.
+ */
+ VERIFY3U(sm->sm_space, ==, sm_space);
+
zio_buf_free(entry_map, bufsize);
+ sm->sm_space -= delta;
VERIFY0(sm->sm_space);
}
OpenPOWER on IntegriCloud