summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_conf.c2
-rw-r--r--sys/kern/subr_unit.c35
-rw-r--r--sys/sys/systm.h2
3 files changed, 38 insertions, 1 deletions
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
index 20d3bc3..751f524 100644
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -617,6 +617,7 @@ make_dev_credv(int flags, struct cdevsw *devsw, int minornr,
dev->si_mode = mode;
devfs_create(dev);
+ clean_unrhdrl(devfs_inos);
dev_unlock();
return (dev);
}
@@ -703,6 +704,7 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...)
va_end(ap);
devfs_create(dev);
+ clean_unrhdrl(devfs_inos);
dev_unlock();
dev_depends(pdev, dev);
return (dev);
diff --git a/sys/kern/subr_unit.c b/sys/kern/subr_unit.c
index 764f26f..4cd77b0 100644
--- a/sys/kern/subr_unit.c
+++ b/sys/kern/subr_unit.c
@@ -197,6 +197,8 @@ struct unrhdr {
u_int first; /* items in allocated from start */
u_int last; /* items free at end */
struct mtx *mtx;
+ TAILQ_HEAD(unrfr,unr) ppfree; /* Items to be freed after mtx
+ lock dropped */
};
@@ -281,9 +283,35 @@ new_unr(struct unrhdr *uh, void **p1, void **p2)
static __inline void
delete_unr(struct unrhdr *uh, void *ptr)
{
+ struct unr *up;
uh->alloc--;
- Free(ptr);
+ up = ptr;
+ TAILQ_INSERT_TAIL(&uh->ppfree, up, list);
+}
+
+void
+clean_unrhdrl(struct unrhdr *uh)
+{
+ struct unr *up;
+
+ mtx_assert(uh->mtx, MA_OWNED);
+ while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) {
+ TAILQ_REMOVE(&uh->ppfree, up, list);
+ mtx_unlock(uh->mtx);
+ Free(up);
+ mtx_lock(uh->mtx);
+ }
+
+}
+
+void
+clean_unrhdr(struct unrhdr *uh)
+{
+
+ mtx_lock(uh->mtx);
+ clean_unrhdrl(uh);
+ mtx_unlock(uh->mtx);
}
/*
@@ -305,6 +333,7 @@ new_unrhdr(int low, int high, struct mtx *mutex)
else
uh->mtx = &unitmtx;
TAILQ_INIT(&uh->head);
+ TAILQ_INIT(&uh->ppfree);
uh->low = low;
uh->high = high;
uh->first = 0;
@@ -320,6 +349,8 @@ delete_unrhdr(struct unrhdr *uh)
check_unrhdr(uh, __LINE__);
KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy));
KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr"));
+ KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL,
+ ("unrhdr has postponed item for free"));
Free(uh);
}
@@ -591,6 +622,7 @@ alloc_unr(struct unrhdr *uh)
mtx_lock(uh->mtx);
i = alloc_unrl(uh);
+ clean_unrhdrl(uh);
mtx_unlock(uh->mtx);
return (i);
}
@@ -719,6 +751,7 @@ free_unr(struct unrhdr *uh, u_int item)
p2 = Malloc(sizeof(struct unr));
mtx_lock(uh->mtx);
free_unrl(uh, item, &p1, &p2);
+ clean_unrhdrl(uh);
mtx_unlock(uh->mtx);
if (p1 != NULL)
Free(p1);
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 13b7ef7..e254d5a 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -342,6 +342,8 @@ int root_mounted(void);
struct unrhdr;
struct unrhdr *new_unrhdr(int low, int high, struct mtx *mutex);
void delete_unrhdr(struct unrhdr *uh);
+void clean_unrhdr(struct unrhdr *uh);
+void clean_unrhdrl(struct unrhdr *uh);
int alloc_unr(struct unrhdr *uh);
int alloc_unrl(struct unrhdr *uh);
void free_unr(struct unrhdr *uh, u_int item);
OpenPOWER on IntegriCloud