diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -2347,6 +2347,7 @@ vhold.9 vholdl.9 MLINKS+=vmem.9 vmem_add.9 \ vmem.9 vmem_alloc.9 \ + vmem.9 vmem_alloc_aligned.9 \ vmem.9 vmem_create.9 \ vmem.9 vmem_destroy.9 \ vmem.9 vmem_free.9 \ diff --git a/share/man/man9/vmem.9 b/share/man/man9/vmem.9 --- a/share/man/man9/vmem.9 +++ b/share/man/man9/vmem.9 @@ -25,7 +25,7 @@ .\" SUCH DAMAGE. .\" .\" ------------------------------------------------------------ -.Dd May 17, 2019 +.Dd Nov 28, 2023 .Dt VMEM 9 .Os .\" ------------------------------------------------------------ @@ -58,6 +58,10 @@ .Ft int .Fn vmem_alloc "vmem_t *vm" "vmem_size_t size" "int flags" "vmem_addr_t *addrp" .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +.Ft int +.Fn vmem_alloc_aligned "vmem_t *vm" "vmem_size_t size" "vmem_size_t align" \ +"int flags" "vmem_addr_t *addrp" +.\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .Ft void .Fn vmem_free "vmem_t *vm" "vmem_addr_t addr" "vmem_size_t size" .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -190,7 +194,9 @@ It must be the one returned by .Fn vmem_xalloc . Notably, it must not be the one from -.Fn vmem_alloc . +.Fn vmem_alloc +or +.Fn vmem_alloc_aligned . Otherwise, the behaviour is undefined. .It Fa size The size of the resource being freed. @@ -224,9 +230,36 @@ .El .Pp .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +.Fn vmem_alloc_aligned +allocates a resource from the arena with a given alignment. +.Bl -tag -width flags +.It Fa vm +The arena which we allocate from. +.It Fa size +Specify the size of the allocation. +.It Fa align +Specify the alignment of the allocation. +.It Fa flags +A bitwise OR of an +.Nm +allocation strategy flag (see above) and a +.Xr malloc 9 +sleep flag. +.It Fa addrp +On success, if +.Fa addrp +is not +.Dv NULL , +.Fn vmem_alloc_aligned +overwrites it with the start address of the allocated span. +.El +.Pp +.\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .Fn vmem_free frees resource allocated by .Fn vmem_alloc +or +.Fn vmem_alloc_aligned to the arena. .Bl -tag -width addr .It Fa vm @@ -234,7 +267,9 @@ .It Fa addr The resource being freed. It must be the one returned by -.Fn vmem_alloc . +.Fn vmem_alloc +or +.Fn vmem_alloc_aligned . Notably, it must not be the one from .Fn vmem_xalloc . Otherwise, the behaviour is undefined. @@ -243,7 +278,9 @@ It must be the same as the .Fa size argument used for -.Fn vmem_alloc . +.Fn vmem_alloc +or +.Fn vmem_alloc_aligned . .El .Pp .\" ------------------------------------------------------------ @@ -262,9 +299,10 @@ .Dv NULL . .Pp On success, -.Fn vmem_xalloc -and +.Fn vmem_xalloc , .Fn vmem_alloc +and +.Fn vmem_alloc_aligned return 0. Otherwise, .Dv ENOMEM diff --git a/sys/kern/subr_vmem.c b/sys/kern/subr_vmem.c --- a/sys/kern/subr_vmem.c +++ b/sys/kern/subr_vmem.c @@ -1348,6 +1348,39 @@ return (vmem_xalloc(vm, size, 0, 0, 0, VMEM_ADDR_MIN, VMEM_ADDR_MAX, flags, addrp)); } +/* + * vmem_alloc: allocate resource from the arena. + */ + +int +vmem_alloc_aligned(vmem_t *vm, vmem_size_t size, vmem_size_t align, int flags, + vmem_addr_t *addrp) +{ + const int strat __unused = flags & VMEM_FITMASK; + qcache_t *qc; + + flags &= VMEM_FLAGS; + MPASS(size > 0); + MPASS(strat == M_BESTFIT || strat == M_FIRSTFIT || strat == M_NEXTFIT); + if ((flags & M_NOWAIT) == 0) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "vmem_alloc"); + + if (size <= vm->vm_qcache_max && align <= vm->vm_quantum_mask + 1) { + /* + * Resource 0 cannot be cached, so avoid a blocking allocation + * in qc_import() and give the vmem_xalloc() call below a chance + * to return 0. + */ + qc = &vm->vm_qcache[(size - 1) >> vm->vm_quantum_shift]; + *addrp = (vmem_addr_t)uma_zalloc(qc->qc_cache, + (flags & ~M_WAITOK) | M_NOWAIT); + if (__predict_true(*addrp != 0)) + return (0); + } + + return (vmem_xalloc(vm, size, align, 0, 0, VMEM_ADDR_MIN, + VMEM_ADDR_MAX, flags, addrp)); +} int vmem_xalloc(vmem_t *vm, const vmem_size_t size0, vmem_size_t align, diff --git a/sys/sys/vmem.h b/sys/sys/vmem.h --- a/sys/sys/vmem.h +++ b/sys/sys/vmem.h @@ -92,6 +92,8 @@ * respect the quantum caches. */ int vmem_alloc(vmem_t *vm, vmem_size_t size, int flags, vmem_addr_t *addrp); +int vmem_alloc_aligned(vmem_t *vm, vmem_size_t size, vmem_size_t align, + int flags, vmem_addr_t *addrp); void vmem_free(vmem_t *vm, vmem_addr_t addr, vmem_size_t size); /*