Extend the kernel unit number allocator for allocating specific unit

numbers. This change adds a new function alloc_unr_specific() which
returns the requested unit number if it is free. If the number is
already allocated or out of the range, -1 is returned.

Update alloc_unr(9) manual page accordingly and add a MLINK for
alloc_unr_specific(9).

Discussed on:	freebsd-hackers
This commit is contained in:
Jaakko Heinonen 2010-07-05 16:23:55 +00:00
parent 45d35a30bd
commit 13c02cbb18
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=209710
4 changed files with 181 additions and 14 deletions

View File

@ -374,6 +374,7 @@ MAN= accept_filter.9 \
zone.9
MLINKS= alloc_unr.9 alloc_unrl.9 \
alloc_unr.9 alloc_unr_specific.9 \
alloc_unr.9 delete_unrhdr.9 \
alloc_unr.9 free_unr.9 \
alloc_unr.9 new_unrhdr.9

View File

@ -24,13 +24,14 @@
.\"
.\" $FreeBSD$
.\"
.Dd February 7, 2010
.Dd July 5, 2010
.Dt ALLOC_UNR 9
.Os
.Sh NAME
.Nm new_unrhdr ,
.Nm delete_unrhdr ,
.Nm alloc_unr ,
.Nm alloc_unr_specific ,
.Nm free_unr
.Nd "kernel unit number allocator"
.Sh SYNOPSIS
@ -43,6 +44,8 @@
.Fn alloc_unr "struct unrhdr *uh"
.Ft int
.Fn alloc_unrl "struct unrhdr *uh"
.Ft int
.Fn alloc_unr_specific "struct unrhdr *uh" "u_int item"
.Ft void
.Fn free_unr "struct unrhdr *uh" "u_int item"
.Sh DESCRIPTION
@ -81,6 +84,13 @@ is returned.
Same as
.Fn alloc_unr
except that mutex is assumed to be already locked and thus is not used.
.It Fn alloc_unr_specific uh item
Allocate a specific unit number.
This function allocates memory and thus may sleep.
The allocated unit number is returned on success.
If the specified number is already allocated or out of the range,
.Li \-1
is returned.
.It Fn free_unr uh item
Free a previously allocated unit number.
This function may require allocating memory, and thus it can sleep.

View File

@ -628,6 +628,132 @@ alloc_unr(struct unrhdr *uh)
return (i);
}
static int
alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2)
{
struct unr *up, *upn;
struct unrb *ub;
u_int i, last, tl;
mtx_assert(uh->mtx, MA_OWNED);
if (item < uh->low + uh->first || item > uh->high)
return (-1);
up = TAILQ_FIRST(&uh->head);
/* Ideal split. */
if (up == NULL && item - uh->low == uh->first) {
uh->first++;
uh->last--;
uh->busy++;
check_unrhdr(uh, __LINE__);
return (item);
}
i = item - uh->low - uh->first;
if (up == NULL) {
up = new_unr(uh, p1, p2);
up->ptr = NULL;
up->len = i;
TAILQ_INSERT_TAIL(&uh->head, up, list);
up = new_unr(uh, p1, p2);
up->ptr = uh;
up->len = 1;
TAILQ_INSERT_TAIL(&uh->head, up, list);
uh->last = uh->high - uh->low - i;
uh->busy++;
check_unrhdr(uh, __LINE__);
return (item);
} else {
/* Find the item which contains the unit we want to allocate. */
TAILQ_FOREACH(up, &uh->head, list) {
if (up->len > i)
break;
i -= up->len;
}
}
if (up == NULL) {
if (i > 0) {
up = new_unr(uh, p1, p2);
up->ptr = NULL;
up->len = i;
TAILQ_INSERT_TAIL(&uh->head, up, list);
}
up = new_unr(uh, p1, p2);
up->ptr = uh;
up->len = 1;
TAILQ_INSERT_TAIL(&uh->head, up, list);
goto done;
}
if (is_bitmap(uh, up)) {
ub = up->ptr;
if (bit_test(ub->map, i) == 0) {
bit_set(ub->map, i);
ub->busy++;
goto done;
} else
return (-1);
} else if (up->ptr == uh)
return (-1);
KASSERT(up->ptr == NULL,
("alloc_unr_specificl: up->ptr != NULL (up=%p)", up));
/* Split off the tail end, if any. */
tl = up->len - (1 + i);
if (tl > 0) {
upn = new_unr(uh, p1, p2);
upn->ptr = NULL;
upn->len = tl;
TAILQ_INSERT_AFTER(&uh->head, up, upn, list);
}
/* Split off head end, if any */
if (i > 0) {
upn = new_unr(uh, p1, p2);
upn->len = i;
upn->ptr = NULL;
TAILQ_INSERT_BEFORE(up, upn, list);
}
up->len = 1;
up->ptr = uh;
done:
last = uh->high - uh->low - (item - uh->low);
if (uh->last > last)
uh->last = last;
uh->busy++;
collapse_unr(uh, up);
check_unrhdr(uh, __LINE__);
return (item);
}
int
alloc_unr_specific(struct unrhdr *uh, u_int item)
{
void *p1, *p2;
int i;
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific");
p1 = Malloc(sizeof(struct unr));
p2 = Malloc(sizeof(struct unr));
mtx_lock(uh->mtx);
i = alloc_unr_specificl(uh, item, &p1, &p2);
mtx_unlock(uh->mtx);
if (p1 != NULL)
Free(p1);
if (p2 != NULL)
Free(p2);
return (i);
}
/*
* Free a unr.
*
@ -810,6 +936,42 @@ print_unrhdr(struct unrhdr *uh)
}
}
static void
test_alloc_unr(struct unrhdr *uh, u_int i, char a[])
{
int j;
if (a[i]) {
printf("F %u\n", i);
free_unr(uh, i);
a[i] = 0;
} else {
no_alloc = 1;
j = alloc_unr(uh);
if (j != -1) {
a[j] = 1;
printf("A %d\n", j);
}
no_alloc = 0;
}
}
static void
test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[])
{
int j;
j = alloc_unr_specific(uh, i);
if (j == -1) {
printf("F %u\n", i);
a[i] = 0;
free_unr(uh, i);
} else {
a[i] = 1;
printf("A %d\n", j);
}
}
/* Number of unrs to test */
#define NN 10000
@ -825,6 +987,7 @@ main(int argc __unused, const char **argv __unused)
print_unrhdr(uh);
memset(a, 0, sizeof a);
srandomdev();
fprintf(stderr, "sizeof(struct unr) %zu\n", sizeof(struct unr));
fprintf(stderr, "sizeof(struct unrb) %zu\n", sizeof(struct unrb));
@ -838,19 +1001,11 @@ main(int argc __unused, const char **argv __unused)
if (a[i] && (j & 1))
continue;
#endif
if (a[i]) {
printf("F %u\n", i);
free_unr(uh, i);
a[i] = 0;
} else {
no_alloc = 1;
i = alloc_unr(uh);
if (i != -1) {
a[i] = 1;
printf("A %u\n", i);
}
no_alloc = 0;
}
if ((random() & 1) != 0)
test_alloc_unr(uh, i, a);
else
test_alloc_unr_specific(uh, i, a);
if (1) /* XXX: change this for detailed debug printout */
print_unrhdr(uh);
check_unrhdr(uh, __LINE__);

View File

@ -363,6 +363,7 @@ 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_unr_specific(struct unrhdr *uh, u_int item);
int alloc_unrl(struct unrhdr *uh);
void free_unr(struct unrhdr *uh, u_int item);