aboutsummaryrefslogtreecommitdiff
path: root/lib/libcuse
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2022-07-13 16:17:40 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2022-07-20 08:41:11 +0000
commitd14b53ee31ca06933a4f8ef2e48ce33cf3dd5ec9 (patch)
tree65aca21dd0d7376a8d47f5bd0f4c0ae918bcea40 /lib/libcuse
parent2ca43c3dba1b818db9245027c87fddfc9d4be0a6 (diff)
cuse(3): Allow shared memory allocations up to, but excluding 2 GBytes.
Currently the cuse(3) mmap(2) offset is split into 128 banks of 16 Mbytes. Allow cuse(3) to make allocations that span multiple banks at the expense of any fragmentation issues that may arise. Typically mmap(2) buffers are well below 16 Mbytes. This allows 8K video resolution to work using webcamd. Reviewed by: markj @ Differential Revision: https://reviews.freebsd.org/D35830 MFC after: 1 week Sponsored by: NVIDIA Networking
Diffstat (limited to 'lib/libcuse')
-rw-r--r--lib/libcuse/cuse_lib.c91
1 files changed, 42 insertions, 49 deletions
diff --git a/lib/libcuse/cuse_lib.c b/lib/libcuse/cuse_lib.c
index d241ce1dc4ac..ec300add5903 100644
--- a/lib/libcuse/cuse_lib.c
+++ b/lib/libcuse/cuse_lib.c
@@ -145,7 +145,7 @@ cuse_vmoffset(void *_ptr)
unsigned long n;
CUSE_LOCK();
- for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
+ for (n = remainder = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
if (a_cuse[n].ptr == NULL)
continue;
@@ -153,20 +153,13 @@ cuse_vmoffset(void *_ptr)
ptr_max = a_cuse[n].ptr + a_cuse[n].size - 1;
if ((ptr >= ptr_min) && (ptr <= ptr_max)) {
-
- CUSE_UNLOCK();
-
remainder = (ptr - ptr_min);
-
- remainder -= remainder %
- (unsigned long)getpagesize();
-
- return ((n * CUSE_ALLOC_BYTES_MAX) + remainder);
+ break;
}
}
CUSE_UNLOCK();
- return (0x80000000UL); /* failure */
+ return ((n << CUSE_ALLOC_UNIT_SHIFT) + remainder);
}
void *
@@ -174,70 +167,70 @@ cuse_vmalloc(int size)
{
struct cuse_alloc_info info;
unsigned long pgsize;
+ unsigned long x;
+ unsigned long m;
unsigned long n;
void *ptr;
int error;
- if (f_cuse < 0)
+ /* some sanity checks */
+ if (f_cuse < 0 || size < 1 || (unsigned long)size > CUSE_ALLOC_BYTES_MAX)
return (NULL);
memset(&info, 0, sizeof(info));
- if (size < 1)
- return (NULL);
-
pgsize = getpagesize();
info.page_count = howmany(size, pgsize);
- CUSE_LOCK();
- for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
+ /* compute how many units the allocation needs */
+ m = howmany(size, 1 << CUSE_ALLOC_UNIT_SHIFT);
+ if (m == 0 || m > CUSE_ALLOC_UNIT_MAX)
+ return (NULL);
- if (a_cuse[n].ptr != NULL)
+ CUSE_LOCK();
+ for (n = 0; n <= CUSE_ALLOC_UNIT_MAX - m; ) {
+ if (a_cuse[n].size != 0) {
+ /* skip to next available unit, depending on allocation size */
+ n += howmany(a_cuse[n].size, 1 << CUSE_ALLOC_UNIT_SHIFT);
continue;
-
- a_cuse[n].ptr = ((uint8_t *)1); /* reserve */
- a_cuse[n].size = 0;
-
+ }
+ /* check if there are "m" free units ahead */
+ for (x = 1; x != m; x++) {
+ if (a_cuse[n + x].size != 0)
+ break;
+ }
+ if (x != m) {
+ /* skip to next available unit, if any */
+ n += x + 1;
+ continue;
+ }
+ /* reserve this unit by setting the size to a non-zero value */
+ a_cuse[n].size = size;
CUSE_UNLOCK();
info.alloc_nr = n;
error = ioctl(f_cuse, CUSE_IOCTL_ALLOC_MEMORY, &info);
- if (error) {
-
- CUSE_LOCK();
-
- a_cuse[n].ptr = NULL;
-
- if (errno == EBUSY)
- continue;
- else
- break;
- }
- ptr = mmap(NULL, info.page_count * pgsize,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, f_cuse, CUSE_ALLOC_BYTES_MAX * n);
-
- if (ptr == MAP_FAILED) {
+ if (error == 0) {
+ ptr = mmap(NULL, info.page_count * pgsize,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, f_cuse, n << CUSE_ALLOC_UNIT_SHIFT);
- error = ioctl(f_cuse, CUSE_IOCTL_FREE_MEMORY, &info);
+ if (ptr != MAP_FAILED) {
+ CUSE_LOCK();
+ a_cuse[n].ptr = ptr;
+ CUSE_UNLOCK();
- if (error) {
- /* ignore */
+ return (ptr); /* success */
}
- CUSE_LOCK();
- a_cuse[n].ptr = NULL;
-
- break;
+ (void) ioctl(f_cuse, CUSE_IOCTL_FREE_MEMORY, &info);
}
- CUSE_LOCK();
- a_cuse[n].ptr = ptr;
- a_cuse[n].size = size;
- CUSE_UNLOCK();
- return (ptr); /* success */
+ CUSE_LOCK();
+ a_cuse[n].size = 0;
+ n++;
}
CUSE_UNLOCK();
return (NULL); /* failure */