[v4l-utils] common: Use posix_memalign for allocating userptr buffers
Commit Message
When dealing with a userptr pointing to a buffer in userspace,
videobuf2 swaps the corresponding physical pages with other pages
so we have a contiguous area of memory for DMA. This only works if
the userptr is page aligned.
The current way of allocating user buffers using malloc only
guarantees alignment up to `alignof(max_align_t)`, which is usually
16. So replace malloc with posix_memalign to ensure the returned
pointer is on a page boundary.
Signed-off-by: Brandon Cheo Fusi <fusibrandon13@gmail.com>
---
utils/common/v4l-helpers.h | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
Comments
Hi Brandon,
Thanks for the patch.
On Thu, Jun 20, 2024 at 10:15:05AM +0100, Brandon Cheo Fusi wrote:
> When dealing with a userptr pointing to a buffer in userspace,
> videobuf2 swaps the corresponding physical pages with other pages
> so we have a contiguous area of memory for DMA. This only works if
> the userptr is page aligned.
>
> The current way of allocating user buffers using malloc only
> guarantees alignment up to `alignof(max_align_t)`, which is usually
> 16. So replace malloc with posix_memalign to ensure the returned
> pointer is on a page boundary.
>
> Signed-off-by: Brandon Cheo Fusi <fusibrandon13@gmail.com>
> ---
> utils/common/v4l-helpers.h | 15 ++++++++++++++-
> 1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/utils/common/v4l-helpers.h b/utils/common/v4l-helpers.h
> index cf0e92d..92a6fdc 100644
> --- a/utils/common/v4l-helpers.h
> +++ b/utils/common/v4l-helpers.h
> @@ -1652,6 +1652,19 @@ static inline int v4l_queue_munmap_bufs(struct v4l_fd *f, struct v4l_queue *q,
> return 0;
> }
>
> +static inline void *userptr_malloc(size_t size)
> +{
> + int v4l2_page_size = getpagesize();
> + void *ptr_addr = 0;
> +
> + int ret = posix_memalign(&ptr_addr, v4l2_page_size, size);
> + if (ret != 0) {
> + fprintf(stderr, "malloc via posix_memalign failed\n");
> + return 0;
> + }
> + return ptr_addr;
> +}
> +
> static inline int v4l_queue_alloc_bufs(struct v4l_fd *f,
> struct v4l_queue *q, unsigned from)
> {
> @@ -1661,7 +1674,7 @@ static inline int v4l_queue_alloc_bufs(struct v4l_fd *f,
> return 0;
> for (b = from; b < v4l_queue_g_buffers(q); b++) {
> for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
> - void *m = malloc(v4l_queue_g_length(q, p));
> + void *m = userptr_malloc(v4l_queue_g_length(q, p));
Could you call posix_memalign() here? I don't see a need to add a new
function for this. Also no temporary varible for the page size is needed.
>
> if (m == NULL)
> return errno;
@@ -1652,6 +1652,19 @@ static inline int v4l_queue_munmap_bufs(struct v4l_fd *f, struct v4l_queue *q,
return 0;
}
+static inline void *userptr_malloc(size_t size)
+{
+ int v4l2_page_size = getpagesize();
+ void *ptr_addr = 0;
+
+ int ret = posix_memalign(&ptr_addr, v4l2_page_size, size);
+ if (ret != 0) {
+ fprintf(stderr, "malloc via posix_memalign failed\n");
+ return 0;
+ }
+ return ptr_addr;
+}
+
static inline int v4l_queue_alloc_bufs(struct v4l_fd *f,
struct v4l_queue *q, unsigned from)
{
@@ -1661,7 +1674,7 @@ static inline int v4l_queue_alloc_bufs(struct v4l_fd *f,
return 0;
for (b = from; b < v4l_queue_g_buffers(q); b++) {
for (p = 0; p < v4l_queue_g_num_planes(q); p++) {
- void *m = malloc(v4l_queue_g_length(q, p));
+ void *m = userptr_malloc(v4l_queue_g_length(q, p));
if (m == NULL)
return errno;